5.1 访问级别
你可能注意到构造函数的名字有点奇怪,像__init__
? 将来你会经常看到这样的东西。
在Python中,有不同的访问级别来控制类的属性和方法的可见性和数据保护。主要的访问控制机制包括在属性或方法名前使用一个或两个下划线(_
和__
)。
使用约定
单个下划线 _
用于类或模块内部使用的属性和方法。这并不是禁止使用,但这是一个需要遵循的约定,以提高代码的可读性和维护性。
双下划线 __
用于那些真正需要私有和保护的属性和方法,不想被无意或故意地从外部访问。name mangling
机制使它们不那么容易访问,但仍然可通过特殊名称访问。
公共(public)
字段和方法
公共属性和方法
可以从代码的任何地方访问
。在
Python中,默认情况下所有属性和方法都是公共的,除非它们的名字以下划线开始。
class MyClass:
def __init__(self):
self.public_attribute = "I am public"
def public_method(self):
return "This is a public method"
obj = MyClass()
print(obj.public_attribute) # 可访问
print(obj.public_method()) # 可访问
通过Python中的访问级别实现 封装,主要通过不公开的字段和方法。
5.2 非公开字段和方法
保护(protected)
字段和方法
受到保护的属性和方法之前用一个下划线_
来表明,主要用于类和其子类的内部使用。这是一个告诉程序员这些数据不应该在类外部使用的约定。
class MyClass:
def __init__(self):
self._protected_attribute = "I am protected"
def _protected_method(self):
return "This is a protected method"
obj = MyClass()
print(obj._protected_attribute) # 可访问,但不推荐
print(obj._protected_method()) # 可访问,但不推荐
私有(private)
字段和方法
在Python中,私有属性和方法在名字前用两个下划线__
表示。它们专用于类内部使用,主要目的是隐藏内部实现和保护数据免受外部的无意修改或使用。
为了防止从外部代码直接访问这些属性和方法,Python采用了一种称为name mangling
(名字混淆)的特殊机制。这个机制会自动改变私有属性的名字,在它们前加上一个类名前缀。因此,类MyClass
中的私有属性__private_attribute
会被转换为内部名字_MyClass__private_attribute
。
这为保护数据免受不小心的访问提供了保障,同时仍然允许在类内部使用这些数据。然而,要记住,"name mangling"
机制不是绝对的保护措施——有经验的程序员可以通过改变的名字来访问这些数据。
让我们看看这个在实践中是如何工作的:
class MyClass:
def __init__(self):
self.__private_attribute = "I am private"
def __private_method(self):
return "This is a private method"
def access_private_method(self):
return self.__private_method()
obj = MyClass()
# print(obj.__private_attribute) # 错误,不可直接访问
# print(obj.__private_method()) # 错误,不可直接访问
print(obj.access_private_method()) # 通过类的公共方法访问
正如例子中所见,直接访问私有属性或方法会产生错误。但Python允许通过改变的名字访问它们。例如,你可以使用“改变”的名字访问私有属性,如下所示:
class MyClass:
def __init__(self):
self.__private_attribute = "I am private"
obj = MyClass()
print(obj._MyClass__private_attribute) # 输出: I am private
虽然通过“改变”的名字访问是可能的,但应该避免这样做,因为它违反了封装原则,可能导致代码不稳定。
为了查看Python如何改变属性名字,你可以使用内置函数dir()
,它显示对象的所有可访问属性和方法:
class MyClass:
def __init__(self):
self.__private_attribute = "I am private"
obj = MyClass()
print(dir(obj)) # 显示对象的所有属性和方法,包括“改变”的名字
dir()
函数运行的结果中,你会看到对象的所有属性和方法列表,包括_MyClass__private_attribute
,这证实了"name mangling"
机制的存在。
5.3 自动调用方法
在使用构造函数时,有一个有趣的方面,你可能注意到了。__init__
方法会自动调用。
其实这样的情况有很多,同样有很多方法在这些情况下会被调用。比如:
方法__str__
如果你的对象有__str__
方法,那么在试图将对象转换为字符串时,它会自动被调用,例如使用print()
和str()
函数时。
class Cat:
def __init__(self, name, age):
self.name = name
self.age = age
def __str__(self):
return f"{self.name} is {self.age} years old"
cat = Cat("Barsik", 5)
print(cat) # 输出: Barsik is 5 years old
方法__len__
如果你的对象有__len__
方法,当试图获取你的对象的“长度”时,它会自动被调用——这是通过len()
函数实现的。例如:
class MyList:
def __init__(self, items):
self.items = items
def __len__(self):
return len(self.items)
my_list = MyList([1, 2, 3])
print(len(my_list)) # 输出: 3
此类“特殊方法”在你的人生中会有很多,但使用它们是一种乐趣。所以准备好:)
GO TO FULL VERSION