Python中__set__和__setattr__之间的区别是什么?应该在何时使用?

eva*_*ing 13 python attributes getter-setter

正如标题所说.

来自Java我以前用过:

private int A;

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

public int getA() {
    return this.A
}
Run Code Online (Sandbox Code Playgroud)

我如何在Python中执行此操作(如果需要).如果其中之一__setattr____set__用于此目的,另一个用于什么?

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

让我们说我想做这样的事情:

public void setA(int A) {
    update_stuff(A);
    and_calculate_some_thing(A);
    this.A = A;
}
Run Code Online (Sandbox Code Playgroud)

什么是"pythonic"方式来实现这个?

mgi*_*son 15

在python中,这样的东西应该用a实现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
Run Code Online (Sandbox Code Playgroud)

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

class Foo(object):
     def __init__(self):
         self.x = None
Run Code Online (Sandbox Code Playgroud)

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

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

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)
Run Code Online (Sandbox Code Playgroud)

在什么__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')
Run Code Online (Sandbox Code Playgroud)

至于__get____set__: 以前的帖子已经很好地讨论了.

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

  • @Greg:我认为看看上面的代码,如果你有多个属性,很明显哪一个更容易维护 - 特别是如果你做的不仅仅是一个简单的`setattr` /`getattr`财产制定者/吸气者. (2认同)
  • 因此,如果我想在属性更改时计算某些内容,我应该使用属性,因为清晰.但__setattr__也可以(int theory)使用. (2认同)

Edw*_*per 8

如果getter/setter真的那么简单,那么你甚至不应该为它们烦恼:只需使用一个实例变量.如果你确实需要一个有趣的getter/setter,那么你应该切换到一个属性,就像mgilson所描述的那样.请注意,您可以从实例变量更改为属性,而无需使用代码注意差异的任何内容.即,开始于:

class Foo(object):
    def __init__(self):
        self.x = None
Run Code Online (Sandbox Code Playgroud)

并且只更改为基于属性的访问器mgilson描述是否/当它发现你需要在获得/设置属性时发生一些有趣的事情.

  • + 1用于推荐简单的实例变量.Python不是Java,并且getter/setter(Python中的属性)使用得更少,只有在实际需要时才使用它们. (2认同)

Ign*_*ams 7

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


geo*_*org 5

假设您有class Master一个属性x,并且您希望在向 中class Slave分配某些内容时执行一些代码。该代码将位于哪里?它可以在类中,在这种情况下您可以使用。它也可以在类中,以便它可以控制分配的内容。在这种情况下,您创建一个描述符并使用.xsome_master.x = fooMaster__setattr__SlaveSlave__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
Run Code Online (Sandbox Code Playgroud)

与此比较:

>>> 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
Run Code Online (Sandbox Code Playgroud)

要回答哪个更Pythonic的问题,我会说两者都不是。如果您需要实际做某事,请将其设为函数。显式 > 隐式。

 def update_param(a):
     update_stuff(a)
     and_calculate_some_thing(a)
     self.a = a
Run Code Online (Sandbox Code Playgroud)