【问题标题】:What is the difference between __set__ and __setattr__ in Python and when should which be used?Python 中的 __set__ 和 __setattr__ 有什么区别,什么时候应该使用?
【发布时间】:2012-05-22 17:44:19
【问题描述】:

正如标题所说。

来自 Java 我曾经:

private int A;

public void setA(int A) {
    this.A = A;
}

public int getA() {
    return this.A
}

如何在 Python 中做到这一点(如果需要)。 如果__setattr____set__ 之一用于此,另一个用于什么?

编辑: 我觉得我需要澄清一下。我知道在 Python 中不会在需要之前创建 setter 和 getter。

假设我想做这样的事情:

public void setA(int A) {
    update_stuff(A);
    and_calculate_some_thing(A);
    this.A = A;
}

实现这个的“pythonic”方式是什么?

【问题讨论】:

    标签: python attributes getter-setter


    【解决方案1】:

    在 python 中,应该使用property 来实现这样的事情(然后只有当他们做一些有用的事情时)。

    class Foo(object):
        def __init__(self):
            self._x = None
    
        @property
        def x(self):
            return self._x
    
        @x.setter
        def x(self,y):
            self._x = y
    

    在这个例子中,最好这样做(正如 Edward 所指出的):

    class Foo(object):
         def __init__(self):
             self.x = None
    

    因为我们的 getter/setter 方法实际上并没有做任何事情......但是,当 setter/getter 实际上做的不仅仅是分配/返回属性的值时,属性会变得非常有用。

    它也可以使用__setattr__/__getattr__ 来实现(但不应该以这种方式实现,因为如果你的类有多个属性,它很快就会变得很麻烦。我也猜想这样做会比使用属性慢):

    class Foo(object):
        def __init__(self):
            self._x = None
        def __setattr__(self,attr,obj):
            if(attr == 'x'):
                object.__setattr__(self,'_x',obj)
            else:
                object.__setattr__(self,attr,obj)
    
        def __getattr__(self,attr):
            if(attr == 'x'):
                return object.__getattr__(self,'_x')
            else:
                return object.__getattr__(self,attr)
    

    __setattr____getattr__ 的实际作用而言... __setattr__/__getattr__ 是当您执行以下操作时所调用的:

    myclassinstance = MyClass()
    myclassinstance.x = 'foo'  #translates to MyClass.__setattr__(myclassinstance,'x','foo')
    bar = myclassinstance.x    #translates to bar=MyClass.__getattr__(myclassinstance,'x')
    

    至于__get____set__previous posts 讨论得很好。

    请注意,在 python 中没有私有变量之类的东西。一般来说,在一个类成员的前缀下划线,你不应该弄乱它(除非你当然知道你在做什么)。如果它带有 2 个下划线前缀,它将调用名称修改,这使得在类外部访问变得更加困难。这用于防止继承中的命名空间冲突(并且这些变量通常也不会被弄乱)。

    【讨论】:

    • 很好的属性说明,但最好解释一下为什么应该使用属性而不是 setattr/getattr
    • @Greg :我认为看看上面的代码,如果你有多个属性,那么很明显哪个更容易维护——特别是如果你做的不仅仅是一个简单的@ 987654335@/getattr 在您的属性设置器/获取器中。
    • 我一点也不反对,但清晰很少是坏事。 +1
    • 因此,如果我想在属性更改时计算一些东西,我应该使用属性,因为它很清楚。但是 setattr 也可以(int理论)使用。
    【解决方案2】:

    __set__() 在分配描述符时用于描述符。 __setattr__() 在绑定到对象的属性时使用。除非您正在创建描述符,否则您不会使用 __set__()

    【讨论】:

    • 感谢您的回答!这很简单,但回答了拒绝者关于__set____setattr_ 的问题。我猜__get____set__ 可能会以有趣的方式被用来滥用语言。
    【解决方案3】:

    如果 getter/setter 真的像那样微不足道,那么您甚至不应该为它们烦恼:只需使用实例变量即可。如果您确实需要做一些有趣的事情的 getter/setter,那么您应该切换到一个属性,如 mgilson 所述。请注意,您可以从实例变量更改为属性,而不会使用您的代码注意到差异。即,以:

    开头
    class Foo(object):
        def __init__(self):
            self.x = None
    

    并且只有当你在获取/设置属性时需要一些有趣的事情发生时,才会更改 mgilson 描述的基于属性的访问器。

    【讨论】:

    • + 1 用于推荐一个简单的实例变量。 Python 不是 Java,getter/setter(Python 中的属性)的使用要少得多,只有在实际需要时才使用。
    • @rubik "../仅在实际需要时。"这可能就是我写“(如果我需要的话)”的原因。
    【解决方案4】:

    假设你有一个class Master 和一个属性x,它是class Slave,并且你希望在你给x 赋值时执行一些代码,就像some_master.x = foo 一样。此代码将位于何处?它可以在Master 类中,在这种情况下,您使用__setattr__。它也可以在Slave 类中,这样它就可以控制分配的内容。在这种情况下,您将Slave 设为descriptor 并使用__set__

    例子:

    >>> class Master(object):
    ...     def __setattr__(self, name, val):
    ...         print "run code in Master: %s" % val
    ... 
    >>> a = Master()
    >>> a.x = 123
    run code in Master: 123
    

    比较一下:

    >>> class Slave(object):
    ...     def __set__(self, obj, val):
    ...         print "run code in Slave: %s" % val
    ... 
    >>> class Master2(object):
    ...     x = Slave()
    ... 
    >>> b = Master2()
    >>> b.x = 345
    run code in Slave: 345
    

    要回答哪个更pythonic的问题,我不会说。如果您需要真正某事,请将其设为函数。显式 > 隐式。

     def update_param(a):
         update_stuff(a)
         and_calculate_some_thing(a)
         self.a = a
    

    【讨论】:

    • 所以我应该通过函数更新 x 而不是 @x.setter\n def x(self, val):\n self.x=y?如果我只想在设置 x 时更新一些相关值,这似乎很麻烦?
    • @refuser:与设计问题一样,这取决于具体的用例。一般来说,暴露对象的状态很少是一个好主意。
    猜你喜欢
    • 2010-09-05
    • 1970-01-01
    • 2010-10-28
    • 1970-01-01
    • 2016-11-21
    • 2011-11-25
    • 2013-04-17
    • 2011-09-19
    • 1970-01-01
    相关资源
    最近更新 更多