一。多态
在现实生活中,多态也会体现。如对于水这种物质,有固态:冰,液态:常态,气态:水蒸气,
在程序中,其官方定义是:多个不同对象可以相应同一方法,产生不同的结果。
而在python中,多态不是一个特殊的语法,而是一种关系,一种特性,举例:
class A: def work(self): print('I am working in A') def name(self): print('i am A') class B: def work(self): print('I am working in B') def name(self): print('i am B') class C: def work(self): print('I am working in C') def name(self): print('i am C') a=A() b=B() c=C() def toge(obj): obj.work() toge(a) toge(b) toge(c) #I am working in A #I am working in B #I am working in C
上述代码中分别制造了ABC三个类,这三个类都有不同 的特征,也有相同的特征work,可以通过多态,统一管理其中的work使之工作而保留其他的特性。
这种方法在接口中有所体现是,所以除了上述的鸭子类型以外也可以使用接口和抽象类来使用多态。
如果不是这种特性,需要分别对ab三个对象编写其对应的方法。
二。相关内置对象
1.isinstance
作用:判断某个对象是否是某个类的实例:isinstance(对象,类)
这种方法也可以判断某个数据是否是某个类型isinstance(数据,类型)
class Person: def work(self): print('i am working ') class book: def write(self): print('i can write') def working(oop): if isinstance(oop,Person): oop.work() else: print('you are not Person') ab=Person() ac=book() working(ab) working(ac) #i am working #you are not Person
当一个对象不具有某个特点时,可以使用isinstance来判断是否可以执行该函数,使程序不会报错,因为可以不执行不存在的方法。
除此之外,isinstance还可以判断某个数据是不是某个数据类型:
def add(a,b): if isinstance(a,int) and isinstance(b,int): return a+b else: return '不是整型' print(add(2,44)) print(add('asd',2)) #46 #不是整型
2.issubclass(子类,父类)
作用,判断一个子类是不是某个父类的子类。
class Father: def name(self): print('i am father') class Son(Father): def name(self): print('i am son') class Wang: def name(self): print('i am wang ') def test1(oop): if issubclass(type(oop),Father): oop.name() else: print('you are not my son') s1=Son() w1=Wang() test1(s1) test1(w1) #i am son #you are not my son
三。魔法函数
这类方法一般都放在类中使用。
1.__str__
该方法是在对象被转化为字符串时触发,而对象本来是一种对象形式:
<__main__.Person object at 0x00000288BDA380B8>
而这种方法显然是没有什么意义的,但是对于print的原理就是先将任何数据转化成字符串形式打印出来,所以,如果定义了该方法之后就可以直接打印该对象。
在__str__方法中可以传入对象参数,规定打印格式,如:
class Person: def __init__(self,name,age): self.name=name self.age=age def __str__(self): return '名字是%s,年龄是%s'%(self.name,self.age) p1=Person('lzx',18) print(p1) #名字是lzx,年龄是18
2.__del__
该方法是在对象被删除时,执行该方法:
class Person2: def __init__(self,name,age): self.name=name self.age=age def __del__(self): print('i am del') a=Person2('lzx',123) del a print('over') #i am del #over
当执行del a与据说是,会打印iam del
但是如果不执行del a 语句,程序会自动结束,垃圾回收机制会自动将不用的对象进行回收删除,所以即使不写这句话,在最后也会执行语句。
简易文件处理:
class File1: def __init__(self,file): self.file=open(file,'r',encoding='utf-8') def read(self): return self.file.read() def __del__(self): self.file.close() print('over') ab=File1('test.py') print(ab.read())
在对象结束时自动关闭对文件的操作。
3.__call__
当对象被调用时,执行该函数,调用就是对象名+()
class Test2: def __call__(self, *args, **kwargs): print('666') ba=Test2() ba() #666
4.__slots__
该属性是一个类属性,在类中使用,用于内存优化,当一个类定义了__slots__后,会使得类中的名称空间不被创建,类中只能创建slots中所用有的名称属性,不能多也不能少,这样就能减少内存开销的效果。
__slots__=['','']
class Person: __slots__ = ["name"] def __init__(self,name): self.name = name p = Person("jck") # 查看内存占用 # print(sys.getsizeof(p)) # p.age = 20 # 无法添加 # dict 没有了 print(p.__dict__)
注意,这时候的Person中的__dict__已经不存在了。
5.getattr setattr delattr
getattr 用点访问属性的时如果属性不存在时执行
setattr 用点设置属性时
delattr 用del 对象.属性 删除属性时 执行
class Test3: def __getattr__(self, item): print('__getattr__') return 1 def __setattr__(self, key, value): print('__setattr__') self.__dict__[key]=value def __delattr__(self, item): print('__delattr__') self.__dict__.pop(item) abc=Test3() print(abc.name) abc.name='123' print(abc.name) del abc.name print(abc.name) #__getattr__ #1 #__setattr__ #123 #__delattr__ #__getattr__ #1
首先,除了使用super继承父类的方法运行程序实现功能之外,对于setattr的基本原理就是将键值添加至名称空间的字典__dict__里,在设置属性时调用。而删除也是将名称空间字典中的键值弹出,顺便执行该函数语句。
而getattr,当可以通过点获取该值时,就返回该值,当没有找到该值时就返回return中的值
getattribute
当类中有getattribute方法时,获取值前会优先执行该函数,如果获取到了属性,就会返回其值,如果没有找到,就会调用getattr方法。
class Test3: def __getattr__(self, item): print('__getattr__') return 1 def __getattribute__(self, item): print('__getattribute__') return super().__getattribute__(item) abc1=Test3() # abc1.name=123 print(abc1.name) #__getattribute__ #__getattr__ #1
6.getitem,setitem,delitem
当类中有上述发方法,使用[]获取其值时,会触发该函数。
class Test4: def __getitem__(self, item): print('__getitem__') return self.__dict__[item] def __setitem__(self, key, value): print('__setitem__') self.__dict__[key]=value def __delitem__(self, key): print('__delitem__') del self.__dict__[key] abc4=Test4() abc4['name']=22 print(abc4['name']) del abc4['name'] print(abc4['name']) #__setitem__ #__getitem__ #22 #__delitem__
了解即可。
例:让一个对象既支持点取值,又支持[]取值:
class MyDict(dict): def __getattr__(self, key): return self.get(key) def __setattr__(self, key, value): self[key] = value def __delattr__(self, item): del self[item]
在该类中,首先继承了dict类的方法,使得对象可以用于字典的属性,再对其点操作进行返回值。
7.运算符重载(__gt__,__lt__,__eq__)
gt是在对象之间进行比较大时,运行该函数
lt是在对象之间进行比较小时,运行该函数
eq是在对象之间进行比较等于时,运行该函数
本来对象之间是不支持运算符比较 的(等于可以比较)
class Test6: def __init__(self,name,age): self.name=name self.age=age a=Test6('lzx',6) b=Test6('zzp',3) print(a>b) #报错
进行等于比较时也是比较两个对象是否相同。
而使用gt或者lt就可以实现对象之间的属性值的比较:
class Test6: def __init__(self,name,age): self.name=name self.age=age def __gt__(self, other): if self.age>other.age: return True return False def __lt__(self, other): if self.age<other.age: return False return True def __eq__(self, other): if self.age==other.age: return 123 return 321 a=Test6('lzx',6) b=Test6('zzp',3) print(a<b) print(a==b) #True #321
当然,在gt和lt之间只需要使用一个就够了。符号如果不同 解释器会自动交换两个对象的位置。
四。迭代器
要使一个类或对象,成为一个迭代器,需要在其定义两个方法:__item__和__next__。
class Dd: def __init__(self,max): self.max=max self.count=0 def __iter__(self): return self def __next__(self): if self.count<self.max: self.count+=1 return self.count else: raise StopIteration for i in Dd(10): print(i)
Dd就使一个迭代器,Dd的作用就是输入1-10的数,当调用该类时,执行next中的语句,使用StopItIreration进行异常抛出,停止程序,防止死循环的出现。
利用这个可以模仿range函数:
class Myrange: def __init__(self,min1,max1,step=1): self.min1=min1-1 self.max1=max1-1 self.step=step def __iter__(self): return self def __next__(self): if self.min1<self.max1: self.min1+=self.step return self.min1 else: raise StopIteration for i in Myrange(0,10,2): print(i)
如上,range满足左开右闭原则,而步长step默认为1,即使不传也没关系,不同点在于必须要传入起始数字。
所以,可以把具有__iter__,__next__两个方法的类看作一个迭代器。
五。上下文操作
上下文操作其实早有应用,像文件的打开与写入就是上下文操作,在使用with操作文件时会获取一个文件句柄,对句柄进行操作,即使后来忘记关闭对文件的链接,最后程序也会自动帮你关闭,其原理 就是在open类中的exit函数帮你关闭文件。
当执行with语句时,会先执行enter语句,如果运行正常,则运行exit语句,当enter运行过程中出现异常,则会立即运行exit语句,并传入异常信息。
class Text7: def __init__(self,file): self.file=file def __enter__(self): print('enter===') self.f=open(self.file) return self.f def __exit__(self, exc_type, exc_val, exc_tb): print('exit===') print(exc_type, exc_val, exc_tb) self.f.close() with Text7('test.py') as m: print(m.read())
Text7就是一个低配的open操作,其中:
enter将文件句柄作为返回值给类。
在exit中exc_type, exc_val, exc_tb,三个参数就是返回其异常信息(包含错误的类型.错误的信息.错误的追踪信息)。
小知识:exit也有返回值,返回的是一个布尔值(True,False),当程序正常运行结束时,没有太大影响,
当程序出现异常时,如果返回值是true时,异常会被处理,如果返回的时False。异常会被保留。