在python中使用访问器的正确方法?

Correct way to use accessors in Python?

本问题已经有最佳答案,请猛点这里访问。

这就是在python中定义具有属性"speed"的类"car"的方法吗?我的背景是在Java中,好像在Python中不使用GET/SET方法。

1
2
3
4
5
6
7
8
9
10
11
class Car(object):
    def __init__(self):
        self._speed = 100

    @property
    def speed(self):
        return self._speed

    @speed.setter
    def speed(self, value):
        self._speed = value


在Python中,我们通常避免使用getter和setter。只有一个.speed属性:

1
2
3
4
5
class Car(object):
    speed = 0

    def __init__(self):
        self.speed = 100

看到Python不是Java的动机和更多的陷阱,以避免:

In Java, you have to use getters and setters because using public fields gives you no opportunity to go back and change your mind later to using getters and setters. So in Java, you might as well get the chore out of the way up front. In Python, this is silly, because you can start with a normal attribute and change your mind at any time, without affecting any clients of the class. So, don't write getters and setters.

当您真正需要在获取、设置或删除属性时执行代码时,请使用property。验证、缓存、副作用等都是属性的合理用例。必要时才使用。


由于技术上的属性在python中从来都不是私有的,所以get/set方法不被视为"pythonic"。这是访问对象属性的标准方法:

1
2
3
4
5
6
7
8
class MyClass():
    def __init__(self):
        self.my_attr = 3

obj1 = MyClass()
print obj1.my_attr #will print 3
obj1.my_attr = 7
print obj1.my_attr #will print 7

当然,您仍然可以使用getter和setter,并且您可以通过在您的属性前面添加__来模仿私有成员:

1
2
3
4
5
6
7
8
9
10
11
12
class MyClass():
    def __init__(self):
        self.__my_attr = 3
    def set_my_attr(self,val):
        self.__my_attr = val
    def get_my_attr(self):
        return self.__my_attr

obj1 = MyClass()
print obj1.get_my_attr() #will print 3
obj1.set_my_attr(7)
print obj1.get_my_attr() #will print 7

__的"mangles"变量名:从定义__attr的某个类classname外,将__attr重命名为_classname__attr;在上面的例子中,我们可以简单地使用obj1._MyClass__my_attr而不使用getter和setter。因此EDOCX1 3阻止了属性的外部使用,但是它并没有像Java EDCOX1×11修改器那样禁止它。

正如您在问题中提到的,python中也有可用的属性。属性的优点在于,您可以使用它们来实现返回或设置值的函数,这些值从类外部看起来只是作为普通成员属性访问的。


我会选择属性,比如:

1
2
3
class Car(object):
    def __init__(self):
        self.speed = 100

你可以用同样的方式改变和得到它。EDCOX1的2进制标记可能更适用于包装使用Java/C GET/SET方法、虚拟属性或如果需要操作输入的值的类。

我经常在GUI类中使用这种方法,在这些类中,我可以根据小部件(类似于自定义事件系统)的属性的变化轻松地强制重新绘制屏幕。