一、变量的定义 在Python中,有以下几种方式来定义变量:
- xx:公有变量
- _xx:前置单下划线,私有化属性或方法,一般来讲,变量名_xx被看作是“私有 的”,在模块或类外不可以使用。当变量是私有的时候,用_xx 来表示变量是很好的习惯。类对象和子类可以访问,这并不能完全做到真正的私有,只是约定俗成的而已,这样写表示不希望这个变量在外部被直接调用
- __xx:前置双下划线,私有化属性或方法,无法在外部直接访问(名字重整所以访问不到,只能是允许这个类本身进行访问了。连子类也不可以)
- __xx__:前后双下划线,系统定义名字(这就是在python中强大的魔法方法),因为变量名xxx对Python 来说有特殊含义,对于普通的变量应当避免这种命名风格。
- xx_:后置单下划线,用于避免与Python关键词的冲突
如以下例子所示,我在test类中定义了x,_x和 __x三个属性,并创建了test的类对象t,对这三个属性进行访问,__x不能被访问到
class test(object):
def __init__(self):
self.x = 10
self._x = 20
self.__x = 30
t = test()
print(t.x) # 10
print(t._x) # 20
# print(t.__x) # AttributeError: 'test' object has no attribute '__x'
可以使用命令dir查看t中的属性和方法,__x的名字已经被重整为_test__x了,如果你非要通过外部访问,也是可以的,可以使用t._test__x对__x进行访问。
python中没有真正的公有和私有变量,python只是对变量名称做了一个变化,还是可以在外部访问到的,是伪私有。
注:虽然私有变量可以通过_类名__变量名来访问,但强烈建议不要这样做!
二、使用不同方法导入模块,模块中私有变量的使用区别
在使用不同方法导入模块后,是否能使用模块中的私有属性和方法,有以下两种情况
- 使用
from somemodule import *进行导入,不能导入私有变量,结果如下: - 在使用
import somemodule导入模块的情况下,能导入并使用私有属性和方法
在下面的两种情况下,我们将使用一个示例模块 somemodule 来说明:
# somemodule.py
public_variable = "I'm a public variable"
_private_variable = "I'm a private variable"
def public_function():
return "I'm a public function"
def _private_function():
return "I'm a private function"
情况1:使用 from somemodule import * 进行导入,不能导入私有变量:
from somemodule import *
print(public_variable) # 可以访问,输出 "I'm a public variable"
# print(_private_variable) # 不能访问,会引发 NameError
print(public_function()) # 可以访问,输出 "I'm a public function"
# print(_private_function()) # 不能访问,会引发 NameError
在这种情况下,由于使用了 from somemodule import *,只有公共变量和函数会被导入到当前命名空间,而私有变量和函数不会被导入。尝试访问私有变量和函数会导致 NameError。
情况2:在使用 import somemodule 导入模块的情况下,能导入并使用私有属性和方法:
import somemodule
print(somemodule.public_variable) # 可以访问,输出 "I'm a public variable"
print(somemodule._private_variable) # 可以访问,输出 "I'm a private variable"
print(somemodule.public_function()) # 可以访问,输出 "I'm a public function"
print(somemodule._private_function()) # 可以访问,输出 "I'm a private function"
在这种情况下,虽然 from somemodule import * 不会导入私有变量和函数,但是使用 import somemodule 后,您仍然可以通过模块名来访问和使用私有属性和方法。请注意,尽管可以访问私有属性和方法,但最好遵循模块的私有约定,避免直接访问模块的内部实现。
三、对类中的私有属性进行操作的方法
如果你想对类中的私有属性进行操作时,有以下两种方法种方法:
方法一:自定义一个方法
class test(object):
def __init__(self):
self._x = 10
def get_x(self):
return self._x
def set_x(self, value):
self._x = value
x = property(get_x, set_x)
"""
这部分使用property装饰器将get_x和set_x方法定义的属性绑定到名称为x的公共属性。
这意味着可以通过t.x来访问属性,实际上是在调用get_x方法,而通过t.x = value来赋值属性,实际上是在调用set_x方法。
"""
t = test()
print(t.x) # 10
t.x=30
print(t.x) # 30
"""
这部分创建了一个test类的实例t,并通过t.x来访问属性。
在第一个打印语句中,t.x会调用get_x方法返回_x的值,即10。然后,通过t.x = 30赋值属性,这会调用set_x方法将_x的值设置为30。
在第二个打印语句中,t.x再次调用get_x方法返回更新后的值,即30。
"""
方法二:使用property或装饰器
class Test(object):
def __init__(self):
self._x = 10
@property
def x(self):
return self._x
@x.setter
def x(self, value):
self._x = value
t = Test()
print(t.x) # 输出 10
t.x = 30
print(t.x) # 输出 30
"""
在这个版本的代码中,我们使用了@property装饰器来定义getter方法,以及使用@x.setter装饰器来定义setter方法。
具体来说,@x.setter 装饰器是用于将一个方法标记为属性 x 的 setter 方法,这样在给属性 x 赋值时,Python 会自动调用这个装饰的方法。这使得您可以在赋值时执行一些额外的操作,例如数据验证、记录变化等。
装饰器使得这些方法看起来就像是实例属性一样,但在背后实际上是调用了对应的方法。
这种方式更加紧凑,使得代码更易于阅读和维护,同时也使得我们遵循了Python中的惯例。
"""
# 关于x.setter:
class Test:
def __init__(self):
self._x = 10
@property
def x(self):
return self._x
@x.setter
def x(self, value):
if value > 0:
self._x = value
else:
print("Value must be greater than 0")
t = Test()
print(t.x) # 输出 10
t.x = 30
print(t.x) # 输出 30
t.x = -5 # 输出 "Value must be greater than 0"
print(t.x) # 输出 30,因为赋值失败未改变属性值
注:
1,在构造函数__init__中是_x,不是x,你直接x是访问不到的;
2,为什么是_x 而不是x,这是python中的私有变量(虽然python中没有公有变量和私有变量,也就是说这是伪私有),在python中,如果一个变量不想被外部直接访问,一般是在变量前加一个下划线,提醒不要直接访问(其实是可以通过self._x访问到的,如果不想被访问还可以使用双下划线__x,也是不能直接访问。所以提供get_x这样的函数供使用者访问;
3,为什么要使用_x这样的伪私有变量,因为我们使用property时,让方法变成属性的方式来调用,一般是这样写x=property(...),这样调用更加清晰明了;但是如果构造函数中的变量也用x,就会和property中的变量有冲突,所有一般我们写_x