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)

描述符

类的内置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,查阅触发getitem
class 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.py
conf文件夹存放的是配置文件
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用于将其加入环境变量
posted @ 2020-10-15 21:43  克莱比-Kirby  阅读(144)  评论(0)    收藏  举报