getattr() 如何尊重 python 类属性?

问题描述 投票:0回答:1

我有一个类在我的项目中执行一些有用的工作

class Test:
    def __init__(self):
        self.__value = None

    def set_value(self, value):
        print(f"set_value(): value={value}")
        self.__value = value

    def get_value(self):
        print(f"get_value()")
        return self.__value

    value = property(get_value, set_value)

在常规函数中,它有一些 getters/setters,可以方便地分组为更简单的客户端代码的属性。例如

t.value = 123

现在,在应用程序的某些部分,我需要在每次访问 Test 对象、每次方法调用时执行一些额外的操作(在我的例子中是 print() 调用)。所以我这样做了:

class Wrapper:
    def __init__(self, wrapped):
        self.wrapped = wrapped

    def __getattr__(self, attr):
        print(f"Wrapper::__getattr__(): {attr}")
        return getattr(self.wrapped, attr)

这与装饰器的做法非常相似,但这种方法有两个好处:

  • 原始类未受影响,我可以与 Wrapper 分开使用它
  • 我可以向 Test 类添加尽可能多的新方法,而无需在 Wrapper 中添加新的装饰器

现在使用代码:

t = Test()
w = Wrapper(t)

w.set_value(123)
print(f"Value: {w.get_value()}")

w.value = 234
print(f"Value: {w.value}")

直接设置/获取呼叫按预期工作。不幸的是 w.value 语法不再起作用,并且默默地将值 234 分配给

value
名称,而不是调用 getter 和 setter。

如何解决此问题,以便 Wrapper 尊重 Test 类属性?

python decorator python-decorators
1个回答
0
投票

您可以定义一个

__setattr__
方法来管理分配。请注意,它必须单独处理
wrapped
属性,以避免
__init__
中的无限递归。

class Test:
    def __init__(self):
        self.__value = None

    def set_value(self, value):
        print(f"set_value(): value={value}")
        self.__value = value

    def get_value(self):
        print(f"get_value()")
        return self.__value

value = property(get_value, set_value)


class Wrapper:
    def __init__(self, wrapped):
        self.wrapped = wrapped

    def __getattr__(self, attr):
        print(f"Wrapper::__getattr__(): {attr}")
        return getattr(self.wrapped, attr)
    
    def __setattr__(self, attr, value):
        if attr == 'wrapped':
            super().__setattr__('wrapped', value)
        else:
            print(f"Wrapper::__setattr__(): {attr}")
            setattr(self.wrapped, attr, value)
    

    
    
    t = Test()
    w = Wrapper(t)
    
    w.set_value(123)
    print(f"Value: {w.get_value()}")
    print()
    w.value = 234
    print(f"Value: {w.value}")

输出:

Wrapper::__getattr__(): set_value
set_value(): value=123
Wrapper::__getattr__(): get_value
get_value()
Value: 123

Wrapper::__setattr__(): value
set_value(): value=234
Wrapper::__getattr__(): value
get_value()
Value: 234
© www.soinside.com 2019 - 2024. All rights reserved.