Py-多态,封装,反射,描述符,包装标准类型,面向对象进阶
多态:
对象可以通过他们共同的属性和动作来访问,而不需要考虑他们的类多态是继承的应用
class H2o: def __init__(self,temp): self.temp=temp def htype(self): if self.temp<=0: print('结冰') if self.temp>0 and self.temp<60: print('化成水') if self.temp>=60: print('水蒸气') class bing(H2o): pass class shui(H2o): pass class qi(H2o): pass ice=bing(0) water=shui(30) gas=qi(80) ice.htype() #ice,water,gas不同的类但是能调用相同的动作,方法 water.htype() gas.htype() #可以封装成函数来调用这些相同的方法 def func(obj): obj.htype() #这要属于H20这个父类的都能用func func(ice)
封装:
是要明确内外,外部调用的时候看不见它,自己里面使用的时候才能看见class H2o: _ab=123 __bc=234 def __init__(self,temp): print(H2o.__bc) #内部可以直接调用,外部不行 self.temp=temp def htype(self): if self.temp<=0: print('结冰') if self.temp>0 and self.temp<60: print('化成水') if self.temp>=60: print('水蒸气') alex=H2o(10) 其他文件import这个py文件调用时 看见这些带_的都是封装的,希望外部不访问的 如果硬要访问的话可以通过 from 封装 import H2o water=H2o(30) print(water._ab) #单斜杠的封装可以这样调用 print(water._H2o__bc) #这个双斜杠的封装可以这样调用 #双斜杠调用的格式_类名__双斜杠封装名
正常访问时在函数内部写非封装接口(里面包含着封装内容)来给别人调用
自省,反射
反射又称为自省,是指程序可以访问检测修改自身的一种能力1.hasattr(对象,字符串):用于查对象或者类里面是否有某个字符串的属性
class Blackmedium: feture='ugly' def __init__(self,name,addr): self.name=name self.addr=addr def sell_hourse(self): print('%s 正在卖房' %self.name) def rent_hourse(self): print('%s 正在租房子' %self.name) b1=Blackmedium('广域网','撒旦') print(hasattr(b1,'feture')) print(hasattr(b1,'sell_hourse'))
2.getattr:用于查对象或者类里面是否有某个字符串的值或者函数的运行地址
class Blackmedium: feture='ugly' def __init__(self,name,addr): self.name=name self.addr=addr def sell_hourse(self): print('%s 正在卖房' %self.name) def rent_hourse(self): print('%s 正在租房子' %self.name) b1=Blackmedium('广域网','撒旦') print(getattr(b1,'feture')) print(getattr(b1,'sell_hourse'))
3.setattr设置和修改对象或者类属性
class Blackmedium: feture='ugly' def __init__(self,name,addr): self.name=name self.addr=addr def sell_hourse(self): print('%s 正在卖房' %self.name) def rent_hourse(self): print('%s 正在租房子' %self.name) b1=Blackmedium('广域网','撒旦') #给对象设置属性 setattr(b1,'sb',123123) print(b1.sb)
反射:
一个人写了一段代码,但是没有写完。另一个人现在想写,利用反射可以那个人现在改写了,但是原来的人回来时还能重置回自己原来的继续写
class Blackmedium: feture='ugly' def __init__(self,name,addr): self.name=name self.addr=addr b1=Blackmedium('广域网','撒旦') if hasattr(b1,'put'): func_get=getattr(b1,'put') func_get() else: print('运行其他的luoji')
高级的导入方法__import__,传字符串
该py文件的同一级有一个CT1文件夹,里面有一个login.py
import importlib
m=importlib.import_module('CT1.login')
print(m)
该py文件的同一级有一个CT1文件夹,里面有一个login.py
import importlib
m=importlib.import_module('CT1.login')
print(m)
描述符
类的内置attr属性,描述符基于__getattr__,__setattr__,__delattr__这三个描述符:描述符就是一个类,只不过它定义了另一个类中属性的访问方式。
换句话说,一个类可以将属性管理全权委托给描述符类。
要遵循优先级
类属性>数据描述符>实例属性>非数据描述符>找不到的属性触发__getattr__
class Blackmedium: feture='ugly' def __init__(self,name,addr): self.name=name self.addr=addr def __getattr__(self,item): print('执行') b1=Blackmedium('广域网','撒旦') print(b1.feture) print(getattr(b1,'feture')) #使用来查找对象里的字符串的属性值,有就返回属性值 print(getattr(b1,'dsadadsad'))#没有就返回none b1.sssssssb #当调用的对象里面没有该属性时,进行__getattr__里面的内容
删除属性delattr,使用del时会触发__delattr__
class Blackmedium: feture='ugly' def __init__(self,name,addr): self.name=name self.addr=addr def __delattr__(self,item): print('删除') b1=Blackmedium('广域网','撒旦') del Blackmedium.feture print(b1.__dict__) print(Blackmedium.__dict__) #可以看见类下面的这个属性被删除了
修改属性setattr,使用setattr时会触发__setattr__
class Blackmedium: feture='ugly' def __init__(self,name,addr): self.name=name self.addr=addr def __setattr__(self,key,value): print('添加和修改完成') self.__dict__[key]=value b1=Blackmedium('广域网','撒旦') print(b1.__dict__) b1.sb='ni' print(b1.__dict__)
包:
大型项目中往往需要分模块,功能相似的模块可以用包组成层次组织结构,方便维护目录
\顶层文件夹
__init__.py
\subpackage1
__init__.py
mod1.py
mod2.py
\subpackage2
__init__.py
mod3.py
程序
import subpackage1.mod1.py
包装标准类型
1.包装list,继承list,添加新功能或者修改功能
class List(list): #继承了父类列表的属性def showmidle(self):
mid=int(len(self)/2)
return mid
l1=List('hello') #因为List没写init,所以hello直接给了List里面的list
print(l1,type(l1))
2.授权
授权:授权是包装的一个特性,这种做法可以新建或者修改产品的原有功能,其他的保持原样。授权是更新的功能是由新类的某部分来处理,但已存在功能授权给对象
的默认属性
解释程序:
class Open: def __init__(self,filename,mode='r',encoding1='utf-8'): self.file=open(filename,mode,encoding=encoding1) #将生成文件打开给self.file def __getattr__(self, item): return getattr(self.file,item) #虽然Open里面没有read,但是self.file里面有,所以找到read了 f1=Open('a.txt','w') print(f1.read) #查看f1里面是否有read函数,虽然Open没有,触发了__getattr__
给实例化的类f1拥有文件操作的所有功能
class Open: def __init__(self,filename,mode='r',encoding1='utf-8'): self.file=open(filename,mode,encoding=encoding1) #将生成文件打开给self.file def __getattr__(self, item): return getattr(self.file,item) #虽然Open里面没有read,但是self.file里面有,所以找到write了 f1=Open('a.txt','w') f1.write('asd')#查看f1里面是否有write函数,虽然Open没有,触发了__getattr_
在上一个程序中的改变型,如果类里面有写write,优先类里面的,不触发getattr
class Open: def __init__(self,filename,mode='r',encoding1='utf-8'): self.file=open(filename,mode,encoding=encoding1) #将生成文件打开给self.file def __getattr__(self, item): return getattr(self.file,item) def write(self,wr): print(wr) f1=Open('a.txt','w') f1.write('asd')
因此我们可以修改类中的write函数,使它在原有的write函数的基础上修改
class Open: def __init__(self,filename,mode='r',encoding1='utf-8'): self.file=open(filename,mode,encoding=encoding1) #将生成文件打开给self.file def __getattr__(self, item): return getattr(self.file,item) #虽然Open里面没有read,但是self.file里面有,所以找到read了 def write(self,wr): x=getattr(self.file,'write') xieru='已经修改 '+wr x(xieru) f1=Open('a.txt','w') f1.write('asd')#查看f1里面是否有read函数,虽然Open没有,触发了__getattr__
面向对象进阶:
1.isinstance(obj,cls)检查obj是否是类cls实例化而来的
2.issubclass(sub,supper)检查sub类是否是supper的子类
3.getattribute,是getattr的大哥,不管里面有没有都会执行它
class Open: x=10086 def __init__(self,filename,mode='r',encoding1='utf-8'): self.file=open(filename,mode,encoding=encoding1) #将生成文件打开给self.file def __getattr__(self, item): print('没有哦') def __getattribute__(self, item): print('有') f1 = Open('a.txt', 'w') f1.x1 #没有也执行 f1.x #有也执行
4.item方法
用字典添加属性的时候会触发setitem,删除时触发delitem,查阅触发getitemclass Foo: def __getitem__(self,item): print('getitem') def __setitem__(self,key,value): print('setitem') def __delitem__(self,key): print('delitem') f1=Foo() print(f1.__dict__) f1['name']='egon' #可见用字典的方式写入的时候会触发setitem print(f1.__dict__)
由于使用的时候会触发,所以可以定义同样名字的来覆盖或者修改这些函数
class Foo: def __getitem__(self,item): print('chufa getitem',item) def __setitem__(self,key,value): print('chufa setitem') self.__dict__[key]=value def __delitem__(self,key): print('chufa delitem') self.__dict__.pop(key) f1=Foo() print(f1.__dict__) f1['name']='egon' #可见用中括号字典的方式写入的时候会触发修改的setitem print(f1.__dict__) f1.name1='sb' #可见用点的方式写入的时候用的是内置的,不会触发修改的setitem print(f1.__dict__) del f1.name print(f1.__dict__) del f1['name1'] print(f1.__dict__)
5.改变对象的字符串显示
第一:正常的时候print实例化的结果class Foo: pass f1=Foo() print(f1) #<__main__.Foo object at 0x00B9E5E0>可以看见打印出来的是对象
第二:__str__改变print实例化出来的时候是自己想展示的字符串内容
class Foo: def __init__(self,name,age): self.name=name self.age=age def __str__(self): return '改成字符串了,活人名字%s,岁数%s' %(self.name,self.age) f1=Foo('sb1',100) print(f1)
第三:__repr__改变print实例化出来的时候是自己想展示的字符串内容
如果还有__str__优先__repr__class Foo: def __init__(self,name,age): self.name=name self.age=age def __repr__(self): return '改成字符串了,活人名字%s,岁数%s' %(self.name,self.age) f1=Foo('sb1',100) print(f1)
6.自定义格式化format方法
第一,普通的format用法x='{0}{0}'.format('dag') print(x)
第二:在类里面自己自定义自己的__format__
format_dic={ '1':'{0.name}-{0.age}', '2':'{0.name}的{0.age}' } class Foo: def __init__(self,name,age): self.name=name self.age=age def __format__(self,format_spec): fm=format_dic[format_spec] return fm.format(self) f1=Foo('sb1',100) print(format(f1,'2'))
7.__slots__节省实例内存
类下面的每个实例都会自己开辟自己的内存空间每个实例都会有自己的__Dict__,因此很占空间,可以用__slots__把所有实例的dict整合到一个里
class Foo: __slots__=['name','age'] f1=Foo() print(Foo.__slots__) print(f1.__slots__) f1.name='sb1' f1.age='11' print(f1.name) print(f1.age) print(f1.__dict__) #可以看见有slots,__dict__就会消失
slots只能定义它里面固定的几个属性,不能添加其他的属性
class Foo: __slots__=['name','age'] def __init__(self, name, age): self.name = name self.age = age f1=Foo('sb1',100) print(f1.name) print(f1.age) f1.abc='ssad' #可见在想添加新的属性abc时报错
8.文档注释__doc__,实例化调用doc,继承的子类调用不到
class Foo: 'are you silly b' __slots__=['name','age'] def __init__(self, name, age): self.name = name self.age = age f1=Foo('sb1',100) print(Foo.__doc__) print(f1.__doc__)
9.析构方法__del__,
清空内存时就会触发,无论是执行完毕还是出现删除实例操作都会触发class Foo: def __init__(self, name, age): self.name = name self.age = age def __del__(self): print('clear flash') f1=Foo('sb1',100)
10.call方法,用于实例化也可以加括号运行
class Foo: def __init__(self, name, age): self.name = name self.age = age def __call__(self,*args,**kwargs): print('call') f1=Foo('sda',12) f1() #实例加上空括号本质调用的是他的类里面的__call__
11.迭代器协议用于类
迭代数字class Foo: def __init__(self, n,): self.n = n def __iter__(self): return self def __next__(self): self.n=self.n+1 return self.n f1=Foo(12) print(f1) print(f1.__next__()) print(f1.__next__()) print(f1.__next__())
迭代字符串
class Foo: i=0 def __init__(self, n,): self.n = n def __iter__(self): return self def __next__(self): s=self.n[Foo.i] Foo.i=Foo.i+1 return s f1=Foo('asdadsad') print(f1) print(f1.__next__()) print(f1.__next__()) print(f1.__next__())
12.迭代器用于斐波那契数列
斐波那契额数列指的是前面两个数加起来等于第三个数如112358
class fib: def __init__(self): self.a=1 self.b=1 def __iter__(self): return self def __next__(self): (self.a,self.b)=(self.b,self.a+self.b) return self.a f1=fib() print(f1.__next__()) print(f1.__next__()) print(f1.__next__()) print(f1.__next__()) print(f1.__next__())
13.软件开发规范
bin文件夹,里面放置启动文件 from src.xxx import xxxx.pyconf文件夹存放的是配置文件
db文件夹存放的是数据文件
lib文件夹存放的是库文件,公共的类库
log文件夹存放的是日志
src存放主逻辑函数
导入其他的文件里的文件时要加下环境变量
import sys,os
#os.path.dirname(__file__)获取它的上一级的绝对地址,嵌套之后是获取它
#上一级的上一级的绝对地址
#以下可以使用os获取上一层的上一层的地址
base_dir=os.path.dirname(os.path.dirname(__file__))
sys.path.append(base_dir) #sys.path.append用于将其加入环境变量
base_dir=os.path.dirname(os.path.dirname(__file__))
sys.path.append(base_dir) #sys.path.append用于将其加入环境变量

浙公网安备 33010602011771号