[TOC]
面向对象
1
2
3
4
5
6
|
class Apple:
price = 100 # 可以直接定义类变量
print(Apple.price) # 使用类名进行调用
Apple.quality = 'good' # # 可以直接定义类变量
print(Apple.quality)
|
所有实例对象公用一个类变量:
1
2
3
4
5
6
7
|
class Apple:
price = 100
apple = Apple()
print(apple.price) # 100
Apple.price = 200
print(apple.price) # 200
|
若定义类的方法,则必须要有一个必要参数:self
,表示对象本身
1
2
3
4
5
6
7
|
class Apple:
def eat(self):
print('I am eating an apple')
apple = Apple()
apple.eat() # 'I am eating an apple'
Apple.eat(apple) # 'I am eating an apple'
|
其中实例可以有自己的属性(变量):
1
2
3
4
5
6
7
8
|
class Apple:
def eat(self):
print('I am eating an apple')
apple = Apple()
apple.size = 16 # 与类变量一致 可以在外部进行定义
print(apple.size)
print(Apple.size) # 报错
|
但是这样的方法显然会让不同实例的属性不统一,需要进行自动化定义:
构造函数__init__()
1
2
3
4
5
6
|
class Apple:
def __init__(self):
self.eat = 'I am an apple!'
apple = Apple()
print(apple.eat)
|
同样可以带上参数:
1
2
3
4
5
6
7
8
9
10
|
class Apple:
def __init__(self,size=12):
self.eat = 'I am an apple!'
self.size = size
apple = Apple()
print(apple.size)
apple2 = Apple(20)
print(apple2.size)
|
析构函数__del__()
1
2
3
4
5
6
7
8
9
|
class Apple:
def __init__(self,size=12):
self.eat = 'I am an apple!'
self.size = size
def __del__(self):
print('Apple is being deleted!')
apple = Apple()
del apple
|
垃圾回收机制:
- Python通过统计对象被引用次数(引用计数器),从而判断是否回收垃圾
- 但是回收不是"立即"的, 由解释器在适当的时机,将垃圾对象占用的内存空间回收
- 但是针对循环引用,会有额外的循环垃圾收集器
封装
隐藏属性也称:魔术方法、特殊方法,通过开头结尾加上两个下划线:__
构造和析构都是一种隐藏属性
对于变量,可以在开头加个__
,实现私有效果
1
2
3
4
5
6
|
class Apple:
public_age = 10
__private_age = 20
print(Apple.public_age)
print(Apple.__private_age) # 报错
|
但是似乎留了一个后门:_类名__隐藏属性
1
2
3
4
5
6
|
class Apple:
public_age = 10
__private_age = 20
print(Apple.public_age)
print(Apple._Apple__private_age)
|
标准的方式还是需要通过类的内部进行访问
1
2
3
4
5
6
7
8
9
10
11
12
13
|
class Apple:
public_age = 10
__private_age = 20
def grow(self):
self.__private_age += 1
def print(self):
print(self.__private_age)
apple = Apple()
apple.print()
apple.grow()
apple.print()
|
有了私有,当然还有保护变量:单个下划线
1
2
3
4
5
6
7
8
9
|
class Fruit:
apple = True
_banana = True
__cherry = True
fruit = Fruit()
print(fruit.apple) # True
print(fruit._banana) # True
print(fruit.__cherry) # AttributeError: 'Fruit' object has no attribute '__cherry'
|
- 私有变量只能被类内部的方法进行使用
- 建议别用,容易和python自带的属性冲突
- 主要用于防止子类意外覆盖父类属性。
- 保护变量可以被外部使用
- 公开变量无限制
类型 |
示例 |
特点 |
公开变量 |
var |
可以直接访问,无任何限制 |
保护变量 |
_var |
本身与子类可以访问,不能被其他文件from import |
私有变量 |
__var |
只允许本身访问 |
魔术方法 |
__var__ |
双下划线开头和结尾,Python的特殊方法 |
方法
1
2
3
4
5
6
7
8
9
|
class Animal:
def speak(self, times):
print("Animal speaks" * times)
@staticmethod
def eat(times):
print("Animal eats" * times)
Animal.eat(3)
|
这样可以不创建实例直接用,同时不传self,减少内存
1
2
3
4
5
6
7
|
class Animal:
name = 'Animal'
@classmethod
def eat(cls):
print(cls.name)
Animal.eat()
|
两种方法都可以用于规避实例的创建,静态方法不能访问类和实例,类方法可以访问类本身
方法 |
参数 |
自动传参 |
访问 |
被调用 |
用途 |
实例方法 |
self |
是 |
✅ 类属性 / ✅ 实例属性 |
✅ 实例 |
操作对象自身的状态 |
类方法 |
cls |
是 |
✅ 类属性 / ❌ 实例属性 |
✅ 类 / ✅ 实例 |
工厂方法、操作类级别的数据 |
静态方法 |
无 |
否 |
❌ 类属性 / ❌ 实例属性 |
✅ 类 / ✅ 实例 |
与类相关的工具函数,不依赖类或实例 |
这里的访问其实不是说无法访问,事实上类名.属性
都可以访问
所以其实都是约定俗成
继承
1
2
3
4
5
6
7
8
|
class Fruit: # 其实默认继承object类(不然你以为默认自带的方法属性都是哪来的)
size = 10
class Apple(Fruit):
color = 'red' # 子类如果拓展了新的属性 ——> 派生类
apple = Apple()
print(apple.size)
|
重写
1
2
3
4
5
6
7
8
9
10
|
class Fruit:
def print(self):
print('I am a fruit')
class Apple(Fruit):
def print(self):
print('I am a apple')
apple = Apple()
apple.print()
|
重写可以用于拓展父类方法的功能:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
class Fruit:
def print(self):
print('I am a fruit')
class Apple(Fruit):
def print(self):
# Fruit.print(self) # 调用父类方法(需要传入self)
super().print() # 更推荐这种方法
# super(Apple, self).print() 等价
print('I am a apple')
apple = Apple()
apple.print()
|
理解上把super()
当成一个函数,返回的是父类,这样没什么问题
实际上是创建了一个super类的实例,动态查找MRO链,返回一个代理对象
MRO = MRO(Method Resolution Order,方法解析顺序)是Python中决定类继承关系中方法调用顺序的规则。它是Python多继承机制的核心组成部分。
方式 |
示例 |
区别 |
super() |
super().method() |
动态查找 MRO 链,适用于多重继承 |
直接调用父类 |
Parent.method(self) |
硬编码父类名,不适用于复杂继承 |
多继承
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
|
class Father(object):
def __init__(self):
print("Father's __init__")
def __del__(self):
print("Father's __del__")
def print(self):
print("Father's print")
class Mother(object):
def __init__(self):
print("Mother's __init__")
def __del__(self):
print("Mother's __del__")
def print(self):
print("Mother's print")
class Child(Mother, Father):
def __init__(self):
super().__init__()
print("Child's __init__")
def __del__(self):
super().__del__()
print("Child's __del__")
child = Child()
child.print()
'''
Mother's __init__
Child's __init__
Mother's print
Mother's __del__
Child's __del__
'''
|
构造与析构的顺序其实可以根据super()
去控制
这里print()
和super()
默认都是就近的Mother
(写在第一个)
调用其他父类需要显式的写出来
1
2
3
4
|
def __init__(self):
Mother.__init__(self)
Father.__init__(self)
print("Child's __init__")
|
目测不实现构造函数应该也会自动实现:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
class Father(object):
def __init__(self):
print("Father's __init__")
def __del__(self):
print("Father's __del__")
def print(self):
print("Father's print")
class Mother(object):
def __init__(self):
print("Mother's __init__")
def __del__(self):
print("Mother's __del__")
def print(self):
print("Mother's print")
class Child(Mother, Father):
pass
child = Child()
print(Child.__mro__)
'''
Mother's __init__
(<class '__main__.Child'>, <class '__main__.Mother'>, <class '__main__.Father'>, <class 'object'>)
Mother's __del__
'''
|
多态
同一种行为多个表现形式
需要基于:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
class Animal:
def speak(self):
print("Animal speaks")
class Dog(Animal):
def speak(self):
print("Dog barks")
class Cat(Animal):
def speak(self):
print("Cat meows")
dog = Dog()
dog.speak() # 重写
cat = Cat()
cat.speak() # 重写
|
这里其实就只是重写
1
2
3
4
5
|
def speak_loudly(animal: Animal):
animal.speak() # 多态
speak_loudly(Dog()) # 调用 Dog 的 speak 方法
speak_loudly(Cat()) # 调用 Cat 的 speak 方法
|
这样就可以体现多态