简体   繁体   English

Python中的__set__和__setattr__有什么区别?何时使用?

[英]What is the difference between __set__ and __setattr__ in Python and when should which be used?

As the title says. 如标题所示。

Coming from Java im used to: 来自Java,即时通讯用于:

private int A;

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

public int getA() {
    return this.A
}

How do I do that (if I need to) in Python. 如何在Python中执行此操作(如果需要)。 And if one of __setattr__ or __set__ is used for this, what is the other one used for? 如果__set__使用__setattr____set__一个,则另一个用于什么呢?

Edit: I feel I need to clarify. 编辑:我觉得我需要澄清。 I know that in Python one doe's not create setters and getters before they are needed. 我知道在Python中,doe不需要先创建setter和getter。

Lets say I want to do something like this: 可以说我想做这样的事情:

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

What is the "pythonic" way to implement this? 实现此目的的“ pythonic”方法是什么?

In python, something like this should be implemented using a property (and then only when they do something useful). 在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

In this example, it would be better to just do (as pointed out by Edward): 在此示例中,最好做一下(如爱德华指出的那样):

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

since our getter/setter methods don't actually do anything ... However, properties become very useful when the setter/getter actually does something more than just assign/return an attribute's value. 因为我们的getter / setter方法实际上不做任何事情...但是,当setter / getter实际上要做的不仅仅是分配/返回属性值时,属性变得非常有用。

It could also be implemented using __setattr__ / __getattr__ (but it shouldn't be implemented this way as it quickly becomes cumbersome if your class has more than 1 property. I would also guess that doing it this way would be slower than using properties): 也可以使用__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)

In terms of what __setattr__ and __getattr__ actually do... __setattr__ / __getattr__ are what are called when you do something like: __setattr____getattr__实际作用__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')

As for __get__ and __set__ : previous posts have discussed that quite nicely. 至于__get____set__以前的帖子 __set__进行了很好的讨论。

Note that in python there is no such thing as private variables . 请注意,在python 中没有私有变量之类的东西 In general, in a class member is prefixed with an underscore, you shouldn't mess with it (unless you know what you're doing of course). 通常,在类成员中以下划线作为前缀,您不应该将其弄乱(除非您当然知道自己在做什么)。 If it's prefixed with 2 underscores, it will invoke name-mangling which makes it harder to access outside the class. 如果以2个下划线作为前缀,它将调用名称修改,这使得在类外部进行访问变得更加困难。 This is used to prevent namespace clashes in inheritance (and those variables are generally also not to be messed with). 这用于防止继承中的名称空间冲突(通常也不要弄混那些变量)。

If the getter/setter are really as trivial as that, then you shouldn't even bother with them: just use an instance variable. 如果getter / setter确实如此琐碎,那么您甚至不必理会它们:只需使用实例变量即可。 If you do need a getter/setter that does something interesting, then you should switch to a property, as mgilson described. 如果您确实需要做一些有趣的getter / setter,那么您应该切换到属性,如mgilson所述。 Note that you can change from an instance variable to a property without anything that uses your code noticing the difference. 请注意,您可以从实例变量更改为属性,而无需任何使用您的代码的方法来注意差异。 Ie, start with: 即,开始于:

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

And only change to the property-based accessors mgilson described if/when it turns out you need something interesting to happen when you get/set the attribute. 并且仅更改为基于属性的访问器,如果/当事实证明您需要获取/设置属性时需要发生一些有趣的事情,mgilson会对此进行描述。

__set__() is used in descriptors when the descriptor is assigned to. 分配描述符时,在描述符中使用__set__() __setattr__() is used when binding to an attribute of an object. 绑定到对象的属性时使用__setattr__() Unless you're creating a descriptor, you won't use __set__() . 除非创建描述符,否则将不会使用__set__()

Assume you've got class Master with an attribute x which is of class Slave and you want some code to be executed when you assign something to x as in some_master.x = foo . 假设您拥有一个具有属性x class Master ,该属性属于class Slave并且您希望在将某物分配给x时执行某些代码,例如some_master.x = foo Where will this code be located? 该代码位于何处? It can be in the class Master , in which case you use __setattr__ . 它可以在Master类中,在这种情况下,您可以使用__setattr__ It can be also in the class Slave , so that it has a control on what is being assigned. 它也可以在Slave类中,以便可以控制要分配的内容。 In this case, you make Slave a descriptor and use __set__ . 在这种情况下,您可以使Slave成为描述符,并使用__set__

Examples: 例子:

>>> 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

compare to this: 与此相比:

>>> 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

To answer the question which one is more pythonic, I'd say neither. 要回答哪个是更pythonic的问题,我都不会说。 If you need to actually do something, make it a function. 如果您需要实际执行某项操作,请将其设为功能。 Explicit > implicit. 显式>隐式。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM