如何在函数中的class里的装饰器中调用外层class中的变量


class libAddress(tfLibClass):
    """
    @class libAddress
    @brief Pack some common APIs for Pba/Lba 
    """
    def __init__(self, testcase):
        """
        @fn __init__
        @brief Initialization of the commands class.  Sets class instance variables.
        @retval This method returns no values.
        @exception This method raises no exceptions.
        """
        super(libAddress, self).__init__(testcase)
        self.storPhyInfo               = self.testcase.vs.getStoragePhyInfo()
        self.rgPageCntPerRgBlk         = self.storPhyInfo.numPagesInBlock
        
    def _getPbaStr(self):
        class pbaStr(ctypes.LittleEndianStructure):
             _fields_ = [
                                ("unit",    ctypes.c_uint32, self.cfgAddr.pbaBitsCountOfUnit), 
                                ("die",     ctypes.c_uint32, self.cfgAddr.pbaBitsCountOfDie),
                                ("rgRow",   ctypes.c_uint32, self.cfgAddr.pbaBitsCountOfRgRow),
                                ("rg",      ctypes.c_uint32, self.cfgAddr.pbaBitsCountOfRg),
                                #no revd bit("rsvd",   ctypes.c_uint32, self.cfgAddr.pbaBitsCountOfRsvd),
                                #RgBlk & RgPage add here only for parsing RgRow,not normal Pba struct
                                # ("rgPage",  ctypes.c_uint32, self.cfgAddr.pbaBitsCountOfRgPage),
                                # ("rgBlk",   ctypes.c_uint32, self.cfgAddr.pbaBitsCountOfRgBlk),
                                ]
            @property
            def rgPage(self):
                return self.rgPage
            @rgPage.setter
            def rgPage(self, rgPageVal):
                rgBlkOldVal = self.rgRow // self.rgPageCntPerRgBlk         
                rgRawVal = rgBlkOldVal * self.rgPageCntPerRgBlk + rgPageVal
                self.rgRow = rgRawVal
    return type('PBAStrCls', (pbaStr,), {})

直接调用self.rgPageCntPerRgBlk 会报AttributeError: 'PBAStrCls' object has no attribute 'rgPageCntPerRgBlk',如何在以上rgPage的函数中调用self.rgPageCntPerRgBlk

基于new Bing的编写:
在您提供的代码中,rgPage属性的setter方法试图访问self.rgPageCntPerRgBlk,但是这个属性是定义在libAddress类中的,而不是在内部类pbaStr中。由于pbaStr类没有定义rgPageCntPerRgBlk属性,所以会报错。

您可以通过将libAddress类的实例作为参数传递给pbaStr类来解决此问题。例如,在_getPbaStr方法中,您可以将当前实例(即self)作为参数传递给pbaStr类:


def _getPbaStr(self):
    class pbaStr(ctypes.LittleEndianStructure):
        def __init__(self, lib_address):
            self.lib_address = lib_address
            ...
        ...
        @rgPage.setter
        def rgPage(self, rgPageVal):
            rgBlkOldVal = self.rgRow // self.lib_address.rgPageCntPerRgBlk
            ...


然后,在创建pbaStr类的实例时,您可以将当前实例(即self)作为参数传递:

pba_str = pbaStr(self)

这样,在pbaStr类中,您就可以通过访问self.lib_address.rgPageCntPerRgBlk来访问外层类中的变量了。
修改过后:

