【问题标题】:python add custom __setattr__ and __getattribute__ [duplicate]python 添加自定义 __setattr__ 和 __getattribute__ [重复]
【发布时间】:2023-01-23 05:51:25
【问题描述】:

我正在尝试在 python 中构建一个类,其中变量赋值和检索需要通过另一个类及其 set_value 和 get_value 的逻辑来完成。

我的对象类给出了 set_value 和 get_value 的逻辑

Class MyObj:
    def __init__(self):
        self.value = 0

    def set_value(self, value):
        self.value = value

    def get_value(self):
        return self.value

用户创建一个我的课对象并设置/获取这些变量的值,但是我的对象类将从用户那里 100% 抽象出来。

class MyClass:
    item1 = MyObj()
    item2 = MyObj()
    item3 = MyObj()

    def __setattr__(self, key, value):
        print(f"set logic :: {key}, {value}")
        # key.set_value(value)

    def __getattribute__(self, item):
        print(f"get logic :: {item}")
        # return item.get_value()

我的课将表现得像任何其他 python 类,但 setter 和 getter 逻辑来自我的对象.

cls = MyClass()
cls.item1 = 10 # Issue: this should not replace variable value from class object.
print(cls.item1) # Issue: this should not return class object

问题:

  1. 目前,这将通过__setattr____getattribute__ 方法完成,但我无法使代码正常工作,因为参数在字符串中。
  2. 我不想为中的每个变量手动键入 getter 和 setter我的课.
  3. 用户应该能够读取和写入变量我的课像标准的 python 类变量。
  4. https://github.com/ramazanpolat/prodict 这个库做了类似的事情,但不是我要找的。

【问题讨论】:

  • 看起来你在描述Descriptors,但你使用的是不同的方法。不清楚(对我而言)您是否需要描述符所做的其他事情。

标签: python python-3.x


【解决方案1】:

虽然这能够巧妙地使用__getattribute____setattr__来完成,那样会更麻烦。你想要的听起来像是descriptors

class MyObj:
    def __init__(self):
        self._name = ''

    def __set_name__(self, owner, name):
        self._name = '__MyObj_' + name

    def __set__(self, instance, value):
        setattr(instance, self._name, value)

    def __get__(self, instance, owner):
        return getattr(instance, self._name, 0)

class MyClass:
    item1 = MyObj()
    item2 = MyObj()
    item3 = MyObj()

假设我们有一个名为 xMyClass 实例。当我们尝试访问 x.item1 时,Python 注意到 x.__dict__x 的实例变量字典)不包含 item1。所以它会查看 x 的类,即 MyClassMyClass.item1已定义,因此 Python 将返回它。但是,我们将它作为实例变量访问,所以实际上 Python 将要给我们的是 MyClass.item1.__get__(x, MyClass)。所以无论何时我们写x.item1,Python 都会在MyObj 上调用__get__。对于item2item3 也是如此。请注意,这与 Python 用于在类内的函数对象上绑定 self 的技术相同。函数类型本身有一个__get__,它返回一个绑定方法对象,而不是原始函数。这就是为什么 x.some_method(1) 等同于 MyClass.some_method(x, 1)。这是因为它是实际上相当于 MyClass.some_method.__get__(x, MyClass)(1) 翻译成前者。

同样,当我们尝试将 x.item1 分配给 x.item1 = new_value 时,Python 将调用 MyClass.item1.__set__(x, new_value),所以这就是你的设置器。我们还可以写一个 __del__ 如果我们尝试将 del 语法与 x.item1 一起使用,它会起作用,尽管你没有提到删除器,所以我在这里省略它。

唯一需要注意的是,使用这种技术,类中的每个字段只有一个 MyObj不是每个实例一个。因此,在我上面发布的示例中,我使用 __set_name__ 和一个巧妙的命名约定将支持字段放在 MyClass 实例的 __dict__ 中。如果您只想返回一个合成值而实际上没有支持字段,则您不需要它。根据您的用例,property 可能适合您并节省您的输入时间。

【讨论】:

  • 我在这个解决方案中看到的一个问题:假设我在MyObj中添加了一个方法def ok(self): print("ok"),然后尝试从MyClass访问它:if __name__ == '__main__': cls = MyClass() cls.item1 = 10 print(cls.item1) 现在尝试从MyClass访问ok方法__init__::@987654362 @打印行将给出错误,因为 item1 是 int
  • 基本上,我希望用户只获得 int,但是从 MyClass 内部,我想完全控制 MyObj 类。
  • 我上面的 cmets 要求可以通过为类的每个变量编写 getter 和 setter 来实现,但是有很多变量我不想为所有变量编写 getter 和 setter。
  • Python 中没有“类内部”。类内部定义的方法并不特殊。他们有第一个参数,通常称为 self,但这不是关键字。就函数内部而言,self 是一个普通变量的名称,恰好指向特定类的实例。
猜你喜欢
  • 1970-01-01
  • 2021-05-08
  • 2018-02-16
  • 2011-10-25
  • 1970-01-01
  • 2015-01-02
  • 1970-01-01
  • 1970-01-01
  • 2010-12-11
相关资源
最近更新 更多