first commit
This commit is contained in:
310
02.面向对象/01.初识面向对象.md
Normal file
310
02.面向对象/01.初识面向对象.md
Normal file
@@ -0,0 +1,310 @@
|
||||
# 初识面向对象
|
||||
|
||||
## 面向对象
|
||||
|
||||
### 面向过程编程vs函数式编程
|
||||
|
||||
```python
|
||||
# 面向过程编程
|
||||
s1 = 'fjdsklafsjda'
|
||||
count = 0
|
||||
for i in s1:
|
||||
count += 1
|
||||
|
||||
|
||||
l1 = [1,2,3,4]
|
||||
count = 0
|
||||
for i in l1:
|
||||
count += 1
|
||||
```
|
||||
|
||||
```python
|
||||
# 函数式编程
|
||||
def func(s):
|
||||
count = 0
|
||||
for i in s:
|
||||
count += 1
|
||||
return count
|
||||
func('fdsafdsa')
|
||||
func([1,2,3,4])
|
||||
```
|
||||
|
||||
通过对比可知:函数编程较之面向过程编程最明显的两个特点:
|
||||
|
||||
1. 减少代码的重用性。
|
||||
|
||||
2. 增强代码的可读性。
|
||||
|
||||
### 函数式编程vs面向对象编程
|
||||
|
||||
```python
|
||||
# 函数式编程
|
||||
|
||||
# auth 认证相关
|
||||
def login():
|
||||
pass
|
||||
|
||||
def regisgter():
|
||||
pass
|
||||
|
||||
# account 账户相关
|
||||
def func1():
|
||||
pass
|
||||
|
||||
def func2():
|
||||
pass
|
||||
|
||||
|
||||
# 购物车相关
|
||||
def shopping(username,money):
|
||||
pass
|
||||
def check_paidgoods(username,money):
|
||||
pass
|
||||
def check_unpaidgoods(username,money):
|
||||
pass
|
||||
def save(username,money):
|
||||
pass
|
||||
```
|
||||
|
||||
```python
|
||||
class LoginHandler:
|
||||
def login(self):
|
||||
pass
|
||||
|
||||
def regisgter(self):
|
||||
pass
|
||||
|
||||
class Account:
|
||||
def func1(self):
|
||||
pass
|
||||
|
||||
def func2(self):
|
||||
pass
|
||||
|
||||
class ShoppingCar:
|
||||
def shopping(username,money):
|
||||
pass
|
||||
def check_paidgoods(username,money):
|
||||
pass
|
||||
def check_unpaidgoods(username,money):
|
||||
pass
|
||||
def save(username,money):
|
||||
pass
|
||||
```
|
||||
|
||||
1. 面向对象编程:是一类相似功能函数的集合,使你的代码更清晰化,更合理化。
|
||||
2. 面向对象,要拥有上帝的视角看问题,类其实就是一个公共模板(厂房),对象就从具体的模板实例化出来。
|
||||
|
||||
### 类的结构
|
||||
|
||||
```python
|
||||
class Human:
|
||||
"""
|
||||
此类主要是构建人类
|
||||
"""
|
||||
mind = '有思想' # 第一部分:静态属性 属性 静态变量 静态字段
|
||||
dic = {}
|
||||
l1 = []
|
||||
def work(self): # 第二部分:方法 函数 动态属性
|
||||
print('人类会工作')
|
||||
```
|
||||
|
||||
class 是关键字与def用法相同,定义一个类。
|
||||
Human是此类的类名,类名使用驼峰(CamelCase)命名风格,首字母大写,私有类可用一个下划线开头。
|
||||
类的结构从大方向来说就分为两部分:
|
||||
|
||||
- 静态变量
|
||||
- 动态方法
|
||||
|
||||
## 从类名的角度研究类
|
||||
|
||||
### 类名操作静态属性
|
||||
|
||||
**查看类中的所有内容:类名.__dict__方式。**
|
||||
|
||||
```python
|
||||
class Human:
|
||||
mind = '有思想'
|
||||
dic = {}
|
||||
l1 = []
|
||||
def work(self):
|
||||
print('会工作')
|
||||
|
||||
print(Human.__dict__)
|
||||
print(Human.__dict__['mind'])
|
||||
Human.__dict__['mind'] = '高智慧'
|
||||
print(Human.__dict__)
|
||||
# 通过这种方式只能查询,不能增删改
|
||||
```
|
||||
|
||||
**万能的点.**
|
||||
|
||||
```python
|
||||
class Human:
|
||||
mind = '有思想'
|
||||
dic = {}
|
||||
l1 = []
|
||||
def work(self):
|
||||
print('会工作')
|
||||
|
||||
print(Human.mind)
|
||||
Human.mind = '高智慧'
|
||||
print(Human.mind)
|
||||
|
||||
del Human.mind
|
||||
Human.walk = '用脚走'
|
||||
print(Human.walk)
|
||||
# 通过万能的点 可以增删改查类中的单个属性
|
||||
```
|
||||
|
||||
**对以上两种做一个总结:如果想查询类中的所有内容,通过 第一种__dict__方法,如果只是操作单个属性则用万能的点的方式。**
|
||||
|
||||
### 类名操作动态方法
|
||||
|
||||
```python
|
||||
class Human:
|
||||
mind = '有思想'
|
||||
dic = {}
|
||||
l1 = []
|
||||
def work(self):
|
||||
print(self,'会工作')
|
||||
|
||||
Human.work('chensong')
|
||||
Human.__dict__['work']('chensong')
|
||||
```
|
||||
|
||||
## 从对象的角度研究类
|
||||
|
||||
### 对象
|
||||
|
||||
对象是从类中出来的,只要是**类名加上()**,这就是一个实例化过程,这个就会实例化一个对象。
|
||||
|
||||
```python
|
||||
class Human:
|
||||
mind = '有思想'
|
||||
dic = {}
|
||||
l1 = []
|
||||
def work(self):
|
||||
print(self,'会工作')
|
||||
|
||||
obj = Human()
|
||||
# 只要实例化对象,它会自动执行__init__方法
|
||||
print(obj)
|
||||
```
|
||||
|
||||
其实实例化一个对象总共发生了三件事:
|
||||
|
||||
1. 在内存中开辟了一个对象空间。
|
||||
|
||||
2. 自动执行类中的__init__方法,并将这个对象空间(内存地址)传给了__init__方法的第一个位置参数self。
|
||||
|
||||
3. 在__init__ 方法中通过self给对象空间添加属性。
|
||||
|
||||
```python
|
||||
class Human:
|
||||
mind = '有思想'
|
||||
work = '用两只腿走'
|
||||
def __init__(self,name,sex,age,hobby):
|
||||
self.n = name
|
||||
self.s = sex
|
||||
self.a = age
|
||||
self.h = hobby
|
||||
|
||||
obj = Human('chensong','男','18','男')
|
||||
```
|
||||
|
||||
### 对象操作对象空间属性
|
||||
|
||||
**对象查询对象中所有属性。 `对象.__dict__`**
|
||||
|
||||
```python
|
||||
class Human:
|
||||
|
||||
mind = '有思想'
|
||||
language = '实用语言'
|
||||
def __init__(self,name,sex,age,hobby):
|
||||
# self 和 obj 指向的是同一个内存地址同一个空间,下面就是通过self给这个对象空间封装四个属性。
|
||||
self.n = name
|
||||
self.s = sex
|
||||
self.a = age
|
||||
self.h = hobby
|
||||
|
||||
obj = Human('chensong','男',18,'男')
|
||||
print(obj.__dict__)
|
||||
```
|
||||
|
||||
**对象操作对象中的单个属性。 万能的点.**
|
||||
|
||||
```python
|
||||
class Human:
|
||||
|
||||
mind = '有思想'
|
||||
language = '实用语言'
|
||||
def __init__(self,name,sex,age,hobby):
|
||||
# self 和 obj 指向的是同一个内存地址同一个空间,下面就是通过self给这个对象空间封装四个属性。
|
||||
self.n = name
|
||||
self.s = sex
|
||||
self.a = age
|
||||
self.h = hobby
|
||||
|
||||
obj = Human('chensong','男',18,'男')
|
||||
obj.job = 'IT'
|
||||
del obj.n
|
||||
obj.s = '女'
|
||||
print(obj.s)
|
||||
print(obj.__dict__)
|
||||
```
|
||||
|
||||
### 对象查看类中的属性
|
||||
|
||||
```python
|
||||
class Human:
|
||||
|
||||
mind = '有思想'
|
||||
language = '实用语言'
|
||||
def __init__(self,name,sex,age,hobby):
|
||||
# self 和 obj 指向的是同一个内存地址同一个空间,下面就是通过self给这个对象空间封装四个属性。
|
||||
self.n = name
|
||||
self.s = sex
|
||||
self.a = age
|
||||
self.h = hobby
|
||||
|
||||
obj = Human('chensong','男',18,'男')
|
||||
print(obj.mind)
|
||||
print(obj.language)
|
||||
obj.a = 666
|
||||
print(obj.a)
|
||||
```
|
||||
|
||||
### 对象操作类中的方法
|
||||
|
||||
```python
|
||||
class Human:
|
||||
|
||||
mind = '有思想'
|
||||
language = '实用语言'
|
||||
def __init__(self,name,sex,age,hobby):
|
||||
# self 和 obj 指向的是同一个内存地址同一个空间,下面就是通过self给这个对象空间封装四个属性。
|
||||
self.n = name
|
||||
self.s = sex
|
||||
self.a = age
|
||||
self.h = hobby
|
||||
|
||||
def work(self):
|
||||
print(self)
|
||||
print(self.n,'会工作')
|
||||
|
||||
def tools(self):
|
||||
print(self.n,'会使用工具')
|
||||
|
||||
obj = Human('chensong','男',18,'男')
|
||||
obj.work()
|
||||
obj.tools()
|
||||
```
|
||||
|
||||
**类中的方法一般都是通过对象执行的(出去类方法,静态方法外),并且对象执行这些方法都会自动将对象空间传给方法中的第一个参数self.**
|
||||
|
||||
*self其实就是类中方法(函数)的第一个位置参数,只不过解释器会自动将调用这个函数的对象传给self。所以咱们把类中的方法的第一个参数约定俗成设置成self, 代表这个就是对象。*
|
||||
|
||||
**一个类可以实例化多个对象**
|
||||
|
314
02.面向对象/02.类空间与类之间的关系.md
Normal file
314
02.面向对象/02.类空间与类之间的关系.md
Normal file
@@ -0,0 +1,314 @@
|
||||
# 类空间与类之间的关系
|
||||
|
||||
## 类的空间问题
|
||||
|
||||
### 添加对象属性
|
||||
|
||||
```python
|
||||
class A:
|
||||
def __init__(self,name):
|
||||
self.name = name
|
||||
|
||||
def func(self,sex):
|
||||
self.sex = sex
|
||||
```
|
||||
|
||||
在类外部添加
|
||||
|
||||
```python
|
||||
class A:
|
||||
def __init__(self,name):
|
||||
self.name = name
|
||||
|
||||
def func(self,sex):
|
||||
self.sex = sexa
|
||||
|
||||
obj = A('chensong')
|
||||
obj.age = 18
|
||||
print(obj.__dict__)
|
||||
```
|
||||
|
||||
类的内部添加
|
||||
|
||||
```python
|
||||
class A:
|
||||
def __init__(self,name):
|
||||
self.name = name
|
||||
|
||||
def func(self,sex):
|
||||
self.sex = sex
|
||||
|
||||
obj = A('chensong')
|
||||
obj.func('男')
|
||||
print(obj.__dict__)
|
||||
```
|
||||
|
||||
**总结:对象的属性不仅可以在__init__里面添加,还可以在类的其他方法或者类的外面添加。**
|
||||
|
||||
### 添加类的静态属性
|
||||
|
||||
```python
|
||||
class A:
|
||||
def __init__(self,name):
|
||||
self.name = name
|
||||
|
||||
def func(self,sex):
|
||||
self.sex = sex
|
||||
|
||||
def func1(self):
|
||||
A.bbb = self
|
||||
|
||||
A.aaa = 'test' # 类的外部添加
|
||||
print(A.__dict__)
|
||||
|
||||
A.func1('123') # 类的内部添加
|
||||
print(A.__dict__)
|
||||
```
|
||||
|
||||
**总结:类的属性不仅可以在类内部添加,还可以在类的外部添加**
|
||||
|
||||
## 对象如何找到类的属性
|
||||
|
||||
对象空间
|
||||
|
||||
1. 产生这个对象空间,并有一个类对象指针
|
||||
2. 执行`__init__`方法,给对象封装属性
|
||||
|
||||
对象查找属性的顺序:先从对象空间找 ------> 类空间找 ------> 父类空间找 ------->.....
|
||||
|
||||
类名查找属性的顺序:先从本类空间找 -------> 父类空间找--------> ........
|
||||
|
||||
上面的顺序都是单向不可逆,类名不可能找到对象的属性。
|
||||
|
||||
## 类与类之间的关系
|
||||
|
||||
类与类中存在以下关系:
|
||||
|
||||
1. 依赖关系
|
||||
2. 关联关系
|
||||
3. 组合关系
|
||||
4. 聚合关系
|
||||
5. 实现关系
|
||||
6. 继承关系(类的三大特性之一:继承。)
|
||||
|
||||
### 依赖关系
|
||||
|
||||
例:将大象装进冰箱,需要两个类, ⼀个是⼤象类, ⼀个是冰箱类
|
||||
|
||||
```python
|
||||
class Elphant:
|
||||
def __init__(self,name):
|
||||
self.name = name
|
||||
|
||||
def open(self):
|
||||
'''
|
||||
开门
|
||||
'''
|
||||
pass
|
||||
|
||||
def close(self):
|
||||
'''
|
||||
关门
|
||||
'''
|
||||
pass
|
||||
|
||||
class Refrigerator:
|
||||
def open_door(self):
|
||||
print('冰箱门打开了')
|
||||
|
||||
def open_door(self):
|
||||
print('冰箱门关上了')
|
||||
```
|
||||
|
||||
将大象类和冰箱类进行依赖
|
||||
|
||||
```python
|
||||
class Elphant:
|
||||
def __init__(self,name):
|
||||
self.name = name
|
||||
|
||||
def open(self,obj1):
|
||||
'''
|
||||
开门
|
||||
'''
|
||||
print(self.name,'要开门了')
|
||||
obj1.open_door()
|
||||
|
||||
def close(self):
|
||||
'''
|
||||
关门
|
||||
'''
|
||||
pass
|
||||
|
||||
class Refrigerator:
|
||||
def open_door(self):
|
||||
print('冰箱门打开了')
|
||||
|
||||
def close_door(self):
|
||||
print('冰箱门关上了')
|
||||
|
||||
elphant1 = Elphant('大象')
|
||||
haier = Refrigerator()
|
||||
elphant1.open(haier)
|
||||
```
|
||||
|
||||
### 关联,聚合,组合关系
|
||||
|
||||
其实这三个在代码上写法是⼀样的. 但是, 从含义上是不⼀样的.
|
||||
|
||||
1. 关联关系. 两种事物必须是互相关联的. 但是在某些特殊情况下是可以更改和更换的.
|
||||
|
||||
2. 聚合关系. 属于关联关系中的⼀种特例. 侧重点是xxx和xxx聚合成xxx. 各⾃有各⾃的声明周期. 比如电脑. 电脑⾥有CPU, 硬盘, 内存等等. 电脑挂了. CPU还是好的. 还是完整的个体
|
||||
|
||||
3. 组合关系. 属于关联关系中的⼀种特例. 写法上差不多. 组合关系比聚合还要紧密. 比如⼈的⼤脑, ⼼脏, 各个器官. 这些器官组合成⼀个⼈. 这时. ⼈如果挂了. 其他的东⻄也跟着挂了
|
||||
|
||||
**关联关系**
|
||||
|
||||
```python
|
||||
class Boy:
|
||||
def __init__(self,name,girlFirend=None):
|
||||
self.name = name
|
||||
self.girlFriend = girlFirend
|
||||
|
||||
def have_a_dinner(self):
|
||||
if self.girlFriend:
|
||||
print('%s 和 %s 一起晚饭'%(self.name,self.girlFriend.name))
|
||||
else:
|
||||
print('单身狗,吃什么饭')
|
||||
|
||||
class Girl:
|
||||
def __init__(self,name):
|
||||
self.name = name
|
||||
|
||||
b = Boy('日天')
|
||||
b.have_a_dinner()
|
||||
|
||||
b.girlFriend = Girl('如花')
|
||||
b.have_a_dinner()
|
||||
|
||||
gg = Girl('花花')
|
||||
bb = Boy('songsong',gg)
|
||||
bb.have_a_dinner()
|
||||
```
|
||||
|
||||
注意. 此时Boy和Girl两个类之间就是关联关系. 两个类的对象紧密联系着. 其中⼀个没有了. 另⼀个就孤单的不得了. 关联关系, 其实就是 我需要你. 你也属于我
|
||||
|
||||
学校和老师之间的关系
|
||||
|
||||
```python
|
||||
class School:
|
||||
|
||||
def __init__(self,name,address):
|
||||
self.name = name
|
||||
self.address = address
|
||||
|
||||
|
||||
class Teacher:
|
||||
|
||||
def __init__(self,name,school):
|
||||
self.name = name
|
||||
self.school = school
|
||||
|
||||
s1 = School('北京校区','北京')
|
||||
s2 = School('上海校区','上海')
|
||||
s3 = School('深圳校区','深圳')
|
||||
|
||||
t1 = Teacher('T1',s1)
|
||||
t2 = Teacher('T2',s2)
|
||||
t3 = Teacher('T3',s3)
|
||||
|
||||
print(t1.school.name)
|
||||
print(t2.school.name)
|
||||
print(t3.school.name)
|
||||
```
|
||||
|
||||
但是学校也是依赖于老师的,所以老师学校应该互相依赖。
|
||||
|
||||
```python
|
||||
class School:
|
||||
|
||||
def __init__(self,name,address):
|
||||
self.name = name
|
||||
self.address = address
|
||||
self.teacher_list = []
|
||||
def append_teacher(self,teacher):
|
||||
self.teacher_list.append(teacher)
|
||||
|
||||
|
||||
class Teacher:
|
||||
|
||||
def __init__(self,name,school):
|
||||
self.name = name
|
||||
self.school = school
|
||||
|
||||
s1 = School('北京校区','北京')
|
||||
s2 = School('上海校区','上海')
|
||||
s3 = School('深圳校区','深圳')
|
||||
|
||||
t1 = Teacher('T1',s1)
|
||||
t2 = Teacher('T2',s2)
|
||||
t3 = Teacher('T3',s3)
|
||||
|
||||
s1.append_teacher(t1.name)
|
||||
s1.append_teacher(t2.name)
|
||||
s1.append_teacher(t3.name)
|
||||
|
||||
print(s1.teacher_list)
|
||||
```
|
||||
|
||||
**组合:将一个类的对象封装到另一个类的对象的属性中,就叫组合。**
|
||||
|
||||
例:设计一个游戏,让游戏里面的人物互殴
|
||||
|
||||
```python
|
||||
class Gamerole:
|
||||
def __init__(self,name,ad,hp):
|
||||
self.name = name
|
||||
self.ad = ad
|
||||
self.hp = hp
|
||||
|
||||
def attack(self,p1):
|
||||
p1.hp -= self.ad
|
||||
print('%s攻击%s,%s掉了%s血,还剩%s'%(self.name,p1.name,p1.name,self.ad,p1.hp))
|
||||
|
||||
man = Gamerole('人',10,100)
|
||||
dog = Gamerole('狗',50,100)
|
||||
|
||||
dog.attack(man)
|
||||
man.attack(dog)
|
||||
```
|
||||
|
||||
加上一个武器类,让人使用武器攻击
|
||||
|
||||
```python
|
||||
class Gamerole:
|
||||
def __init__(self,name,ad,hp):
|
||||
self.name = name
|
||||
self.ad = ad
|
||||
self.hp = hp
|
||||
|
||||
def attack(self,p1):
|
||||
p1.hp -= self.ad
|
||||
print('%s攻击%s,%s掉了%s血,还剩%s'%(self.name,p1.name,p1.name,self.ad,p1.hp))
|
||||
|
||||
def equip_weapon(self,wea):
|
||||
self.wea = wea
|
||||
|
||||
class Weapon:
|
||||
def __init__(self,name,ad):
|
||||
self.name = name
|
||||
self.ad = ad
|
||||
def weapon_attack(self,p1,p2):
|
||||
p2.hp = p2.hp - self.ad - p1.ad
|
||||
print('%s利用%s攻击了%s,%s还剩%s血'%(p1.name,self.name,p2.name,p2.name,p2.hp))
|
||||
|
||||
|
||||
|
||||
man = Gamerole('人',10,100)
|
||||
dog = Gamerole('狗',50,100)
|
||||
stick = Weapon('木棍',40)
|
||||
|
||||
man.equip_weapon(stick)
|
||||
man.wea.weapon_attack(man,dog)
|
||||
# 人利用木棍攻击了狗,狗还剩50血
|
||||
```
|
422
02.面向对象/03.类的继承.md
Normal file
422
02.面向对象/03.类的继承.md
Normal file
@@ -0,0 +1,422 @@
|
||||
# 类的继承
|
||||
|
||||
## 面向对象的继承
|
||||
|
||||
不用继承创建对象
|
||||
|
||||
```python
|
||||
class Person:
|
||||
def __init__(self,name,sex,age):
|
||||
self.name = name
|
||||
self.age = age
|
||||
self.sex = sex
|
||||
|
||||
class Cat:
|
||||
def __init__(self,name,sex,age):
|
||||
self.name = name
|
||||
self.age = age
|
||||
self.sex = sex
|
||||
|
||||
class Dog:
|
||||
def __init__(self,name,sex,age):
|
||||
self.name = name
|
||||
self.age = age
|
||||
self.sex = sex
|
||||
```
|
||||
|
||||
使用继承的方式
|
||||
|
||||
```python
|
||||
class Aniaml(object):
|
||||
def __init__(self,name,sex,age):
|
||||
self.name = name
|
||||
self.age = age
|
||||
self.sex = sex
|
||||
|
||||
class Person(Aniaml):
|
||||
pass
|
||||
|
||||
class Cat(Aniaml):
|
||||
pass
|
||||
|
||||
class Dog(Aniaml):
|
||||
pass
|
||||
```
|
||||
|
||||
继承的有点也是显而易见的:
|
||||
|
||||
1. 增加了类的耦合性(耦合性不宜多,宜精)。
|
||||
|
||||
2. 减少了重复代码。
|
||||
|
||||
3. 使得代码更加规范化,合理化。
|
||||
|
||||
## 继承的分类
|
||||
|
||||
上面的那个例子:
|
||||
|
||||
- Aminal 叫做父类,基类,超类。
|
||||
- Person Cat Dog: 子类,派生类。
|
||||
|
||||
继承:可以分**单继承,多继承**。
|
||||
|
||||
这里需要补充一下python中类的种类(继承需要):
|
||||
|
||||
在python2x版本中存在两种类.:
|
||||
|
||||
- ⼀个叫**经典类**. 在python2.2之前. ⼀直使⽤的是经典类. 经典类在基类的根如果什么都不写.
|
||||
- ⼀个叫**新式类**. 在python2.2之后出现了新式类. 新式类的特点是基类的根是object类。
|
||||
python3x版本中只有一种类:
|
||||
python3中使⽤的都是**新式类**. 如果基类谁都不继承. 那这个类会默认继承 object
|
||||
|
||||
## 单继承
|
||||
|
||||
### 类名,对象执行父类方法
|
||||
|
||||
```python
|
||||
class Aniaml(object):
|
||||
type_name = '动物类'
|
||||
|
||||
def __init__(self,name,sex,age):
|
||||
self.name = name
|
||||
self.age = age
|
||||
self.sex = sex
|
||||
|
||||
def eat(self):
|
||||
print('吃',self)
|
||||
|
||||
class Person(Aniaml):
|
||||
pass
|
||||
|
||||
class Cat(Aniaml):
|
||||
pass
|
||||
|
||||
class Dog(Aniaml):
|
||||
pass
|
||||
|
||||
print(Person.type_name)
|
||||
Person.eat('东西')
|
||||
print(Person.type_name)
|
||||
|
||||
p1 = Person('aaron','男',18)
|
||||
print(p1.__dict__)
|
||||
print(p1.type_name)
|
||||
p1.type_name = '666'
|
||||
print(p1)
|
||||
p1.eat()
|
||||
```
|
||||
|
||||
### 执行顺序
|
||||
|
||||
```python
|
||||
class Aniaml(object):
|
||||
type_name = '动物类'
|
||||
|
||||
def __init__(self,name,sex,age):
|
||||
self.name = name
|
||||
self.age = age
|
||||
self.sex = sex
|
||||
|
||||
def eat(self):
|
||||
print('吃',self)
|
||||
|
||||
class Person(Aniaml):
|
||||
|
||||
def eat(self):
|
||||
print('%s 用筷子吃饭'%self.name)
|
||||
|
||||
class Cat(Aniaml):
|
||||
pass
|
||||
|
||||
class Dog(Aniaml):
|
||||
pass
|
||||
|
||||
p1 = Person('eagle','男',18)
|
||||
p1.eat()
|
||||
```
|
||||
|
||||
### 同时执行类以及父类方法
|
||||
|
||||
方法一:如果想执行父类的func方法,这个方法并且子类中夜用,那么就在子类的方法中写上:父类.func(对象,其他参数)
|
||||
|
||||
```python
|
||||
class Aniaml(object):
|
||||
type_name = '动物类'
|
||||
def __init__(self,name,sex,age):
|
||||
self.name = name
|
||||
self.age = age
|
||||
self.sex = sex
|
||||
|
||||
def eat(self):
|
||||
print('吃东西')
|
||||
|
||||
class Person(Aniaml):
|
||||
def __init__(self,name,sex,age,mind):
|
||||
Aniaml.__init__(self,name,sex,age)
|
||||
self.mind = mind
|
||||
|
||||
def eat(self):
|
||||
Aniaml.eat(111)
|
||||
print('%s 吃饭'%self.name)
|
||||
class Cat(Aniaml):
|
||||
pass
|
||||
|
||||
class Dog(Aniaml):
|
||||
pass
|
||||
|
||||
p1 = Person('aaron','男',18,'想吃东西')
|
||||
p1.eat()
|
||||
```
|
||||
|
||||
方法二:利用super,super().func(参数)
|
||||
|
||||
```python
|
||||
class Aniaml(object):
|
||||
type_name = '动物类'
|
||||
def __init__(self,name,sex,age):
|
||||
self.name = name
|
||||
self.age = age
|
||||
self.sex = sex
|
||||
|
||||
def eat(self):
|
||||
print('吃东西')
|
||||
|
||||
class Person(Aniaml):
|
||||
def __init__(self,name,sex,age,mind):
|
||||
# super(Person,self).__init__(name,sex,age)
|
||||
super().__init__(name,sex,age)
|
||||
self.mind = mind
|
||||
|
||||
def eat(self):
|
||||
super().eat()
|
||||
print('%s 吃饭'%self.name)
|
||||
class Cat(Aniaml):
|
||||
pass
|
||||
|
||||
class Dog(Aniaml):
|
||||
pass
|
||||
|
||||
p1 = Person('aaron','男',18,'想吃东西')
|
||||
p1.eat()
|
||||
```
|
||||
|
||||
单继承练习题
|
||||
|
||||
```python
|
||||
class Base:
|
||||
def __init__(self,num):
|
||||
self.num = num
|
||||
def func1(self):
|
||||
print(self.num)
|
||||
|
||||
class Foo(Base):
|
||||
pass
|
||||
|
||||
obj = Foo(123)
|
||||
obj.func1()
|
||||
# 运⾏的是Base中的func1
|
||||
```
|
||||
|
||||
```python
|
||||
class Base:
|
||||
def __init__(self,num):
|
||||
self.num = num
|
||||
def func1(self):
|
||||
print(self.num)
|
||||
|
||||
class Foo(Base):
|
||||
def func1(self):
|
||||
print("Foo.func1",self.num)
|
||||
|
||||
obj = Foo(123)
|
||||
obj.func1()
|
||||
# 运⾏的是Foo中的func1
|
||||
```
|
||||
|
||||
```python
|
||||
class Base:
|
||||
def __init__(self, num):
|
||||
self.num = num
|
||||
def func1(self):
|
||||
print(self.num)
|
||||
self.func2()
|
||||
def func2(self):
|
||||
print("Base.func2")
|
||||
class Foo(Base):
|
||||
def func2(self):
|
||||
print("Foo.func2")
|
||||
|
||||
obj = Foo(123)
|
||||
obj.func1()
|
||||
# func1是Base中的 func2是⼦类中的
|
||||
```
|
||||
|
||||
```python
|
||||
class Base:
|
||||
def __init__(self, num):
|
||||
self.num = num
|
||||
def func1(self):
|
||||
print(self.num)
|
||||
self.func2()
|
||||
def func2(self):
|
||||
print(111, self.num)
|
||||
class Foo(Base):
|
||||
def func2(self):
|
||||
print(222, self.num)
|
||||
|
||||
lst = [Base(1), Base(2), Foo(3)]
|
||||
for obj in lst:
|
||||
obj.func2()
|
||||
```
|
||||
|
||||
```python
|
||||
class Base:
|
||||
def __init__(self, num):
|
||||
self.num = num
|
||||
def func1(self):
|
||||
print(self.num)
|
||||
self.func2()
|
||||
def func2(self):
|
||||
print(111, self.num)
|
||||
class Foo(Base):
|
||||
def func2(self):
|
||||
print(222, self.num)
|
||||
|
||||
lst = [Base(1), Base(2), Foo(3)]
|
||||
for obj in lst:
|
||||
obj.func1()
|
||||
```
|
||||
|
||||
## 多继承
|
||||
|
||||
```python
|
||||
class ShenXian: # 神仙
|
||||
def fei(self):
|
||||
print("神仙都会⻜")
|
||||
class Monkey: # 猴
|
||||
def chitao(self):
|
||||
print("猴⼦喜欢吃桃⼦")
|
||||
class SunWukong(ShenXian, Monkey): # 孙悟空是神仙, 同时也是⼀只猴
|
||||
pass
|
||||
|
||||
sxz = SunWukong() # 孙悟空
|
||||
sxz.chitao() # 会吃桃⼦
|
||||
sxz.fei() # 会⻜
|
||||
```
|
||||
|
||||
### 经典类的多继承
|
||||
|
||||
```python
|
||||
class A:
|
||||
pass
|
||||
class B(A):
|
||||
pass
|
||||
class C(A):
|
||||
pass
|
||||
class D(B, C):
|
||||
pass
|
||||
class E:
|
||||
pass
|
||||
class F(D, E):
|
||||
pass
|
||||
class G(F, D):
|
||||
pass
|
||||
class H:
|
||||
pass
|
||||
class Foo(H, G):
|
||||
pass
|
||||
```
|
||||
|
||||
画图
|
||||
|
||||

