【问题标题】:Attribute aliasing using __setattr__ in Python在 Python 中使用 __setattr__ 进行属性别名
【发布时间】:2014-02-11 10:35:33
【问题描述】:

我有一个 Python 类,它有各种内部变量,我想将它们公开为 x、y,一个简单的例子是:

class Vec2:
    def __init__(self):
        self.data = [0.0, 0.0]
        self.mapping = {'x':0, 'y':1}

    def __getitem__(self, index):
        return self.data[index]

    def __setitem__(self, index, value):
        self.data[index] = value

    def __getattr__(self, key):
        if key in self.mapping:
            return self.data[self.mapping[key]]
        else:
            raise AttributeError

    def _setattr__(self, key, value):
        # ?????
        pass

我原以为这行不通,因为__getattr__ 访问了self 的成员。但是,只要我不尝试定义__setattr__,一切都会正常工作——即使我只是让它等于pass,我也会得到递归。我应该如何实现__setattr__?特别是,如果他们的键不是 x 或 y,我应该调用什么?

另外,总的来说,我的问题是这是否是实现所需行为的正确方法,例如:

v = Vec2()
# this
v.x = 1.0
v.y = 0.0
# or this
v[0] = 1.0
v[1] = 0.0

或者是否有更好的选择。我正在使用 python 2.7.5。谢谢!

【问题讨论】:

    标签: python getattr setattr


    【解决方案1】:

    不要为此使用 __getattr____setattr__Properties 更适合您的任务:

    # Inherit from object. This is important.
    class Vec2(object):
        def __init__(self):
            self.data = [0.0, 0.0]
    
        def __getitem__(self, index):
            return self.data[index]
    
        def __setitem__(self, index, val):
            self.data[index] = val
    
        @property
        def x(self):
            return self.data[0]
        @x.setter
        def x(self, val):
            self.data[0] = val
    
        @property
        def y(self):
            return self.data[1]
        @y.setter
        def y(self, val):
            self.data[1] = val
    

    您的__setattr__ 尝试的问题在于,所有属性分配都调用了__setattr__,包括self.dataself.mapping,以及您在__setattr__ 本身中尝试的任何分配。您可以通过将xy 以外的属性委托给object.__setattr__ 来解决此问题,但属性更容易。属性还使您不必使用object.__getattribute__ 来访问__getattr__ 中的属性,这是导致无限递归问题的因素之一。

    __setattr__ 相比,属性仅在您尝试访问它们控制的属性时触发。 x 属性不必处理对x 以外的属性的访问,并且您在编写属性时不必使用其他属性访问机制。

    【讨论】:

    • 当我尝试添加这些时,它什么也没做。也就是说,如果我尝试使用v.x=1.0,它只会在类中添加一个名为x 的属性,而不会调用您的属性。如果我在这些方法中放置一个打印语句,它不会打印任何内容。我需要做点别的吗。根据您链接到的页面,它应该可以工作,但到目前为止我仍然遇到问题。
    • 好的,我发现了问题,我需要从对象派生类才能工作。
    • @Robotbugs:是的。大多数花哨的东西都不起作用,除非一个类在其祖先的某个地方有object
    【解决方案2】:

    您可以显式调用object.__setattr__ 以避免递归:

    def __setattr__(self, key, value):
        object.__setattr__(self, key, value)
    

    【讨论】:

      猜你喜欢
      • 2023-03-09
      • 2018-02-16
      • 2013-12-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-10-15
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多