我来自Java世界,正在阅读Bruce Eckels的《Python 3 Patterns, Recipes and idiom》。
在阅读有关类的内容时,会继续说在Python中不需要声明实例变量。你只需要在构造函数中使用它们,它们就在那里了。
例如:
class Simple:
def __init__(self, s):
print("inside the simple constructor")
self.s = s
def show(self):
print(self.s)
def showMsg(self, msg):
print(msg + ':', self.show())
如果这是真的,那么任何Simple类的对象都可以改变类外变量s的值。
例如:
if __name__ == "__main__":
x = Simple("constructor argument")
x.s = "test15" # this changes the value
x.show()
x.showMsg("A message")
在Java中,我们已经学习了公共/私有/受保护变量。这些关键字是有意义的,因为有时您希望类中的变量在类之外没有人可以访问。
为什么Python中不需要这个?
私有变量在Python中或多或少是一种hack:解释器会故意重命名变量。
class A:
def __init__(self):
self.__var = 123
def printVar(self):
print self.__var
现在,如果你试图在类定义之外访问__var,它会失败:
>>> x = A()
>>> x.__var # this will return error: "A has no attribute __var"
>>> x.printVar() # this gives back 123
但你可以很容易地摆脱这种情况:
>>> x.__dict__ # this will show everything that is contained in object x
# which in this case is something like {'_A__var' : 123}
>>> x._A__var = 456 # you now know the masked name of private variables
>>> x.printVar() # this gives back 456
你可能知道OOP中的方法是这样调用的:x. printvar () => A.printVar(x)。如果A.printVar()可以访问x中的某个字段,那么这个字段也可以在A.printVar()之外访问…毕竟,函数是为可重用性而创建的,其中的语句并没有任何特殊的功能。
如前所述,可以通过在变量或方法前面加上下划线来表示它是私有的。如果您觉得这还不够,还可以使用属性装饰器。这里有一个例子:
class Foo:
def __init__(self, bar):
self._bar = bar
@property
def bar(self):
"""Getter for '_bar'."""
return self._bar
This way, someone or something that references bar is actually referencing the return value of the bar function rather than the variable itself, and therefore it can be accessed but not changed. However, if someone really wanted to, they could simply use _bar and assign a new value to it. There is no surefire way to prevent someone from accessing variables and methods that you wish to hide, as has been said repeatedly. However, using property is the clearest message you can send that a variable is not to be edited. property can also be used for more complex getter/setter/deleter access paths, as explained here: https://docs.python.org/3/library/functions.html#property
下面是我处理Python 3类字段的方法:
class MyClass:
def __init__(self, public_read_variable, private_variable):
self.public_read_variable_ = public_read_variable
self.__private_variable = private_variable
我只在MyClass方法中使用两个下划线访问__private_variable。
我用一个下划线对public_read_variable_进行读访问
在类之外,但从不修改变量:
my_class = MyClass("public", "private")
print(my_class.public_read_variable_) # OK
my_class.public_read_variable_ = 'another value' # NOT OK, don't do that.
Python不像c++或Java那样有任何私有变量。如果需要,还可以在任何时候访问任何成员变量。然而,在Python中不需要私有变量,因为在Python中公开类的成员变量并不坏。如果需要封装成员变量,可以稍后使用“@property”来实现,而不会破坏现有的客户端代码。
在Python中,单个下划线“_”用于表示方法或变量不被视为类的公共API的一部分,并且API的这一部分可以在不同版本之间更改。您可以使用这些方法和变量,但是如果您使用这个类的新版本,您的代码可能会中断。
双下划线“__”并不意味着“私有变量”。你可以使用它来定义“类本地”变量,这些变量不容易被子类覆盖。它破坏了变量名。
例如:
class A(object):
def __init__(self):
self.__foobar = None # Will be automatically mangled to self._A__foobar
class B(A):
def __init__(self):
self.__foobar = 1 # Will be automatically mangled to self._B__foobar
自我。__foobar的名称自动被破坏为self。在类B中,它被破坏为self._B__foobar。因此,每个子类都可以定义自己的变量__foobar,而不重写其父变量。但是没有什么可以阻止您访问以双下划线开头的变量。但是,name mangling阻止你偶然调用这些变量/方法。
我强烈建议你观看Raymond Hettinger的Python类开发工具包,它提供了一个很好的例子,为什么以及如何使用@property和“__”-实例变量。
如果您已经公开了公共变量,并且需要封装它们,那么可以使用@property。因此,您可以从最简单的解决方案开始。你可以让成员变量为public,除非你有具体的理由不这样做。这里有一个例子:
class Distance:
def __init__(self, meter):
self.meter = meter
d = Distance(1.0)
print(d.meter)
# prints 1.0
class Distance:
def __init__(self, meter):
# Customer request: Distances must be stored in millimeters.
# Public available internals must be changed.
# This would break client code in C++.
# This is why you never expose public variables in C++ or Java.
# However, this is Python.
self.millimeter = meter * 1000
# In Python we have @property to the rescue.
@property
def meter(self):
return self.millimeter *0.001
@meter.setter
def meter(self, value):
self.millimeter = value * 1000
d = Distance(1.0)
print(d.meter)
# prints 1.0