|
||||
|
||||
在经典类中采⽤的是深度优先,遍历⽅案. 什么是深度优先. 就是⼀条路走到头. 然后再回来. 继续找下⼀个.
|
||||
|
||||
类的MRO(method resolution order): Foo-> H -> G -> F -> E -> D -> B -> A -> C.
|
||||
|
||||
### 新式类的多继承
|
||||
|
||||
#### mro序列
|
||||
|
||||
MRO是一个有序列表L,在类被创建时就计算出来。
|
||||
|
||||
通用计算公式为:
|
||||
|
||||
mro(Child(Base1,Base2)) = [ Child ] + merge( mro(Base1), mro(Base2), [ Base1, Base2] )(其中Child继承自Base1, Base2)
|
||||
|
||||
如果继承至一个基类:class B(A)
|
||||
这时B的mro序列为
|
||||
|
||||
mro( B ) = mro( B(A) )
|
||||
= [B] + merge( mro(A) + [A] )
|
||||
= [B] + merge( [A] + [A] )
|
||||
= [B,A]
|
||||
|
||||
如果继承至多个基类:class B(A1, A2, A3 …)
|
||||
这时B的mro序列
|
||||
|
||||
mro(B) = mro( B(A1, A2, A3 …) )
|
||||
= [B] + merge( mro(A1), mro(A2), mro(A3) ..., [A1, A2, A3] )
|
||||
= ...
|
||||
|
||||
计算结果为列表,列表中至少有一个元素即类自己,如上述示例[A1,A2,A3]。merge操作是C3算法的核心。
|
||||
|
||||
#### 表头和表尾
|
||||
|
||||
表头:列表的第一个元素
|
||||
|
||||
表尾:列表中表头以外的元素集合(可以为空)
|
||||
|
||||
示例:列表:[A, B, C] 表头是A,表尾是B和C
|
||||
|
||||
#### 列表之间的+操作
|
||||
|
||||
[A] + [B] = [A, B]
|
||||
|
||||
merge操作示例:
|
||||
|
||||
如计算merge( [E,O], [C,E,F,O], [C] )
|
||||
有三个列表 : ① ② ③
|
||||
|
||||
1 merge不为空,取出第一个列表列表①的表头E,进行判断
|
||||
各个列表的表尾分别是[O], [E,F,O],E在这些表尾的集合中,因而跳过当前当前列表
|
||||
2 取出列表②的表头C,进行判断
|
||||
C不在各个列表的集合中,因而将C拿出到merge外,并从所有表头删除
|
||||
merge( [E,O], [C,E,F,O], [C]) = [C] + merge( [E,O], [E,F,O] )
|
||||
3 进行下一次新的merge操作 ......
|
||||
---------------------
|
||||
|
||||

