first commit

This commit is contained in:
2025-08-27 14:39:37 +08:00
commit 81ebee9cf3
97 changed files with 14191 additions and 0 deletions

View 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, 代表这个就是对象。*
**一个类可以实例化多个对象**

View 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血
```

View 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()
```
方法二利用supersuper().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
```
画图
![image-20210725220109579](03.%E7%B1%BB%E7%9A%84%E7%BB%A7%E6%89%BF/image-20210725220109579.png)
在经典类中采⽤的是深度优先,遍历⽅案. 什么是深度优先. 就是⼀条路走到头. 然后再回来. 继续找下⼀个.
类的MRO(method resolution order): Foo-> H -> G -> F -> E -> D -> B -> A -> C.
### 新式类的多继承
#### mro序列
MRO是一个有序列表L在类被创建时就计算出来。
通用计算公式为:
mro(Child(Base1Base2)) = [ 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操作 ......
---------------------
![image-20210725220122519](03.%E7%B1%BB%E7%9A%84%E7%BB%A7%E6%89%BF/image-20210725220122519.png)
计算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呢? 因为笔
试.......你在笔试的时候, 是没有电脑的. 所以这个算法要知道. 并且简单的计算要会. 正式项⽬
开发的时候很少有⼈这么去写代码.

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

View 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()
```

View 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÷身高^2m
  EX70kg÷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的子类。
```

View 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__()`方法会返回clscls指代当前类的实例然后该类的`__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())
```