day18回顾


类属性
class A:
v = 100
def fx(self):
pass
@classmethod
def fy(cls):
pass
@staticmethod
def fz():
pass
类方法
class A:
@classmethod
def fy(cls, ....):
...
A.fy()
a = A()
a.fy()

__slots__列表
限定此类创建的对象(实例)只能有固定的属性

静态方法 @staticmethod
class A:
@staticmethod
def fz():
pass
A.fz()
a = A()
a.fz()

继承/派生
class B(A):
pass

子类添加功能,添加新方法
子类修改功能,覆盖

单继承
语法:
class 子类名(父类名):
语句块
覆盖:
1. 继承/派生机制
2. 子类实现与父类同名的方法
3. 子类对象调用该方法

super函数:
super(类名, 对象).方法名()
super().方法名() # 只能在方法内部调用

父类名.方法名(对象, ....)

显式调用基类的 __init__ 方法
class A:
def __init__(self, x, y):
...
class B(A):
def __init__(self, ....):
super().__init__(100, 200)

issubclass(类, 类或元组)

新的一天day19 笔记:

封装 enclosure

封装是指隐藏类的实现细节,让使用者不关心这些细节
封装的目的是让使用者通过尽可能少的方法(或属性)操作对象

私有属性和私有方法:

python类中以双下划线(__) 开头,不以双下划线结尾的标识符为
私有成员,私有成员只能使用该类的方法进行调用和访问

示例见:
```python
class A:
def __init__(self, v):
self.__money = v # 私有属性
self.__aaa__ = 10000 # 此实例属性不是私有属性

def buy(self, obj, m):
self.__money -= m
print('买', obj, '花了', m, '元,剩余',
self.__money, '元')

a = A(1000)
a.buy('电纸书', 600)
print(a.__aaa__)
# print(a.__money) # 取值也会报错
# a.__money -= 10000
a.buy('耳机', 100)

```

多态 Polymorphic

字面意思: '多种状态'

状态:
静态(编译时状态,代码写完就固定下来的状态)
动态(运行时状态,在运行时确定的状态)
说明:
多态是指在有继承/派生关系的类中,调用基类对象的方法,实际
能调用子类的覆盖方法的现象叫多态
python 的全部对象都只有"运行时状态(动态)" 没有C++语言里
的编译时状态(静态)
示例见:
```class A:
def run(self):
print("A")

class B(A):
def run(self):
print('B')

class C(B):
def run(self):
print("C")

def test(obj):
obj.run() # 请问调用谁? # 此处体现出动态

a = A()
b = B()
c = C()

test(b)
test(c)```

面向对象编程语言的特征

  1. 继承
    可以很多容易去创建新类,新类继承旧类的功能
  2. 封装
    隐藏细节,提高软件的开发效率
  3. 多态
    把所有的同类或子类对象看成同一种对象进行统一的操作C++/C#/Java/Python …

多继承 multiple inheritance

多继承是指一个子类继承自两个或两个以上的基类

语法:
class 类名(基类名1, 基类名2, ...):
...
说明:
一个子类同时继承自多个父类,父类中的方法可以同时被继承下来
如果两个父类中有同名的方法,而在子类中又没有覆盖此方法时,
调用结果难以确定
示例见:
```
class Car:
def run(self, speed):
print("汽车以", speed, '公里/小时的速度行驶')

class Plane:
def fly(self, height):
print("飞机以海拔", height, '米的高度飞行')

class PlaneCar(Car, Plane):
'''PlaneCar为飞行汽车类'''

p1 = PlaneCar()
p1.fly(10000)
p1.run(300)
```

多继承的问题:

  1. 标识符冲突的问题,要谨慎使用多继承
示例见:
```
class A:
def m(self):
print("A.m被调用")

# 小李写了一个类B
class B:
def m(self):
print("B.m被调用")

# 小王感觉小张和小李写的两个类自己都可以用
# class AB(B, A):
class AB(A, B):
pass

ab = AB()
ab.m() # 请问调用谁?

多继承的MRO(Method Resolution Order) 问题

类的__mro__属性
每个类都有自己的__mro__属性,此属性绑定的元组记录了此
类创建的对象的方法的调用次序

钻石继承
A
/ \
B C
\ /
D
示例见:
class A:
def go(self):
print("A")

class B(A):
def go(self):
print("B")

class C(A):
def go(self):
print("C")

class D(B, C):
def go(self):
print('D')

for cls in D.__mro__:
print(cls)
# print("D.__mro__: ", D.__mro__)
d = D()
d.go() # ???

对象转字符串函数

repr(obj)  返回一个能代表obj这个对象的字符串,此字符串
必须是能表示obj内容且符合python语法的字符串
通常:
eval(repr(obj)) == obj
str(obj) 通过给定的对象返回一个对象字符串
注:
repr(obj) 返回的字符串通常是给python3解释执行器执行的
str(obj) 返回的字符串通常是给人来阅读的

示例:
s = "I'm a Student"
s1 = str(s)
print(s1) # I'm a Student
r1 = repr(s)
print(r1) # "I'm a Student"

对象转字符串函数的重写(覆盖)方法

repr函数的重写方法
def __repr__(self):
return 字符串
str函数的重写方法:
def __str__(self):
return 字符串

说明:
1. str(obj) 函数先查找obj.__str__() 方法,调用此方法
并返回结果
2. 如果obj.__str__方法不存在,则调用obj.__repr__()方法
并返回结果
3. 如果obj.__repr__方法不存在,则调用object类的__repr__
方法并返回<__main__.XXXX object at 0xXXXXXX> 格式
的字符串

示例见:
```
class MyNumber:
def __init__(self, v):
self.data = v