|
||||
|
||||
计算mro(A)方式:
|
||||
|
||||
mro(A) = mro( A(B,C) )
|
||||
|
||||
原式= [A] + merge( mro(B),mro(C),[B,C] )
|
||||
|
||||
mro(B) = mro( B(D,E) )
|
||||
= [B] + merge( mro(D), mro(E), [D,E] ) # 多继承
|
||||
= [B] + merge( [D,O] , [E,O] , [D,E] ) # 单继承mro(D(O))=[D,O]
|
||||
= [B,D] + merge( [O] , [E,O] , [E] ) # 拿出并删除D
|
||||
= [B,D,E] + merge([O] , [O])
|
||||
= [B,D,E,O]
|
||||
|
||||
mro(C) = mro( C(E,F) )
|
||||
= [C] + merge( mro(E), mro(F), [E,F] )
|
||||
= [C] + merge( [E,O] , [F,O] , [E,F] )
|
||||
= [C,E] + merge( [O] , [F,O] , [F] ) # 跳过O,拿出并删除
|
||||
= [C,E,F] + merge([O] , [O])
|
||||
= [C,E,F,O]
|
||||
|
||||
原式= [A] + merge( [B,D,E,O], [C,E,F,O], [B,C])
|
||||
= [A,B] + merge( [D,E,O], [C,E,F,O], [C])
|
||||
= [A,B,D] + merge( [E,O], [C,E,F,O], [C]) # 跳过E
|
||||
= [A,B,D,C] + merge([E,O], [E,F,O])
|
||||
= [A,B,D,C,E] + merge([O], [F,O]) # 跳过O
|
||||
= [A,B,D,C,E,F] + merge([O], [O])
|
||||
= [A,B,D,C,E,F,O]
|
||||
|
||||
那既然python提供了. 为什么我们还要如此⿇烦的计算MRO呢? 因为笔
|
||||
试.......你在笔试的时候, 是没有电脑的. 所以这个算法要知道. 并且简单的计算要会. 正式项⽬
|
||||
开发的时候很少有⼈这么去写代码.
|
BIN
02.面向对象/03.类的继承/image-20210725220109579.png
Normal file
BIN
02.面向对象/03.类的继承/image-20210725220109579.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 50 KiB |
BIN
02.面向对象/03.类的继承/image-20210725220122519.png
Normal file
BIN
02.面向对象/03.类的继承/image-20210725220122519.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 26 KiB |
313
02.面向对象/04.封装与多态.md
Normal file
313
02.面向对象/04.封装与多态.md
Normal file
@@ -0,0 +1,313 @@
|
||||
# 封装与多态
|
||||
|
||||
python面向对象的三大特性:继承,封装,多态。
|
||||
|
||||
1. **封装**: 把很多数据封装到⼀个对象中. 把固定功能的代码封装到⼀个代码块, 函数, 对象, 打包成模块. 这都属于封装的思想. 具体的情况具体分析. 比如. 你写了⼀个很⽜B的函数. 那这个也可以被称为封装. 在⾯向对象思想中. 是把⼀些看似⽆关紧要的内容组合到⼀起统⼀进⾏存储和使⽤. 这就是封装.
|
||||
|
||||
2. **继承**: ⼦类可以⾃动拥有⽗类中除了私有属性外的其他所有内容. 说⽩了, ⼉⼦可以随便⽤爹的东⻄. 但是朋友们, ⼀定要认清楚⼀个事情. 必须先有爹, 后有⼉⼦. 顺序不能乱, 在python中实现继承非常简单. 在声明类的时候, 在类名后⾯添加⼀个⼩括号,就可以完成继承关系. 那么什么情况可以使⽤继承呢? 单纯的从代码层⾯上来看. 两个类具有相同的功能或者特征的时候. 可以采⽤继承的形式. 提取⼀个⽗类, 这个⽗类中编写着两个类相同的部分. 然后两个类分别取继承这个类就可以了. 这样写的好处是我们可以避免写很多重复的功能和代码. 如果从语义中去分析的话. 会简单很多. 如果语境中出现了x是⼀种y. 这时, y是⼀种泛化的概念. x比y更加具体. 那这时x就是y的⼦类. 比如. 猫是⼀种动物. 猫继承动物. 动物能动. 猫也能动. 这时猫在创建的时候就有了动物的"动"这个属性. 再比如, ⽩骨精是⼀个妖怪. 妖怪天⽣就有⼀个比较不好的功能叫"吃⼈", ⽩骨精⼀出⽣就知道如何"吃⼈". 此时 ⽩骨精继承妖精.
|
||||
3. **多态**: 同⼀个对象, 多种形态. 这个在python中其实是很不容易说明⽩的. 因为我们⼀直在⽤. 只是没有具体的说. 比如. 我们创建⼀个变量a = 10 , 我们知道此时a是整数类型. 但是我们可以通过程序让a = "hello", 这时, a⼜变成了字符串类型. 这是我们都知道的. 但是, 我要告诉你的是. 这个就是多态性. 同⼀个变量a可以是多种形态。
|
||||
|
||||
## 封装
|
||||
|
||||
第一步:将内容封装到某处
|
||||
|
||||
```python
|
||||
class Foo:
|
||||
def __init__(self,name,age):
|
||||
self.name = name
|
||||
self.age = age
|
||||
|
||||
obj1 = Foo('chensong',18)
|
||||
obj2 = Foo('aaron',16)
|
||||
```
|
||||
|
||||
第二步:从某处调用被封装的内容
|
||||
|
||||
```python
|
||||
class Foo:
|
||||
def __init__(self,name,age):
|
||||
self.name = name
|
||||
self.age = age
|
||||
|
||||
def detail(self):
|
||||
print(self.name)
|
||||
print(self.age)
|
||||
|
||||
obj1 = Foo('chensong',18)
|
||||
obj2 = Foo('aaron',16)
|
||||
|
||||
print(obj1.name)
|
||||
print(obj2.age)
|
||||
# 通过对象直接调用被封装的内容
|
||||
|
||||
obj1.detail()
|
||||
obj2.detail()
|
||||
# 通过self间接调用被封装的内容
|
||||
```
|
||||
|
||||
## 多态
|
||||
|
||||
多态,同一个对象,多种形态。python默认支持多态。
|
||||
|
||||
python中有一句谚语说的好,你看起来像鸭子,那么你就是鸭子。
|
||||
对于代码上的解释其实很简答:
|
||||
|
||||
```python
|
||||
class A:
|
||||
def f1(self):
|
||||
print('in A f1')
|
||||
|
||||
def f2(self):
|
||||
print('in A f2')
|
||||
|
||||
|
||||
class B:
|
||||
def f1(self):
|
||||
print('in B f1')
|
||||
|
||||
def f2(self):
|
||||
print('in B f2')
|
||||
|
||||
obj = A()
|
||||
obj.f1()
|
||||
obj.f2()
|
||||
|
||||
obj2 = B()
|
||||
obj2.f1()
|
||||
obj2.f2()
|
||||
# A 和 B两个类完全没有耦合性,但是在某种意义上他们却统一了一个标准。
|
||||
# 对相同的功能设定了相同的名字,这样方便开发,这两个方法就可以互成为鸭子类型。
|
||||
|
||||
# 这样的例子比比皆是:str tuple list 都有 index方法,这就是统一了规范。
|
||||
# str bytes 等等 这就是互称为鸭子类型。
|
||||
```
|
||||
|
||||
## 类的约束
|
||||
|
||||
写一个支付功能
|
||||
|
||||
```python
|
||||
class QQpay:
|
||||
def pay(self,money):
|
||||
print('使用qq支付%s元' % money)
|
||||
|
||||
class Alipay:
|
||||
def pay(self,money):
|
||||
print('使用阿里支付%s元' % money)
|
||||
|
||||
a = Alipay()
|
||||
a.pay(100)
|
||||
|
||||
b = QQpay()
|
||||
b.pay(200)
|
||||
```
|
||||
|
||||
统一一下付款方式
|
||||
|
||||
```python
|
||||
class QQpay:
|
||||
def pay(self,money):
|
||||
print('使用qq支付%s元' % money)
|
||||
|
||||
class Alipay:
|
||||
def pay(self,money):
|
||||
print('使用阿里支付%s元' % money)
|
||||
|
||||
def pay(obj,money):
|
||||
obj.pay(money)
|
||||
|
||||
|
||||
a = Alipay()
|
||||
b = QQpay()
|
||||
|
||||
pay(a,100)
|
||||
pay(b,200)
|
||||
```
|
||||
|
||||
如果后期添加微信支付,但是没有统一标准,换个程序员就可能写成这样
|
||||
|
||||
```python
|
||||
class QQpay:
|
||||
def pay(self,money):
|
||||
print('使用qq支付%s元' % money)
|
||||
|
||||
class Alipay:
|
||||
def pay(self,money):
|
||||
print('使用阿里支付%s元' % money)
|
||||
|
||||
class Wechatpay:
|
||||
def fuqian(self,money):
|
||||
print('使用微信支付%s元' % money)
|
||||
|
||||
def pay(obj,money):
|
||||
obj.pay(money)
|
||||
|
||||
|
||||
a = Alipay()
|
||||
b = QQpay()
|
||||
|
||||
pay(a,100)
|
||||
pay(b,200)
|
||||
|
||||
c = Wechatpay()
|
||||
c.fuqian(300)
|
||||
```
|
||||
|
||||
所以此时我们要用到对类的约束,对类的约束有两种:
|
||||
|
||||
1. 提取⽗类. 然后在⽗类中定义好⽅法. 在这个⽅法中什么都不⽤⼲. 就抛⼀个异常就可以了. 这样所有的⼦类都必须重写这个⽅法. 否则. 访问的时候就会报错.
|
||||
|
||||
2. 使⽤元类来描述⽗类. 在元类中给出⼀个抽象⽅法. 这样⼦类就不得不给出抽象⽅法的具体实现. 也可以起到约束的效果.
|
||||
|
||||
- 先用第一种方法解决问题
|
||||
|
||||
```python
|
||||
class Payment:
|
||||
"""
|
||||
此类什么都不做,就是制定一个标准,谁继承我,必须定义我里面的方法。
|
||||
"""
|
||||
def pay(self,money):
|
||||
raise Exception("你没有实现pay方法")
|
||||
|
||||
class QQpay(Payment):
|
||||
def pay(self,money):
|
||||
print('使用qq支付%s元' % money)
|
||||
|
||||
class Alipay(Payment):
|
||||
def pay(self,money):
|
||||
print('使用阿里支付%s元' % money)
|
||||
|
||||
class Wechatpay(Payment):
|
||||
def fuqian(self,money):
|
||||
print('使用微信支付%s元' % money)
|
||||
|
||||
|
||||
def pay(obj,money):
|
||||
obj.pay(money)
|
||||
|
||||
a = Alipay()
|
||||
b = QQpay()
|
||||
c = Wechatpay()
|
||||
pay(a,100)
|
||||
pay(b,200)
|
||||
pay(c,300)
|
||||
```
|
||||
|
||||
- 引入抽象类的概念处理
|
||||
|
||||
```python
|
||||
from abc import ABCMeta,abstractmethod
|
||||
class Payment(metaclass=ABCMeta): # 抽象类 接口类 规范和约束 metaclass指定的是一个元类
|
||||
@abstractmethod
|
||||
def pay(self):pass # 抽象方法
|
||||
|
||||
class Alipay(Payment):
|
||||
def pay(self,money):
|
||||
print('使用支付宝支付了%s元'%money)
|
||||
|
||||
class QQpay(Payment):
|
||||
def pay(self,money):
|
||||
print('使用qq支付了%s元'%money)
|
||||
|
||||
class Wechatpay(Payment):
|
||||
# def pay(self,money):
|
||||
# print('使用微信支付了%s元'%money)
|
||||
def recharge(self):pass
|
||||
|
||||
def pay(a,money):
|
||||
a.pay(money)
|
||||
|
||||
a = Alipay()
|
||||
a.pay(100)
|
||||
pay(a,100) # 归一化设计:不管是哪一个类的对象,都调用同一个函数去完成相似的功能
|
||||
q = QQpay()
|
||||
q.pay(100)
|
||||
pay(q,100)
|
||||
w = Wechatpay()
|
||||
pay(w,100) # 到用的时候才会报错
|
||||
|
||||
|
||||
|
||||
# 抽象类和接口类做的事情 :建立规范
|
||||
# 制定一个类的metaclass是ABCMeta,
|
||||
# 那么这个类就变成了一个抽象类(接口类)
|
||||
# 这个类的主要功能就是建立一个规范
|
||||
```
|
||||
|
||||
总结: 约束. 其实就是⽗类对⼦类进⾏约束. ⼦类必须要写xxx⽅法. 在python中约束的⽅式和⽅法有两种:
|
||||
|
||||
1. 使⽤抽象类和抽象⽅法, 由于该⽅案来源是java和c#. 所以使⽤频率还是很少的
|
||||
|
||||
2. 使⽤⼈为抛出异常的⽅案. 并且尽量抛出的是NotImplementError. 这样比较专业, ⽽且错误比较明确.(推荐)
|
||||
|
||||
## super()深入了解
|
||||
|
||||
**super是严格按照类的继承顺序执行!!!**
|
||||
|
||||
```python
|
||||
class A:
|
||||
def f1(self):
|
||||
print('in A f1')
|
||||
|
||||
def f2(self):
|
||||
print('in A f2')
|
||||
|
||||
|
||||
class Foo(A):
|
||||
def f1(self):
|
||||
super().f2()
|
||||
print('in A Foo')
|
||||
|
||||
|
||||
obj = Foo()
|
||||
obj.f1()
|
||||
```
|
||||
|
||||
```python
|
||||
class A:
|
||||
def f1(self):
|
||||
print('in A')
|
||||
|
||||
class Foo(A):
|
||||
def f1(self):
|
||||
super().f1()
|
||||
print('in Foo')
|
||||
|
||||
class Bar(A):
|
||||
def f1(self):
|
||||
print('in Bar')
|
||||
|
||||
class Info(Foo,Bar):
|
||||
def f1(self):
|
||||
super().f1()
|
||||
print('in Info f1')
|
||||
|
||||
obj = Info()
|
||||
obj.f1()
|
||||
|
||||
print(Info.mro())
|
||||
```
|
||||
|
||||
```python
|
||||
class A:
|
||||
def f1(self):
|
||||
print('in A')
|
||||
|
||||
class Foo(A):
|
||||
def f1(self):
|
||||
super().f1()
|
||||
print('in Foo')
|
||||
|
||||
class Bar(A):
|
||||
def f1(self):
|
||||
print('in Bar')
|
||||
|
||||
class Info(Foo,Bar):
|
||||
def f1(self):
|
||||
super(Foo,self).f1()
|
||||
print('in Info f1')
|
||||
|
||||
obj = Info()
|
||||
obj.f1()
|
||||
```
|
||||
|
497
02.面向对象/05.类的成员.md
Normal file
497
02.面向对象/05.类的成员.md
Normal file
@@ -0,0 +1,497 @@
|
||||
# 类的成员
|
||||
|
||||
## 细分类的组成成员
|
||||
|
||||
之前咱们讲过类大致分两块区域
|
||||
|
||||
```python
|
||||
class A:
|
||||
name = '陈松'
|
||||
|
||||
# 第一部分:静态字段(静态变量)部分
|
||||
|
||||
def __init__(self):
|
||||
pass
|
||||
def func(self):
|
||||
pass
|
||||
|
||||
# 第二部分:方法部分
|
||||
```
|
||||
|
||||
每个区域详细划分
|
||||
|
||||
```python
|
||||
class A:
|
||||
|
||||
company_name = '陈松' # 静态变量(静态字段)
|
||||
__iphone = '132333xxxx' # 私有静态变量(私有静态字段)
|
||||
|
||||
def __init__(self,name,age): #特殊方法
|
||||
self.name = name #对象属性(普通字段)
|
||||
self.__age = age # 私有对象属性(私有普通字段)
|
||||
|
||||
def func1(self): # 普通方法
|
||||
pass
|
||||
|
||||
def __func(self): #私有方法
|
||||
print(666)
|
||||
|
||||
@classmethod # 类方法
|
||||
def class_func(cls):
|
||||
""" 定义类方法,至少有一个cls参数 """
|
||||
print('类方法')
|
||||
|
||||
@staticmethod #静态方法
|
||||
def static_func():
|
||||
""" 定义静态方法 ,无默认参数"""
|
||||
print('静态方法')
|
||||
|
||||
@property # 属性
|
||||
def prop(self):
|
||||
pass
|
||||
```
|
||||
|
||||
## 类的私有成员
|
||||
|
||||
对于每一个类的成员而言都有两种形式:
|
||||
|
||||
- 公有成员,在任何地方都能访问
|
||||
- 私有成员,只有在类的内部才能方法
|
||||
|
||||
**私有成员和公有成员的访问限制不同:**
|
||||
|
||||
静态字段(静态属性)
|
||||
|
||||
- 公有静态字段:类可以访问;类内部可以访问;派生类中可以访问
|
||||
- 私有静态字段:仅类内部可以访问;
|
||||
|
||||
```python
|
||||
class C:
|
||||
|
||||
name = "公有静态字段"
|
||||
|
||||
def func(self):
|
||||
print (C.name)
|
||||
|
||||
class D(C):
|
||||
|
||||
def show(self):
|
||||
print (C.name)
|
||||
|
||||
|
||||
print(C.name) # 类访问
|
||||
|
||||
obj = C()
|
||||
obj.func() # 类内部可以访问
|
||||
|
||||
obj_son = D()
|
||||
obj_son.show() # 派生类中可以访问
|
||||
```
|
||||
|
||||
```python
|
||||
class C:
|
||||
|
||||
__name = "私有静态字段"
|
||||
|
||||
def func(self):
|
||||
print (C.__name)
|
||||
|
||||
class D(C):
|
||||
|
||||
def show(self):
|
||||
print (C.__name)
|
||||
|
||||
|
||||
print(C.__name) # 不可在外部访问
|
||||
|
||||
obj = C()
|
||||
print(C.__name) # 不可在外部访问
|
||||
obj.func() # 类内部可以访问
|
||||
|
||||
obj_son = D()
|
||||
obj_son.show() #不可在派生类中可以访问
|
||||
```
|
||||
|
||||
普通字段(对象属性)
|
||||
|
||||
公有普通字段:对象可以访问;类内部可以访问;派生类中可以访问
|
||||
私有普通字段:仅类内部可以访问;
|
||||
|
||||
```python
|
||||
class C:
|
||||
|
||||
def __init__(self):
|
||||
self.foo = "公有字段"
|
||||
|
||||
def func(self):
|
||||
print(self.foo) # 类内部访问
|
||||
|
||||
class D(C):
|
||||
|
||||
def show(self):
|
||||
print(self.foo) # 派生类中访问
|
||||
|
||||
obj = C()
|
||||
|
||||
obj.foo # 通过对象访问
|
||||
obj.func() # 类内部访问
|
||||
|
||||
obj_son = D();
|
||||
obj_son.show() # 派生类中访问
|
||||
```
|
||||
|
||||
```python
|
||||
class C:
|
||||
|
||||
def __init__(self):
|
||||
self.__foo = "私有字段"
|
||||
|
||||
def func(self):
|
||||
print self.foo # 类内部访问
|
||||
|
||||
class D(C):
|
||||
|
||||
def show(self):
|
||||
print self.foo # 派生类中访问
|
||||
|
||||
obj = C()
|
||||
|
||||
obj.__foo # 通过对象访问 ==> 错误
|
||||
obj.func() # 类内部访问 ==> 正确
|
||||
|
||||
obj_son = D();
|
||||
obj_son.show() # 派生类中访问 ==> 错误
|
||||
```
|
||||
|
||||
```python
|
||||
class C:
|
||||
|
||||
def __init__(self):
|
||||
self.__foo = "私有字段"
|
||||
|
||||
def func(self):
|
||||
print(self.__foo) # 类内部访问
|
||||
|
||||
class D(C):
|
||||
|
||||
def show(self):
|
||||
print(self.__foo) # 派生类中访问
|
||||
|
||||
obj = C()
|
||||
|
||||
print(obj.__foo) # 通过对象访问 ==> 错误
|
||||
obj.func() # 类内部访问 ==> 正确
|
||||
|
||||
obj_son = D()
|
||||
obj_son.show() # 派生类中访问 ==> 错误
|
||||
```
|
||||
|
||||
方法:
|
||||
|
||||
公有方法:对象可以访问;类内部可以访问;派生类中可以访问
|
||||
私有方法:仅类内部可以访问;
|
||||
|
||||
```python
|
||||
class C:
|
||||
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def add(self):
|
||||
print('in C')
|
||||
|
||||
|
||||
class D(C):
|
||||
|
||||
def show(self):
|
||||
print('in D')
|
||||
|
||||
def func(self):
|
||||
self.show()
|
||||
|
||||
|
||||
obj = D()
|
||||
obj.show() # 通过对象访问
|
||||
obj.func() # 类内部访问
|
||||
obj.add() # 派生类中访问
|
||||
```
|
||||
|
||||
```python
|
||||
class C:
|
||||
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def __add(self):
|
||||
print('in C')
|
||||
|
||||
class D(C):
|
||||
|
||||
def __show(self):
|
||||
print('in D')
|
||||
|
||||
def func(self):
|
||||
self.__show()
|
||||
obj = D()
|
||||
obj.__show() # 通过不能对象访问
|
||||
obj.func() # 类内部可以访问
|
||||
obj.__add() # 派生类中不能访问
|
||||
```
|
||||
|
||||
总结:
|
||||
|
||||
对于这些私有成员来说,他们只能在类的内部使用,不能再类的外部以及派生类中使用.
|
||||
|
||||
**ps:非要访问私有成员的话,可以通过 对象._类__属性名,但是绝对不允许!!!**
|
||||
|
||||
为什么可以通过._类__私有成员名访问呢?因为类在创建时,如果遇到了私有成员(包括私有静态字段,私有普通字段,私有方法)它会将其保存在内存时自动在前面加上_类名.
|
||||
|
||||
## 类的其他成员
|
||||
|
||||
这里的其他成员主要就是类方法:
|
||||
|
||||
方法包括:普通方法、静态方法和类方法,三种方法在**内存中都归属于类**,区别在于调用方式不同。
|
||||
|
||||
**实例方法**
|
||||
|
||||
定义:第一个参数必须是实例对象,该参数名一般约定为“self”,通过它来传递实例的属性和方法(也可以传类的属性和方法);
|
||||
|
||||
调用:只能由实例对象调用。
|
||||
|
||||
**类方法**
|
||||
|
||||
定义:使用装饰器@classmethod。第一个参数必须是当前类对象,该参数名一般约定为“cls”,通过它来传递类的属性和方法(不能传实例的属性和方法);
|
||||
|
||||
调用:实例对象和类对象都可以调用。
|
||||
|
||||
**静态方法**
|
||||
|
||||
定义:使用装饰器@staticmethod。参数随意,没有“self”和“cls”参数,但是方法体中不能使用类或实例的任何属性和方法;
|
||||
|
||||
调用:实例对象和类对象都可以调用。
|
||||
|
||||
**双下方法(后面会讲到)**
|
||||
|
||||
定义:双下方法是特殊方法,他是解释器提供的 由爽下划线加方法名加爽下划线 __方法名__的具有特殊意义的方法,双下方法主要是python源码程序员使用的,
|
||||
|
||||
我们在开发中尽量不要使用双下方法,但是深入研究双下方法,更有益于我们阅读源码。
|
||||
|
||||
调用:不同的双下方法有不同的触发方式,就好比盗墓时触发的机关一样,不知不觉就触发了双下方法,例如:__init__
|
||||
|
||||
### 类方法
|
||||
|
||||
使用装饰器@classmethod。
|
||||
|
||||
原则上,类方法是将类本身作为对象进行操作的方法。假设有个方法,且这个方法在逻辑上采用类本身作为对象来调用更合理,那么这个方法就可以定义为类方法。另外,如果需要继承,也可以定义为类方法。
|
||||
|
||||
如下场景:
|
||||
|
||||
假设我有一个学生类和一个班级类,想要实现的功能为:
|
||||
执行班级人数增加的操作、获得班级的总人数;
|
||||
学生类继承自班级类,每实例化一个学生,班级人数都能增加;
|
||||
最后,我想定义一些学生,获得班级中的总人数。
|
||||
|
||||
**思考**:这个问题用类方法做比较合适,为什么?因为我实例化的是学生,但是如果我从学生这一个实例中获得班级总人数,在逻辑上显然是不合理的。同时,如果想要获得班级总人数,如果生成一个班级的实例也是没有必要的。
|
||||
|
||||
```python
|
||||
class Student:
|
||||
__num = 0
|
||||
|
||||
def __init__(self, name, age):
|
||||
self.name = name
|
||||
self.age = age
|
||||
Student.addNum() # 写在__new__方法中比较合适,但是现在还没有学,暂且放到这里
|
||||
|
||||
@classmethod
|
||||
def addNum(cls):
|
||||
cls.__num += 1
|
||||
|
||||
@classmethod
|
||||
def getNum(cls):
|
||||
return cls.__num
|
||||
|
||||
|
||||
Student('陈松', 18)
|
||||
Student('阿松', 36)
|
||||
Student('松松', 73)
|
||||
print(Student.getNum())
|
||||
```
|
||||
|
||||
### 静态方法
|
||||
|
||||
使用装饰器@staticmethod。
|
||||
|
||||
静态方法是类中的函数,不需要实例。静态方法主要是用来存放逻辑性的代码,逻辑上属于类,但是和类本身没有关系,也就是说在静态方法中,不会涉及到类中的属性和方法的操作。可以理解为,静态方法是个**独立的、单纯的**函数,它仅仅托管于某个类的名称空间中,便于使用和维护。
|
||||
|
||||
譬如,我想定义一个关于时间操作的类,其中有一个获取当前时间的函数。
|
||||
|
||||
```python
|
||||
import time
|
||||
|
||||
class TimeTest(object):
|
||||
def __init__(self, hour, minute, second):
|
||||
self.hour = hour
|
||||
self.minute = minute
|
||||
self.second = second
|
||||
|
||||
@staticmethod
|
||||
def showTime():
|
||||
return time.strftime("%H:%M:%S", time.localtime())
|
||||
|
||||
|
||||
print(TimeTest.showTime())
|
||||
t = TimeTest(2, 10, 10)
|
||||
nowTime = t.showTime()
|
||||
print(nowTime)
|
||||
```
|
||||
|
||||
### 属性
|
||||
|
||||
property是一种特殊的属性,访问它时会执行一段功能(函数)然后返回值
|
||||
|
||||
例一:BMI指数(bmi是计算而来的,但很明显它听起来像是一个属性而非方法,如果我们将其做成一个属性,更便于理解)
|
||||
|
||||
成人的BMI数值:
|
||||
过轻:低于18.5
|
||||
正常:18.5-23.9
|
||||
过重:24-27
|
||||
肥胖:28-32
|
||||
非常肥胖, 高于32
|
||||
体质指数(BMI)=体重(kg)÷身高^2(m)
|
||||
EX:70kg÷(1.75×1.75)=22.86
|
||||
|
||||
```python
|
||||
class People:
|
||||
def __init__(self,name,weight,height):
|
||||
self.name=name
|
||||
self.weight=weight
|
||||
self.height=height
|
||||
@property
|
||||
def bmi(self):
|
||||
return self.weight / (self.height**2)
|
||||
|
||||
p1=People('陈松',75,1.85)
|
||||
print(p1.bmi)
|
||||
```
|
||||
|
||||
将一个类的函数定义成特性以后,对象再去使用的时候obj.name,根本无法察觉自己的name是执行了一个函数然后计算出来的,这种特性的使用方式遵循了**统一访问的原则**
|
||||
|
||||
由于新式类中具有三种访问方式,我们可以根据他们几个属性的访问特点,分别将三个方法定义为对同一个属性:获取、修改、删除
|
||||
|
||||
```python
|
||||
class Foo:
|
||||
@property
|
||||
def AAA(self):
|
||||
print('get的时候运行我啊')
|
||||
|
||||
@AAA.setter
|
||||
def AAA(self,value):
|
||||
print('set的时候运行我啊')
|
||||
|
||||
@AAA.deleter
|
||||
def AAA(self):
|
||||
print('delete的时候运行我啊')
|
||||
|
||||
#只有在属性AAA定义property后才能定义AAA.setter,AAA.deleter
|
||||
f1=Foo()
|
||||
f1.AAA
|
||||
f1.AAA='aaa'
|
||||
del f1.AAA
|
||||
```
|
||||
|
||||
或者
|
||||
|
||||
```python
|
||||
class Foo:
|
||||
def get_AAA(self):
|
||||
print('get的时候运行我啊')
|
||||
|
||||
def set_AAA(self,value):
|
||||
print('set的时候运行我啊')
|
||||
|
||||
def delete_AAA(self):
|
||||
print('delete的时候运行我啊')
|
||||
AAA=property(get_AAA,set_AAA,delete_AAA) #内置property三个参数与get,set,delete一一对应
|
||||
|
||||
f1=Foo()
|
||||
f1.AAA
|
||||
f1.AAA='aaa'
|
||||
del f1.AAA
|
||||
```
|
||||
|
||||
商品的例子
|
||||
|
||||
```python
|
||||
class Goods(object):
|
||||
|
||||
def __init__(self):
|
||||
# 原价
|
||||
self.original_price = 100
|
||||
# 折扣
|
||||
self.discount = 0.8
|
||||
|
||||
@property
|
||||
def price(self):
|
||||
# 实际价格 = 原价 * 折扣
|
||||
new_price = self.original_price * self.discount
|
||||
return new_price
|
||||
|
||||
@price.setter
|
||||
def price(self, value):
|
||||
self.original_price = value
|
||||
|
||||
@price.deleter
|
||||
def price(self):
|
||||
del self.original_price
|
||||
|
||||
obj = Goods()
|
||||
print(obj.price) # 获取商品价格
|
||||
obj.price = 200 # 修改商品原价
|
||||
print(obj.price)
|
||||
del obj.price # 删除商品原价
|
||||
```
|
||||
|
||||
## isinstace 与 issubclass
|
||||
|
||||
isinstance(a,b):判断a是否是b类(或者b类的派生类)实例化的对象
|
||||
|
||||
```python
|
||||
class A:
|
||||
pass
|
||||
|
||||
class B(A):
|
||||
pass
|
||||
|
||||
obj = B()
|
||||
|
||||
print(isinstance(obj,B))
|
||||
print(isinstance(obj,A))
|
||||
```
|
||||
|
||||
issubclass(a,b): 判断a类是否是b类(或者b的派生类)的派生类
|
||||
|
||||
```python
|
||||
class A:
|
||||
pass
|
||||
|
||||
class B(A):
|
||||
pass
|
||||
|
||||
class C(B):
|
||||
pass
|
||||
|
||||
print(issubclass(B,A))
|
||||
print(issubclass(C,A))
|
||||
```
|
||||
|
||||
思考:那么 list str tuple dict等这些类与 Iterble类 的关系是什么?
|
||||
|
||||
```python
|
||||
from collections import Iterable
|
||||
|
||||
print(isinstance([1,2,3], list)) # True
|
||||
print(isinstance([1,2,3], Iterable)) # True
|
||||
print(issubclass(list,Iterable)) # True
|
||||
|
||||
# 由上面的例子可得,这些可迭代的数据类型,list str tuple dict等 都是 Iterable的子类。
|
||||
```
|
639
02.面向对象/06.反射与双下方法.md
Normal file
639
02.面向对象/06.反射与双下方法.md
Normal file
@@ -0,0 +1,639 @@
|
||||
# 反射与双下方法
|
||||
|
||||
## 反射
|
||||
|
||||
python面向对象中的反射:通过字符串的形式操作对象相关的属性。python中的一切事物都是对象(都可以使用反射)
|
||||
|
||||
四个可以实现自省的函数
|
||||
|
||||
下列方法适用于类和对象(一切皆对象,类本身也是一个对象)
|
||||
|
||||
**对对象的反射**
|
||||
|
||||
```python
|
||||
class Foo:
|
||||
f = '类的静态变量'
|
||||
def __init__(self,name,age):
|
||||
self.name=name
|
||||
self.age=age
|
||||
|
||||
def say_hi(self):
|
||||
print('hi,%s'%self.name)
|
||||
|
||||
obj=Foo('陈松',73)
|
||||
|
||||
# 检测是否含有某属性
|
||||
print(hasattr(obj,'name'))
|
||||
print(hasattr(obj,'say_hi'))
|
||||
|
||||
# 获取属性
|
||||
n=getattr(obj,'name')
|
||||
print(n)
|
||||
func=getattr(obj,'say_hi')
|
||||
func()
|
||||
|
||||
print(getattr(obj,'aaaaaaaa','不存在啊')) # 报错
|
||||
|
||||
# 设置属性
|
||||
setattr(obj,'sb',True)
|
||||
setattr(obj,'show_name',lambda self:self.name+'sb')
|
||||
print(obj.__dict__)
|
||||
print(obj.show_name(obj))
|
||||
|
||||
# 删除属性
|
||||
delattr(obj,'age')
|
||||
delattr(obj,'show_name')
|
||||
# delattr(obj,'show_name111') # 不存在,则报错
|
||||
|
||||
print(obj.__dict__)
|
||||
```
|
||||
|
||||
**对类的反射**
|
||||
|
||||
```python
|
||||
class Foo(object):
|
||||
staticField = "test"
|
||||
|
||||
def __init__(self):
|
||||
self.name = '陈松'
|
||||
|
||||
def func(self):
|
||||
return 'func'
|
||||
|
||||
@staticmethod
|
||||
def bar():
|
||||
return 'bar'
|
||||
|
||||
|
||||
print(getattr(Foo, 'staticField'))
|
||||
print(getattr(Foo, 'func'))
|
||||
print(getattr(Foo, 'bar'))
|
||||
```
|
||||
|
||||
当前模块的反射
|
||||
|
||||
```python
|
||||
import sys
|
||||
|
||||
def s1():
|
||||
print('s1')
|
||||
|
||||
def s2():
|
||||
print('s2')
|
||||
|
||||
this_module = sys.modules[__name__]
|
||||
|
||||
print(hasattr(this_module, 's1'))
|
||||
print(getattr(this_module, 's2'))
|
||||
```
|
||||
|
||||
其他模块的反射
|
||||
|
||||
程序目录:
|
||||
module_test.py
|
||||
test.py
|
||||
|
||||
当前文件:
|
||||
test.py
|
||||
|
||||
```python
|
||||
import module_test as obj
|
||||
|
||||
obj.test()
|
||||
|
||||
print(hasattr(obj,'test'))
|
||||
|
||||
getattr(obj,'test')()
|
||||
```
|
||||
|
||||
举例:
|
||||
|
||||
使用反射前
|
||||
|
||||
```python
|
||||
class User:
|
||||
def login(self):
|
||||
print('欢迎来到登录页面')
|
||||
|
||||
def register(self):
|
||||
print('欢迎来到注册页面')
|
||||
|
||||
def save(self):
|
||||
print('欢迎来到存储页面')
|
||||
|
||||
|
||||
while 1:
|
||||
choose = input('>>>').strip()
|
||||
if choose == 'login':
|
||||
obj = User()
|
||||
obj.login()
|
||||
|
||||
elif choose == 'register':
|
||||
obj = User()
|
||||
obj.register()
|
||||
|
||||
elif choose == 'save':
|
||||
obj = User()
|
||||
obj.save()
|
||||
```
|
||||
|
||||
用了反射之后
|
||||
|
||||
```python
|
||||
class User:
|
||||
def login(self):
|
||||
print('欢迎来到登录页面')
|
||||
|
||||
def register(self):
|
||||
print('欢迎来到注册页面')
|
||||
|
||||
def save(self):
|
||||
print('欢迎来到存储页面')
|
||||
|
||||
|
||||
user = User()
|
||||
while 1:
|
||||
choose = input('>>>').strip()
|
||||
if hasattr(user, choose):
|
||||
func = getattr(user, choose)
|
||||
func()
|
||||
else:
|
||||
print('输入错误。。。。')
|
||||
```
|
||||
|
||||
## 函数 vs 方法
|
||||
|
||||
### 通过打印函数(方法)名确定
|
||||
|
||||
```python
|
||||
def func():
|
||||
pass
|
||||
|
||||
print(func)
|
||||
|
||||
class A:
|
||||
def func(self):
|
||||
pass
|
||||
|
||||
print(A.func)
|
||||
obj = A()
|
||||
print(obj.func)
|
||||
```
|
||||
|
||||
### 通过types模块验证
|
||||
|
||||
```python
|
||||
from types import FunctionType
|
||||
from types import MethodType
|
||||
|
||||
def func():
|
||||
pass
|
||||
|
||||
class A:
|
||||
def func(self):
|
||||
pass
|
||||
|
||||
obj = A()
|
||||
|
||||
print(isinstance(func,FunctionType))
|
||||
print(isinstance(A.func,FunctionType))
|
||||
print(isinstance(obj.func,FunctionType))
|
||||
print(isinstance(obj.func,MethodType))
|
||||
```
|
||||
|
||||
### 静态方法是函数
|
||||
|
||||
```python
|
||||
from types import FunctionType
|
||||
from types import MethodType
|
||||
|
||||
|
||||
class A:
|
||||
|
||||
def func(self):
|
||||
pass
|
||||
|
||||
@classmethod
|
||||
def func1(self):
|
||||
pass
|
||||
|
||||
@staticmethod
|
||||
def func2(self):
|
||||
pass
|
||||
|
||||
|
||||
obj = A()
|
||||
|
||||
# 静态方法其实是函数
|
||||
print(isinstance(A.func2,FunctionType))
|
||||
print(isinstance(obj.func2,FunctionType))
|
||||
```
|
||||
|
||||
### 函数与方法的区别
|
||||
|
||||
那么,函数和方法除了上述的不同之处,我们还总结了一下几点区别。
|
||||
|
||||
1. 函数的是显式传递数据的。如我们要指明为len()函数传递一些要处理数据。
|
||||
|
||||
2. 函数则跟对象无关。
|
||||
|
||||
3. 方法中的数据则是隐式传递的。
|
||||
|
||||
4. 方法可以操作类内部的数据。
|
||||
|
||||
5. 方法跟对象是关联的。如我们在用strip()方法是,是不是都是要通过str对象调用,比如我们有字符串s,然后s.strip()这样调用。是的,strip()方法属于str对象。
|
||||
|
||||
我们或许在日常中会口语化称呼函数和方法时不严谨,但是我们心中要知道二者之间的区别。
|
||||
|
||||
在其他语言中,如Java中只有方法,C中只有函数,C++么,则取决于是否在类中
|
||||
|
||||
## 双下方法
|
||||
|
||||
### `__len__`
|
||||
|
||||
```python
|
||||
class B:
|
||||
def __len__(self):
|
||||
return 666
|
||||
|
||||
b = B()
|
||||
print(len(b)) # len 一个对象就会触发 __len__方法。
|
||||
|
||||
class A:
|
||||
def __init__(self):
|
||||
self.a = 1
|
||||
self.b = 2
|
||||
|
||||
def __len__(self):
|
||||
return len(self.__dict__)
|
||||
a = A()
|
||||
print(len(a))
|
||||
```
|
||||
|
||||
### `__hash__`
|
||||
|
||||
```python
|
||||
class A:
|
||||
def __init__(self):
|
||||
self.a = 1
|
||||
self.b = 2
|
||||
|
||||
def __hash__(self):
|
||||
return hash(str(self.a)+str(self.b))
|
||||
a = A()
|
||||
print(hash(a))
|
||||
```
|
||||
|
||||
### `__str__`
|
||||
|
||||
如果一个类中定义了__str__方法,那么在打印 对象 时,默认输出该方法的返回值。
|
||||
|
||||
```python
|
||||
class A:
|
||||
def __init__(self):
|
||||
pass
|
||||
def __str__(self):
|
||||
return '陈松'
|
||||
a = A()
|
||||
print(a)
|
||||
print('%s' % a)
|
||||
```
|
||||
|
||||
### `__repr__`
|
||||
|
||||
如果一个类中定义了__repr__方法,那么在repr(对象) 时,默认输出该方法的返回值。
|
||||
|
||||
```python
|
||||
class A:
|
||||
def __init__(self):
|
||||
pass
|
||||
def __repr__(self):
|
||||
return '陈松'
|
||||
a = A()
|
||||
print(repr(a))
|
||||
print('%r'%a)
|
||||
```
|
||||
|
||||
### `__call__`
|
||||
|
||||
对象后面加括号,触发执行。
|
||||
|
||||
注:构造方法__new__的执行是由创建对象触发的,即:对象 = 类名() ;而对于 __call__ 方法的执行是由对象后加括号触发的,即:对象() 或者 类()()
|
||||
|
||||
```python
|
||||
class Foo:
|
||||
|
||||
def __init__(self):
|
||||
print('__init__')
|
||||
|
||||
def __call__(self, *args, **kwargs):
|
||||
print('__call__')
|
||||
|
||||
|
||||
obj = Foo() # 执行 __init__
|
||||
obj() # 执行 __call__
|
||||
```
|
||||
|
||||
### `__eq__`
|
||||
|
||||
```python
|
||||
class A:
|
||||
def __init__(self):
|
||||
self.a = 1
|
||||
self.b = 2
|
||||
|
||||
def __eq__(self,obj):
|
||||
if self.a == obj.a and self.b == obj.b:
|
||||
return True
|
||||
a = A()
|
||||
b = A()
|
||||
print(a == b)
|
||||
```
|
||||
|
||||
### `__del__`
|
||||
|
||||
析构方法,当对象在内存中被释放时,自动触发执行。
|
||||
|
||||
注:此方法一般无须定义,因为Python是一门高级语言,程序员在使用时无需关心内存的分配和释放,因为此工作都是交给Python解释器来执行,所以,析构函数的调用是由解释器在进行垃圾回收时自动触发执行的。
|
||||
|
||||
### `__new__`
|
||||
|
||||
- `__new__()` 方法是在类准备将自身实例化时调用。
|
||||
- `__new__()` 方法始终都是类的静态方法,即使没有被加上静态方法装饰器。
|
||||
- 通常来说,新式类开始实例化时,`__new__()`方法会返回cls(cls指代当前类)的实例,然后该类的`__init__()`方法作为构造方法会接收这个实例(即self)作为自己的第一个参数,然后依次传入`__new__()`方法中接收的位置参数和命名参数。
|
||||
|
||||
```python
|
||||
class A:
|
||||
def __init__(self):
|
||||
self.x = 1
|
||||
print('in init function')
|
||||
def __new__(cls, *args, **kwargs):
|
||||
print('in new function')
|
||||
return object.__new__(A, *args, **kwargs)
|
||||
|
||||
a = A()
|
||||
print(a.x)
|
||||
```
|
||||
|
||||
单例模式
|
||||
|
||||
```python
|
||||
class A:
|
||||
__instance = None
|
||||
def __new__(cls, *args, **kwargs):
|
||||
if cls.__instance is None:
|
||||
obj = object.__new__(cls)
|
||||
cls.__instance = obj
|
||||
return cls.__instance
|
||||
```
|
||||
|
||||
单例模式是一种常用的软件设计模式。在它的核心结构中只包含一个被称为单例类的特殊类。通过单例模式可以保证系统中一个类只有一个实例而且该实例易于外界访问,从而方便对实例个数的控制并节约系统资源。如果希望在系统中某个类的对象只能存在一个,单例模式是最好的解决方案。
|
||||
**【采用单例模式动机、原因】**
|
||||
对于系统中的某些类来说,只有一个实例很重要,例如,一个系统中可以存在多个打印任务,但是只能有一个正在工作的任务;一个系统只能有一个窗口管理器或文件系统;一个系统只能有一个计时工具或ID(序号)生成器。如在Windows中就只能打开一个任务管理器。如果不使用机制对窗口对象进行唯一化,将弹出多个窗口,如果这些窗口显示的内容完全一致,则是重复对象,浪费内存资源;如果这些窗口显示的内容不一致,则意味着在某一瞬间系统有多个状态,与实际不符,也会给用户带来误解,不知道哪一个才是真实的状态。因此有时确保系统中某个对象的唯一性即一个类只能有一个实例非常重要。
|
||||
如何保证一个类只有一个实例并且这个实例易于被访问呢?定义一个全局变量可以确保对象随时都可以被访问,但不能防止我们实例化多个对象。一个更好的解决办法是让类自身负责保存它的唯一实例。这个类可以保证没有其他实例被创建,并且它可以提供一个访问该实例的方法。这就是单例模式的模式动机。
|
||||
**【单例模式优缺点】**
|
||||
**【优点】**
|
||||
一、实例控制
|
||||
单例模式会阻止其他对象实例化其自己的单例对象的副本,从而确保所有对象都访问唯一实例。
|
||||
二、灵活性
|
||||
因为类控制了实例化过程,所以类可以灵活更改实例化过程。
|
||||
**【缺点】**
|
||||
一、开销
|
||||
虽然数量很少,但如果每次对象请求引用时都要检查是否存在类的实例,将仍然需要一些开销。可以通过使用静态初始化解决此问题。
|
||||
二、可能的开发混淆
|
||||
使用单例对象(尤其在类库中定义的对象)时,开发人员必须记住自己不能使用new关键字实例化对象。因为可能无法访问库源代码,因此应用程序开发人员可能会意外发现自己无法直接实例化此类。
|
||||
三、对象生存期
|
||||
不能解决删除单个对象的问题。在提供内存管理的语言中(例如基于.NET Framework的语言),只有单例类能够导致实例被取消分配,因为它包含对该实例的私有引用。在某些语言中(如 C++),其他类可以删除对象实例,但这样会导致单例类中出现悬浮引用
|
||||
|
||||
### `__item__`系列
|
||||
|
||||
```python
|
||||
class Foo:
|
||||
def __init__(self,name):
|
||||
self.name=name
|
||||
|
||||
def __getitem__(self, item):
|
||||
print(self.__dict__[item])
|
||||
|
||||
def __setitem__(self, key, value):
|
||||
self.__dict__[key]=value
|
||||
print('赋值成功')
|
||||
|
||||
def __delitem__(self, key):
|
||||
print('del obj[key]时,我执行')
|
||||
self.__dict__.pop(key)
|
||||
|
||||
def __delattr__(self, item):
|
||||
print('del obj.key时,我执行')
|
||||
self.__dict__.pop(item)
|
||||
|
||||
f1=Foo('sb')
|
||||
f1['age']=18
|
||||
f1['age1']=19
|
||||
del f1.age1
|
||||
del f1['age']
|
||||
f1['name']='mingzi'
|
||||
print(f1.__dict__)
|
||||
```
|
||||
|
||||
### 上下文管理器相关
|
||||
|
||||
`__enter__` `__exit__`
|
||||
|
||||
```python
|
||||
class A:
|
||||
|
||||
def __init__(self, text):
|
||||
self.text = text
|
||||
|
||||
def __enter__(self): # 开启上下文管理器对象时触发此方法
|
||||
self.text = self.text + '您来啦'
|
||||
return self # 将实例化的对象返回f1
|
||||
|
||||
def __exit__(self, exc_type, exc_val, exc_tb): # 执行完上下文管理器对象f1时触发此方法
|
||||
self.text = self.text + '这就走啦'
|
||||
|
||||
|
||||
with A('大爷') as f1:
|
||||
print(f1.text)
|
||||
print(f1.text)
|
||||
```
|
||||
|
||||
自定义文件管理器
|
||||
|
||||
```python
|
||||
class Diycontextor:
|
||||
def __init__(self, name, mode):
|
||||
self.name = name
|
||||
self.mode = mode
|
||||
|
||||
def __enter__(self):
|
||||
print("Hi enter here!!")
|
||||
self.filehander = open(self.name, self.mode)
|
||||
return self.filehander
|
||||
|
||||
def __exit__(self,*args):
|
||||
print("Hi exit here")
|
||||
self.filehander.close()
|
||||
|
||||
|
||||
with Diycontextor('config', 'r') as f:
|
||||
for i in f:
|
||||
print(i.strip())
|
||||
```
|
||||
|
||||
案例
|
||||
|
||||
```python
|
||||
class StarkConfig:
|
||||
def __init__(self, num):
|
||||
self.num = num
|
||||
|
||||
def run(self):
|
||||
self()
|
||||
|
||||
def __call__(self, *args, **kwargs):
|
||||
print(self.num)
|
||||
|
||||
|
||||
class RoleConfig(StarkConfig):
|
||||
def __call__(self, *args, **kwargs):
|
||||
print(345)
|
||||
|
||||
def __getitem__(self, item):
|
||||
return self.num[item]
|
||||
|
||||
|
||||
v1 = RoleConfig('abcedf')
|
||||
v2 = StarkConfig('2333')
|
||||
print(v1[3])
|
||||
## print(v2[2])
|
||||
v1.run()
|
||||
```
|
||||
|
||||
```python
|
||||
class UserInfo:
|
||||
pass
|
||||
|
||||
|
||||
class Department:
|
||||
pass
|
||||
|
||||
|
||||
class StarkConfig:
|
||||
def __init__(self, num):
|
||||
self.num = num
|
||||
|
||||
def changelist(self, request):
|
||||
print(self.num, request)
|
||||
|
||||
def run(self):
|
||||
self.changelist(999)
|
||||
|
||||
|
||||
class RoleConfig(StarkConfig):
|
||||
def changelist(self, request):
|
||||
print(666, self.num)
|
||||
|
||||
|
||||
class AdminSite:
|
||||
|
||||
def __init__(self):
|
||||
self._registry = {}
|
||||
|
||||
def register(self, k, v):
|
||||
self._registry[k] = v
|
||||
|
||||
|
||||
site = AdminSite()
|
||||
site.register(UserInfo, StarkConfig)
|
||||
# 1
|
||||
obj = site._registry[UserInfo]()
|
||||
|
||||
# 2
|
||||
# obj = site._registry[UserInfo](100)
|
||||
obj.run()
|
||||
```
|
||||
|
||||
```python
|
||||
class UserInfo:
|
||||
pass
|
||||
|
||||
class Department:
|
||||
pass
|
||||
|
||||
class StarkConfig:
|
||||
def __init__(self,num):
|
||||
self.num = num
|
||||
|
||||
def changelist(self,request):
|
||||
print(self.num,request)
|
||||
|
||||
def run(self):
|
||||
self.changelist(999)
|
||||
|
||||
class RoleConfig(StarkConfig):
|
||||
def changelist(self,request):
|
||||
print(666,self.num)
|
||||
|
||||
|
||||
class AdminSite:
|
||||
|
||||
def __init__(self):
|
||||
self._registry = {}
|
||||
|
||||
def register(self,k,v):
|
||||
self._registry[k] = v(k)
|
||||
|
||||
site = AdminSite()
|
||||
site.register(UserInfo,StarkConfig)
|
||||
site.register(Department,RoleConfig)
|
||||
|
||||
for k,row in site._registry.items():
|
||||
row.run()
|
||||
```
|
||||
|
||||
```python
|
||||
class A:
|
||||
list_display = []
|
||||
|
||||
def get_list(self):
|
||||
self.list_display.insert(0, 33)
|
||||
return self.list_display
|
||||
|
||||
|
||||
s1 = A()
|
||||
print(s1.get_list())
|
||||
```
|
||||
|
||||
```python
|
||||
class A:
|
||||
list_display = [1, 2, 3]
|
||||
def __init__(self):
|
||||
self.list_display = []
|
||||
def get_list(self):
|
||||
self.list_display.insert(0, 33)
|
||||
return self.list_display
|
||||
|
||||
|
||||
s1 = A()
|
||||
print(s1.get_list())
|
||||
```
|
||||
|
||||
```python
|
||||
class A:
|
||||
list_display = []
|
||||
|
||||
def get_list(self):
|
||||
self.list_display.insert(0,33)
|
||||
return self.list_display
|
||||
|
||||
class B(A):
|
||||
list_display = [11,22]
|
||||
|
||||
|
||||
s1 = A()
|
||||
s2 = B()
|
||||
print(s1.get_list())
|
||||
print(s2.get_list())
|
||||
```
|
Reference in New Issue
Block a user