Python之路,第十九篇:Python入门与基础19
python3 面向对象3
数值转换函数重载:
str(obj) __str__
complex(x) __complex__
int(obj) __int__
float(obj) __float__
bool __bool__
1 class MyNumber: 2 def __init__(self,n): 3 self.data = n 4 5 def __float__(self): 6 print("__float__被调用。") 7 try: 8 x = float(self.data) 9 except: 10 x = 0.0 11 return x 12 13 14 n = MyNumber('100') 15 print(float(n)) #__float__被调用。 #100.0 16 17 print(float("100.0")) #100.0 18 print(float(True)) #1.0 19 20 n = MyNumber(1+2j) 21 print(float(n)) #__float__被调用。 #0.0
bool 测试运算符重载:
方法格式:def __bool__(self):
.......
作用:1, 用于if 语句的真值表达式中:
2, 用于while 语句的真值表达式中;
3,用于bool(obj) 函数取值;
说明:当没有__bool__ (self)方法时, 真值测试将以__len__(self)的方法的返回值来进行测试布尔值;
1 class MyList: 2 def __init__(self, count=0, value =0): 3 self.data = [] 4 for x in range(count): 5 self.data.append(value) 6 7 def __repr__(self): 8 return "MyList("+ repr(self.data) +")" 9 10 def __bool__(self): 11 print("__bool__被调用") 12 for x in self.data: 13 if x: 14 return True #如果遇到一个真值,直接返回true,不在执行下面的语句 15 return False 16 17 18 #myl = MyList(10) 19 #print(myl) #MyList([0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) #__bool__被调用 #MyList为假值 20 myl = MyList(10,1) 21 print(myl) 22 if myl: 23 print("MyList 为真值") 24 else: 25 print("MyList为假值") 26 #MyList([1, 1, 1, 1, 1, 1, 1, 1, 1, 1]) 27 #__bool__被调用 28 #MyList 为真值 29 #
1 class MyList: 2 def __init__(self, count=0, value =0): 3 self.data = [] 4 for x in range(count): 5 self.data.append(value) 6 7 def __repr__(self): 8 return "MyList("+ repr(self.data) +")" 9 10 def __len__(self): 11 return len(self.data) 12 #def __bool__(self): #如果有__len__存在,__bool__优先执行; 13 # print("__bool__被调用") 14 # for x in self.data: 15 # if x: 16 # return True #如果遇到一个真值,直接返回true,不在执行下面的语句 17 # return False 18 19 20 #myl = MyList(10) 21 #print(myl)#MyList([0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) 22 # MyList 为真值 23 myl = MyList(10,1) 24 print(myl) 25 if myl: 26 print("MyList 为真值") 27 else: 28 print("MyList为假值") 29 #MyList([1, 1, 1, 1, 1, 1, 1, 1, 1, 1]) 30 #MyList 为真值
in / not in 运算符重载:
重载方法:
def __contains__(self, e):
pass
1 class even: 2 "偶数类,用于显示偶数的有序列表" 3 def __init__(self, begin, end): 4 self.begin = begin 5 self.end = end #不包含end 6 7 def __contains__(self, e): 8 print("__contains__被调用") 9 if e < self.begin: 10 return False 11 12 if e >= self.end: 13 return False 14 15 if e % 2 == 0: 16 return True 17 18 return False 19 20 e1 = even(1, 10) 21 if 4 in e1: 22 print("4 在e1中") 23 24 if 3 in e1: 25 print("3 在e1中") 26 else: 27 print("3 不在e1中") 28 29 if 30 not in even(10, 20): 30 print("30不在even(10, 20)中") 31 32 #__contains__被调用 33 #4 在e1中 34 #__contains__被调用 35 #3 不在e1中 36 #__contains__被调用 37 #30不在even(10, 20)中
练习1:定义一个素数的类;
1 class Primes: 2 def __init__(self, end): 3 """end 用于表示素数的终止点,素数的起点是2包含2""" 4 self.end = end 5 6 def __contains__(self, element): 7 def isprime(x): 8 for i in range(2, x): 9 if x % 2 == 0: 10 return False 11 return True 12 if element < 2: 13 return False 14 if element >= self.end: 15 return False 16 return isprime(element) 17 18 19 p1 = Primes(100) 20 if 50 in p1: 21 print("50是素数") 22 else: 23 print("50不是素数"
1 def isprime(x): 2 for i in range(2, x): 3 if x % 2 == 0: 4 return False 5 return True 6 class Primes: 7 def __init__(self, end): 8 """end 用于表示素数的终止点,素数的起点是2包含2""" 9 self.end = end 10 11 def __contains__(self, element): 12 #def isprime(x): 13 # for i in range(2, x): 14 # if x % 2 == 0: 15 # return False 16 # return True 17 18 if element < 2: 19 return False 20 if element >= self.end: 21 return False 22 return isprime(element) 23 24 25 p1 = Primes(100) 26 if 50 in p1: 27 print("50是素数") 28 else: 29 print("50不是素数")
1 class Primes: 2 def __init__(self, end): 3 """end 用于表示素数的终止点,素数的起点是2包含2""" 4 self.end = end 5 6 @staticmethod 7 def isprime(x): 8 for i in range(2, x): 9 if x % 2 == 0: 10 return False 11 return True 12 13 def __contains__(self, element): 14 #def isprime(x): 15 # for i in range(2, x): 16 # if x % 2 == 0: 17 # return False 18 # return True 19 20 if element < 2: 21 return False 22 if element >= self.end: 23 return False 24 return self.isprime(element) 25 26 27 p1 = Primes(100) 28 if 50 in p1: 29 print("50是素数") 30 else: 31 print("50不是素数")
索引和切片运算符的重载:
__getitem__(self, i) # 索引/切片获取值
__getitem__(self, i , value) #设置索引或切片的值;
__delitem__(self, i) #进行删除索引操作
作用:让自定义的对象能进行索引和切片操作;
1 class MyList: 2 def __init__(self, count=0, value=0): 3 self.data = [] 4 for x in range(count): 5 self.data.append(value) 6 7 def __repr__(self): 8 return "MyList("+ repr(self.data) +")" 9 10 def setValueAt(self,index, value): 11 self.data[index] = value 12 #return self 13 14 myl = MyList(5, 1) 15 print(myl) #MyList([1, 1, 1, 1, 1]) 16 #myl[1] = 2 17 #print(myl.setValueAt(1, 2)) #return self 18 myl.setValueAt(1, 2) 19 print(myl) 20 =========================== 21 class MyList: 22 def __init__(self, count=0, value=0): 23 self.data = [] 24 for x in range(count): 25 self.data.append(value) 26 27 def __repr__(self): 28 return "MyList("+ repr(self.data) +")" 29 30 #def setValueAt(self,index, value): 31 # self.data[index] = value 32 # #return self 33 def __setitem__(self, index, value): 34 self.data[index] = value 35 36 37 myl = MyList(5, 1) 38 print(myl) #MyList([1, 1, 1, 1, 1]) 39 40 myl[1] = 2 41 print(myl) #MyList([1, 2, 1, 1, 1])
1 class MyList: 2 def __init__(self, count=0, value=0): 3 self.data = [] 4 for x in range(count): 5 self.data.append(value) 6 7 def __repr__(self): 8 return "MyList("+ repr(self.data) +")" 9 10 def __setitem__(self, index, value): 11 self.data[index] = value 12 13 def __getitem__(self, index): 14 print("__getitem__被调用") 15 return self.data[index] 16 17 myl = MyList(5, 1) 18 print(myl) #MyList([1, 1, 1, 1, 1]) 19 20 myl[1] = 2 21 print(myl) #MyList([1, 2, 1, 1, 1]) 22 # 23 print(myl[0]) #__getitem__被调用, #1
1 class MyList: 2 def __init__(self, count=0, value=0): 3 self.data = [] 4 for x in range(count): 5 self.data.append(value) 6 7 def __repr__(self): 8 return "MyList("+ repr(self.data) +")" 9 10 def __setitem__(self, index, value): 11 self.data[index] = value 12 13 def __getitem__(self, index): 14 print("__getitem__被调用") 15 return self.data[index] 16 17 def __delitem__(self, index): 18 if index >= len(self.data): 19 raise IndexError("%d在不予许的范围内" % index) 20 21 if index < -len(self.data): 22 raise IndexError("%d在不予许的范围内" % index) 23 del self.data[index] 24 #以下示意不予许用del,进行索引操作 25 #print("__delitem__被调用,index:", index) 26 #print("del 啥也不做!") 27 #raise TypeError 28 29 myl = MyList(5, 1) 30 print(myl) #MyList([1, 1, 1, 1, 1]) 31 32 myl[1] = 2 33 print(myl) #MyList([1, 2, 1, 1, 1]) 34 # 35 print(myl[0]) #__getitem__被调用, #1 36 # 37 print(myl) 38 del myl[3] 39 print(myl) 40 #MyList([1, 2, 1, 1, 1]) 41 #MyList([1, 2, 1, 1])
步长
1 class MyList: 2 def __init__(self, count=0, value=0): 3 self.data = [] 4 for x in range(count): 5 self.data.append(value) 6 7 def __repr__(self): 8 return "MyList("+ repr(self.data) +")" 9 10 def __setitem__(self, index, value): 11 self.data[index] = value 12 13 def __getitem__(self, index): 14 print("__getitem__被调用,index:",index) 15 if isinstance(index, int): 16 return self.data[index] 17 elif isinstance(index, slice): 18 print("开始值是:", index.start) 19 print("结束值是:", index.stop) 20 print("步长是:", index.step) 21 22 23 def __delitem__(self, index): 24 if index >= len(self.data): 25 raise IndexError("%d在不予许的范围内" % index) 26 27 if index < -len(self.data): 28 raise IndexError("%d在不予许的范围内" % index) 29 del self.data[index] 30 #以下示意不予许用del,进行索引操作 31 #print("__delitem__被调用,index:", index) 32 #print("del 啥也不做!") 33 #raise TypeError 34 35 myl = MyList(5, 1) 36 print(myl) #MyList([1, 1, 1, 1, 1]) 37 myl[1] = 2 38 myl[2] = 3 39 myl[3] = 4 40 myl[4] = 5 41 print(myl) #MyList([1, 2, 3, 4, 5]) 42 print(myl[1]) 43 print(myl[1:5:2]) #__getitem__被调用,index: slice(1, 5, 2)#[2, 4] 44 45 L = [1,2,3,4,5,6,7,8,9] 46 print(L[1::2]) #[2, 4, 6, 8] 47 s = slice(1,10,2) 48 print(L[s]) ##[2, 4, 6, 8] 49 print(s.start) #1 50 print(s.stop) #10 51 print(s.step) #2 52 print() 53 print(myl[slice(1,5,2)]) 54 print(myl[:])
函数调用(模拟)重载:
__call__ 方法:
作用:让一个对象能像函数一样被调用;
方法格式: def __call__(self, 参数列表):
执行代码
注: 此重载方法的参数可以是1个或多个()
例: class A:
pas
a = A() #创建对象
a() #??/a能被调用吗?
1 class MySum: 2 def __init__(self): 3 self.data = 0 4 5 def __call__(self, *args, **kwargs): 6 #def __call__(self): 7 #def __call__(self, a, b): 8 "函数调用重载" 9 print("__call__被调用") 10 print("args",args, "kwargs",kwargs) 11 s = sum(args) 12 self.data += s 13 return s 14 15 16 ms = MySum() 17 r = ms(100, 200) 18 print("r:",r) 19 r = ms(300, 400) 20 print("r:",r) 21 print("以前所有数之和:",ms.data) 22 #__call__被调用 23 #args (100, 200) kwargs {} 24 #r: 300 25 #__call__被调用 26 #args (300, 400) kwargs {} 27 #r: 700 28 #以前所有数之和: 1000#
迭代器(高级)
迭代器协议: 是指对象(实例)能够使用next函数获取下项数据,在没有下一项数据时触发一个StopIteration异常来终止迭代的约定;
next(it) 对应 __next__(self) 方法
iter(obj) 对应 __iter__(self)方法通常返回一个可迭代对象;
xxx
for 语句和推导式,先调用iter(obj)拿出迭代器,再迭代;
迭代器:
range() 生成器函数:
(x for x in range(10) ) 生成器表达式
迭代器协议:
1, 要有 __next__方法;
2, 无法取值产生StopIteration异常;
获取迭代器的方法;
__iter__方法,对象用于方法迭代器;
1 class Odd: 2 def __init__(self, begin, end): 3 self.begin = begin 4 self.end = end 5 self.cur = begin #数据的当前位置 6 7 def __next__(self): 8 print("__next__被调用") 9 if self.cur >= self.end: 10 raise StopIteration 11 if self.cur % 2 == 0: 12 self.cur += 1 13 r = self.cur 14 self.cur += 2 15 return r 16 17 def __iter__(self): 18 print("__iter__被调用,返回字节作为迭代器") 19 self.cur = self.begin 20 return self 21 22 #o = Odd(1, 10) 23 o = Odd(2, 10) # 奇数对象 24 for x in iter(o): 25 print(x) 26 27 print([x for x in o]) 28 #print(next(o))#1 29 #print(next(o))#3 30 #print(next(o))#5 31 #print(next(o))#7 32 #print(next(o))#9 33 #print(next(o)) 34 #__iter__被调用,返回字节作为迭代器 35 #__iter__被调用,返回字节作为迭代器 36 #__next__被调用 37 #3 38 #__next__被调用 39 #5 40 #__next__被调用 41 #7 42 #__next__被调用 43 #9 44 #__next__被调用 45 #__iter__被调用,返回字节作为迭代器 46 #__next__被调用 47 #__next__被调用 48 #__next__被调用 49 #__next__被调用 50 #__next__被调用 51 #[3, 5, 7, 9] 52 # 53 L = [1,2,3] 54 it = iter(L) 55 id(it) == id(L) 56 False 57 it 58 <list_iterator object at 0x0000000003D10940> 59 L 60 [1, 2, 3]
异常(高级)
with 语句
语法: with 表达式 [ as 变量名 ]:
语句块
或:
with 表达式1 [ as 变量名1 ] [ ,表达式2 [ as 变量名2 ]....]:
语句块
说明:as 子句中的变量绑定生成的对象;
1 #f = open("file.txt",'r') 2 #while True: 3 # l = f.readline() 4 # print(l, end='') 5 # if len(l) == 0: 6 # break 7 # 8 ##### 9 with open('file.txt','r') as f: 10 while True: 11 #3/0 #触发异常,但文件肯定会关闭 12 l = f.readline() 13 print(l, end='') 14 if len(l) == 0: 15 break 16
作用:使用于对资源进行访问的场合,确保使用过程中不管是否发生异常,都会执行必须的“清理” 操作,并释放资源;
环境管理器:
1,类内有__enter__ 和__exit__ 方法的类被称为环境管理器;
2,能够用with 语句进行管理的对象必须是环境管理器;
3,__enter__将进入with语句时被调用并返回由as变量管理对象;
4, __exit__ 将在离开with 时被调用, 且可以用参数来判断在离开with语句时是否有异常发生,并且做出相应的处理;
1 class Cooker: 2 def open_c(self): 3 print("正在打开火") 4 5 def close_c(self): 6 print("正在关闭火") 7 8 def doworks(self): 9 print("正在做饭") 10 11 def __enter__(self): 12 self.open_c() 13 return self #此对象将被as绑定 14 15 def __exit__(self, exc_type, exc_val, exc_tb): 16 self.close_c() 17 if exc_type is None: 18 print("with语句正常退出") 19 else: 20 print("with语句异常退出", exc_val) 21 22 23 with Cooker() as c: 24 c.doworks() 25 3/0 26 c.doworks() 27 28 #正在打开火 29 #正在做饭 30 #正在关闭火 31 #Traceback (most recent call last): 32 # File "C:, line 23, in <module> 33 # 3/0 34 #ZeroDivisionError: division by zero# 35 36 37 #正常处理 38 #c = Cooker() 39 #c.open_c() 40 #c.doworks() 41 #3/0 42 #c.doworks() 43 #c.close_c()
什么是继承(inheritance)/派生(derived)
什么是继承/派生
继承的目的是延续旧的功能;
派生的目的是在类旧类的基础上添加新的功能;
作用: 用继承派生机制,可以将一些共有功能加在基类中,实现代码共享,在不改变超类的代码的基础上改变原有功能;
名词: 基类(base class)/ 超类(supper class) /父类 (father class) /派生类(derived class) / 子类 (child class)
单继承语法:
class 类名(超类名):
。。。。
继承说明:任何类都直接或间接的继承自object类; object类是一切类的超类;
__base__属性:
作用:用来记录此类的基类(类实例);
覆盖override (也叫重写 overrite)
什么是覆盖:
覆盖是指由继承关系的类中,子类中实现了与基类(超类)同名的方法,在子类实例调用该方法时,实际调用的是子类中的覆盖版本,这种现象叫做覆盖;
子类对象显示调用基类方法的方式:
基类名。方法名。(实例,参数)
1 class Human: 2 def say(self): 3 print("say: hello,world!") 4 5 def run(self, speed): 6 print("Human run km/h speed:", speed) 7 8 class Student(Human): 9 def study(self, s): 10 print("Student study:", s) 11 12 def run(self, speed): 13 print("Student run km/h speed:", speed) 14 15 def walk(self, speed): #走的方法 16 #self.run(speed) #调用自身self #Student run km/h speed: 3 17 #self.__class__.run(self, speed) #调用自身 #self #Student run km/h speed: 3 18 self.__class__.__base__.run(self, speed) #借助于self自身调用父类的run方法 19 # #Human run km/h speed: 3 20 21 22 t1 = Human() 23 s1 = Student() 24 25 t1.run(5) 26 s1.run(4)#Student run km/h speed: 4 #此时调用的是子类的覆盖版本的方法 27 28 #子类调用基类的版本(原版本)方法 29 Human.run(s1, 8) # Human run km/h speed: 8 30 31 s1.walk(3) #Student run km/h speed: 3
1 class Human: 2 def say(self): 3 print("say: hello,world!") 4 5 def run(self, speed): 6 print("Human run km/h speed:", speed) 7 8 class Teacher(Human): 9 def teach(self, te): 10 print("Teacher teach:", te) 11 12 #def run(self, speed): 13 # print("Teacher run km/h speed:", speed) 14 15 class Student(Teacher): 16 def study(self, s): 17 print("Student study:", s) 18 19 #def run(self, speed): 20 # print("Student run km/h speed:", speed) 21 22 def walk(self, speed): #走的方法 23 #self.run(speed) #调用自身self #Student run km/h speed: 3 24 #self.__class__.run(self, speed) #调用自身 #self #Student run km/h speed: 3 25 self.__class__.__base__.run(self, speed) #借助于self自身调用父类的run方法 26 # #Human run km/h speed: 3 27 28 29 t1 = Human() 30 t2 = Teacher() 31 s1 = Student() 32 33 t1.run(5) 34 #s1.run(4)#Student run km/h speed: 4 #此时调用的是子类的覆盖版本的方法 35 t2.run(3.5) 36 s1.run(4) 37 38 39 #子类调用基类的版本(原版本)方法 40 #Human.run(s1, 8) # Human run km/h speed: 8 41 # 42 #s1.walk(3) #Student run km/h speed: 3