Python 面向对象
注意
Python中有大量语法糖,特性和C++、Java也不同,个人感觉不需要全都了解,用到什么学什么就好了。
# 数据模型
参考Python官方文档:数据模型 (opens new window)
对象 是 Python 中对数据的抽象。 Python 程序中的所有数据都是由对象或对象间关系来表示的。 (从某种意义上说,按照冯·诺依曼的“存储程序计算机”模型,代码本身也是由对象来表示的。)
每个对象都有各自的编号、类型和值。一个对象被创建后,它的 编号 就绝不会改变;你可以将其理解为该对象在内存中的地址。 'is
(opens new window)' 运算符可以比较两个对象的编号是否相同;id()
(opens new window) 函数能返回一个代表其编号的整型数。
# 特殊方法名称
下面简单介绍三个方法。
# object.__init__(self[, ...])
通常把__init__()
理解为类的构造函数,但其实对象是由 __new__()
和 __init__()
协作构造完成的 (由 __new__()
创建,并由 __init__()
定制)。把__init__()
理解为初始化更好,类实例已经由__new__
创建出来了,然后经过初始化设置属性等,构造出一个对象。所以__init__()
并没有返回值,也不能有返回值,它只是给已经创建的对象进行初始化操作。
# object.__new__(cls[, ...])
__new__()
是一个静态方法,创建并返回一个当前类的实例。注意它的第一个参数是cls而不是self。cls代表当前类,self代表当前类的对象。
# object.__del__(self)
在实例将被销毁时调用。注意把它理解为析构函数是不恰当的,官方描述为"由于调用 __del__()
方法时周边状况已不确定,在其执行期间发生的异常将被忽略,改为打印一个警告到 sys.stderr
。当解释器退出时不会确保为仍然存在的对象调用 __del__()
方法。"
# 私有变量
经常听说在 Python 类中以一个下划线开头的变量是保护类型(protected )的变量,以双下划线开头的变量是私有类型(private)的变量。
但其实这种写法只是Python的一个约定,无论怎么写,最终都不能实现真正意义的私有变量,也就是实际上还是可以被直接访问。
Python只是会把例如 __spam
这种标识符替换为 _classname__spam
,所以只要使用 objecname._classname__spam
还是可以直接访问私有变量的。
demo:
class Person:
def __init__(self, name, age):
self.__name = name
self._age = age
if __name__ == '__main__':
peter = Person("Peter", 18)
# print(peter.__name), 直接访问__name会报错:AttributeError: 'Person' object has no attribute '__name'
print(peter._Person__name)
print(peter._age)
2
3
4
5
6
7
8
9
10
11
12
用PyCharm调试也能看到,实际上只是双下划线开头的变量名被替换成了 _classname__spam
这种格式:
参考:Python官方文档 (opens new window)
# 元类和抽象方法
关于Python抽象基类请查看文档:abc --- 抽象基类 (opens new window)
因为Python没有接口的概念,如果想写一个抽象类,需要用到元类ABCMeta
和装饰器abstractmethod
。
特别注意:
- 有
abstractmethod
的抽象类不能直接实例化(报错),必须子类实现了抽象方法后才能实例化。 - 装饰器
abstractmethod
所在的类的元类必须是ABCMeta
或其子类,否则定义的抽象方法没有实际效果,就是这个类即使有抽象方法也能直接实例化,没有报错。
from abc import ABCMeta, abstractmethod
class AbstractService(metaclass=ABCMeta):
"""定义抽象类"""
@abstractmethod
def run(self):
pass
class ServiceImplement(AbstractService):
"""抽象类具体实现"""
def run(self):
print("do something")
if __name__ == '__main__':
# 抽象类(有抽象方法)不能直接实例化,会报错:TypeError: Can't instantiate abstract class AbstractService with abstract methods run
# service = AbstractService()
service = ServiceImplement()
service.run()
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22