class libAddress(tfLibClass):
    """
    @class libAddress
    @brief Pack some common APIs for Pba/Lba 
    """
    def __init__(self, testcase):
        """
        @fn __init__
        @brief Initialization of the commands class.  Sets class instance variables.
        @retval This method returns no values.
        @exception This method raises no exceptions.
        """
        super(libAddress, self).__init__(testcase)
        self.storPhyInfo               = self.testcase.vs.getStoragePhyInfo()
        self.rgPageCntPerRgBlk         = self.storPhyInfo.numPagesInBlock
        
    def _getPbaStr(self):
        class pbaStr(ctypes.LittleEndianStructure):
            # 添加一个初始化方法,接收外层类的实例作为参数
            def __init__(self, lib_address):
                self.lib_address = lib_address
            _fields_ = [
                            ("unit",    ctypes.c_uint32, self.cfgAddr.pbaBitsCountOfUnit), 
                            ("die",     ctypes.c_uint32, self.cfgAddr.pbaBitsCountOfDie),
                            ("rgRow",   ctypes.c_uint32, self.cfgAddr.pbaBitsCountOfRgRow),
                            ("rg",      ctypes.c_uint32, self.cfgAddr.pbaBitsCountOfRg),
                            #no revd bit("rsvd",   ctypes.c_uint32, self.cfgAddr.pbaBitsCountOfRsvd),
                            #RgBlk & RgPage add here only for parsing RgRow,not normal Pba struct
                            # ("rgPage",  ctypes.c_uint32, self.cfgAddr.pbaBitsCountOfRgPage),
                            # ("rgBlk",   ctypes.c_uint32, self.cfgAddr.pbaBitsCountOfRgBlk),
                            ]
            @property
            def rgPage(self):
                return self.rgPage
            @rgPage.setter
            def rgPage(self, rgPageVal):
                # 通过访问self.lib_address.rgPageCntPerRgBlk来访问外层类中的变量
                rgBlkOldVal = self.rgRow // self.lib_address.rgPageCntPerRgBlk         
                rgRawVal = rgBlkOldVal * self.lib_address.rgPageCntPerRgBlk + rgPageVal
                self.rgRow = rgRawVal

        # 在创建pbaStr类的实例时,将当前实例(即self)作为参数传递
        pba_str = pbaStr(self)

不知道你这个问题是否已经解决, 如果还没有解决的话:
  • 以下回答来自chatgpt:

    解决方案: 在装饰器内调用外层class中的变量需要使用外层class的实例化对象来访问变量。

    具体步骤如下:

    1. 定义外层class PBAStrCls,并在其中定义变量rgPageCntPerRgBlk:
    class PBAStrCls:
    
        def __init__(self):
            self.rgPageCntPerRgBlk = 10
    
    1. 定义内层class InnerClass,并在其中使用装饰器来装饰函数:
    class PBAStrCls:
    
        def __init__(self):
            self.rgPageCntPerRgBlk = 10
    
        class InnerClass:
            def __init__(self, func):
                self.func = func
    
            def __call__(self, *args, **kwargs):
                # 通过self.func.__name__可以获取到被装饰函数的名字
                print(f"调用函数:{self.func.__name__}之前,self.rgPageCntPerRgBlk:{args[0].rgPageCntPerRgBlk}")
                result = self.func(*args, **kwargs)
                print(f"调用函数:{self.func.__name__}之后")
                return result
    
    1. 在外层class PBAStrCls中定义被装饰的函数test,并将InnerClass的实例化对象作为装饰器使用即可:
    class PBAStrCls:
    
        def __init__(self):
            self.rgPageCntPerRgBlk = 10
    
        class InnerClass:
            def __init__(self, func):
                self.func = func
    
            def __call__(self, *args, **kwargs):
                print(f"调用函数:{self.func.__name__}之前,self.rgPageCntPerRgBlk:{args[0].rgPageCntPerRgBlk}")
                result = self.func(*args, **kwargs)
                print(f"调用函数:{self.func.__name__}之后")
                return result
    
        @InnerClass
        def test(self):
            print("装饰的函数test被调用了")
    
    1. 最后,实例化PBAStrCls对象,调用被装饰的函数test:
    pba = PBAStrCls()
    pba.test()
    

    输出结果将会是:

    调用函数:test之前self.rgPageCntPerRgBlk:10
    装饰的函数test被调用了
    调用函数:test之后
    

如果你已经解决了该问题, 非常希望你能够分享一下解决方案, 写成博客, 将相关链接放在评论区, 以帮助更多的人 ^-^