Python类中方法包含共有、私有、保护方法,还包含魔术方法。
private (私有) 属性/方法名
- __xxx "双下划线"开头
- Python并没有真正的私有化支持,但可用双下划线得到伪私有。
- 只有类对象自己能访问,连子类对象也不能访问到这个数据。
方法或者变量是private类型时,其方法或者变量实际上是被转换了。在内部,python使用一种 name mangling 技术(名字重整:目的是防止子类意外重写基类的方法或者属性1),转换规则是在变量XXX的前插入类名,在类名前加一个下划线"_",形成"_ClassName__XXX"2
class ClassDef(object):
def __init__(self):
# public
self.name = "class_def"
# private
self.__age = 29
# protected
self._sex = "man"
def fun1(self):
print("call public function")
def __fun2(self):
print("call private function")
def _fun3(self):
print("call protected function")
def print_age(self):
print(self.__age)
if __name__ == "__main__":
# 实例化类对象
class_def = ClassDef()
# 调用public
>>> class_def.fun1()
"call public function"
>>> print(class_def.name)
"class_def"
# 调用protect
>>> class_def._fun3()
"call private function"
>>> print(class_def._sex)
"man"
# 调用private
>>> class_def._ClassDef__fun2()
"call private function"
>>> print(class_def._ClassDef__age)
29
# 以下调用private会报错
>>> class_def.__fun2()
"Traceback (most recent call last):
File "XXX.py", line 39, in <module>
class_def.__fun2()
AttributeError: 'ClassDef' object has no attribute '__fun2'"
>>> print(class_def.__age)
"Traceback (most recent call last):
File "XXX.py", line 39, in <module>
print(class_def.__age)
AttributeError: 'ClassDef' object has no attribute '__age'"
可见private是被转换了,不可直接调用。但可以通过赋值后使用。
# 以下调用private不会报错
>>> class_def.__age = 80
>>> print(class_def.__age)
80
>>> class_def.print_age()
29 # 可以看到类的私有属性并没有被真正修改
>>> class_def._ClassDef__age = 70
>>> class_def.print_age()
70
如果不给class_def.__age赋值,直接打印会触发AttributeError错误。**给class_def.__age赋值的操作,其实是在class_def中定义了一个名为__age的变量(因为Python中的都是动态变量)。**类中真正的属性class_def._ClassDef__age是没有被更改的。3
protect (保护) 属性/方法
- _xxx “单下划线”开头
- 只有类对象(即类实例)和子类对象自己能访问到这些变量
- 不能用
from module import *导入。需通过类提供的接口进行访问。
public (共有) 属性/方法
- xxx 不以下划线开头。
- Python中数据和方法默认都是pubic类型。
- public类型可以被子类、类内以及类外访问。
魔术方法
在Python中,所有以"__“双下划线包起来的方法,都统称为"Magic Method”,中文称『魔术方法』,例如类的初始化方法 __init__()。4
- __xxx__ 系统定义名字,前后均有一个"双下划线"
- 可以给类增加"magic"的特殊方法,如 __init__() 代表类的构造函数。
- 从使用范围来说,__init__()可以被继承,也可以直接调用。
| 魔术方法 | 含义 |
|---|---|
| __new__(cls, […]) | 在一个对象实例化的时候所调用的第一个方法。第一个参数是这个类,其他的参数是用来直接传递给 __init__ 方法。5 |
| __init__(self, […]) | 构造器。构造函数被调用的时候的任何参数都将会传给它。(比如如果我们调用 x = SomeClass(10, 'foo'),那么 __init__ 将会得到两个参数10和foo。) |
| __del__(self) | 析构器。它定义的是当一个对象进行垃圾回收时候的行为。它不实现语句 del x |
Python的垃圾回收机制——__del__()析构器
s = '123'
print('del...running')
del s
当用del删除一个对象时,其实并没有直接清除该对象的内存空间。Python 采用’引用计数’ 的算法方式来处理回收,即:当某个对象在其作用域内不再被其他对象引用的时候,Python 就自动清除对象。
而析构函数 __del__()在引用的时候就会自动清除被删除对象的内存空间。6
在对象的生命周期结束时,__del__会被调用,可以将__del__理解为"析构函数"。__del__定义的是当一个对象进行垃圾回收时候的行为。
有一点容易被人误解,实际上,x.__del__()并不是对于del x的实现,但是往往执行del x时会调用x.__del__()。7
class Foo(object):
def __init__(self):
print('foo __init__')
return None # 必须返回None,否则抛TypeError
def __del__(self):
print('foo __del__')
# 实例化类对象
>>> foo = Foo()
"foo __init__"
"foo __del__"
>>> foo.__del__()
"foo __del__"
>>> print(foo)
"<__main__.Foo object at 0x7fc3669b7250>"
>>> del foo
# 打印会报错
>>> print(foo)
"NameError: name 'foo' is not defined"

被折叠的 条评论
为什么被折叠?