def __str__(self):
print("__str__方法被调用")
s = '数字:' + str(self.data)
return s

def __repr__(self):
'''此方法必须返回能让eval执行自字符串'''
s = 'MyNumber(%d)' % self.data
return s

n1 = MyNumber(100)
print("repr(n1)=", repr(n1))
print("str(n1) =", str(n1)) # 数字: 100
```

内建函数的重写

__abs__(self)      abs(obj) 函数调用
__len__(self) len(obj) 函数调用
__reversed__(self) reversed(obj) 函数调用
__round__(self) round(obj) 函数调用

示例见:
```
class MyList:
def __init__(self, iterable=()):
self.data = [x for x in iterable]

def __repr__(self):
s = 'MyList(%s)' % self.data
return s

def __len__(self):
'此方法必须返回整数'
return len(self.data)

myl = MyList([1, -2, 3, -4])
myl2 = MyList()
print(myl) # 内部会用str(myl) 转为字符串
print(myl2) #
print(len(myl)) #
print(len(myl2))
# myl3 = abs(myl)
# print("myl3=", myl3) # MyList([1, 2, 3, 4])
```

数值转换函数的重写

__complex__    complex(obj) 函数调用
__int__ int(obj) 函数调用
__float__ float(obj) 函数调用
__bool__ bool(obj) 函数调用

示例见:
class MyNumber:
def __init__(self, v):
self.data = v

def __float__(self):
'''此方法必须返回浮点数'''
return float(self.data)


n1 = MyNumber('100')
f1 = float(n1) # ???
print(f1) # 100.0
```

### 布尔测试函数重写
__bool__(self) ---> bool(obj)

作用:
用于bool(obj) 函数取值
用于if语句真值表达式中
用于while语句真值表达式中
说明:
当自定义类内有__bool__(self) 方法时会优先调用此方法
当不存在__bool__(self) 方法时bool(obj) 调用
obj.__len__() 返回值是否为非零来决定真假值
当再不存在__len__(self) 方法时,则直接返回True
示例见:
```
class MyList:
def __init__(self, iterable=()):
self.data = [x for x in iterable]

def __repr__(self):
s = 'MyList(%s)' % self.data
return s

# def __len__(self):
# '此方法必须返回整数'
# print("__len__被调用")
# return len(self.data)

# def __bool__(self):
# print("__bool__被调用")
# return len(self.data) != 0

myl1 = MyList([1, -2, 3, -4])
myl2 = MyList()
print(bool(myl1)) # True/False???
print(bool(myl2)) # ???

if myl1:
print("myl1为真值")
else:
print("myl1为假值")

# for x in myl1: # myl1 不是可迭代对象
# print(x)
```
### 小结:
只有以下几个函数可以有对应的方法进行重写
str(x), repr(x), int(x), bool(x), float(x)
complex(x), abs(x), len(x), reversed(x), round(x)

对象的属性管理函数:
getattr(obj, name[,default])
hasattr(obj, name)
setattr(obj, name, value)
delattr(obj, name)


### 迭代器(高级)
什么是迭代器
可以通过next函数取值的对象就是迭代器
迭代器协议:
迭代器协议是指对象能够使用next函数获取下一项数据,在没有
下一项数据时触发一个StopIteration异常来终止迭代的约定
迭代器协议的实现方法:
def __next__(self)

### 可迭代对象
是指能用iter(obj) 函数返回迭代器的对象
可迭代对象内部需要定义 __iter__(self) 方法来返回迭代器
对象

示例见:
```
class MyList:
def __init__(self, iterable=()):
self.data = [x for x in iterable]
def __repr__(self):
s = 'MyList(%s)' % self.data
return s
def __iter__(self):
'''此方法会将MyList对象作为可迭代对象,此方法
要求必须返回迭代器'''
myit = MyListIterator(self.data) # 创建迭代器
return myit

class MyListIterator:
'''此类的对象将作为迭代器来访问MyList类型的对象'''
def __init__(self, lst):
self.data = lst
self.cur_index = 0 # 用记录当前访问位置的索引
def __next__(self):
# 如果数据已经获取完毕,抛出StopIteration异常
if self.cur_index >= len(self.data):
raise StopIteration
r = self.data[self.cur_index]
self.cur_index += 1
return r
# return 999

myl1 = MyList([1, -2, 3, -4])
it = iter(myl1) # it = myl1.__iter__()
while True:
try:
x = next(it) # it.__next__()
print(x)
import time
time.sleep(1)
except StopIteration:
break
print('-------------------')
for x in myl1:
print(x) # 打印: 1 -2 3 -4
```