1、反射
面向对(OOP)的优点:
面向对象是一种更高级别的结构化编程,有两点好处:
通过封装明确内外;通过继承+多态在语言层面支持了归一化设计。
泛化/特化
泛化:基于继承,表示所有子类与父类有一样的特点
特化:所有子类的自定义
自省/反射
自省也称为反射,这个性质展示了某对象是如何在运行期间获得自身信息的,
主要指程序可以访问、检测、修改它本身状态和行为的一种能力。
四个可以实现自省的函数,只用于类和对象
hasattr(obj,name) 判断obj对象是否能调用到name字符串的方法或属性
getattr(obj,name,default) 从obj对象中调用name字符串并得到结果
setattr(obj,x,y) 给obj对象设置属性,属性名x,属性值为y
delattr(obj,name) 从obj对象中删除name方法或者属性
class Bm():
feture = 'ugly'
def __init__(self,name,addr):
self.name = name
self.addr = addr
def sel_hourse(self):
print('不买')
def rent_hourse(self):
print('不租')
b1 = Bm('中介','上海')
print(b1.__dict__)
b1.sel_hourse()
print(hasattr(b1,'name')) 实质就是判断能否调用到name字符串属性或者方法
print(hasattr(b1,'sel_hourse'))
print(getattr(b1,'name'))
print(getattr(b1,'sel_hourse'))
print(getattr(b1,'sel','不存在')) 可以设置默认值,防止没有报错
setattr(b1,'sb','true')
setattr(b1,'name','黑的')
setattr(b1,'func',lambda x:x+1) 增加和修改数据属性和函数属性
print(b1.__dict__)
# del b1.name
delattr(b1,'name')
print(b1.__dict__)
反射的应用场景:两个人(A,B)合作一个项目,A需要B的模块,但B没有写,此时可以利用反射
在调用前判断是否由此项功能,如果有调用,没有执行其他功能
即:实现定义好接口,接口只有在被完全执行时才会真正的执行,实现了即插即用。
import sys
obj = sys.modules[__name__]
print(hasattr(obj,'x')) 检测自己文件是否存在某一属性
2、模块导入
from web1.web2 import t
t.test()
from web1.web2.t import *
test()
from web1 import web2.t 注意:这种导入是错误的
模块名是字符串时:
module_t = __import__('web1.web2.t')不管嵌套多少层,返回的都是最顶层模块
print(module_t) module_t = web1
module_t.web2.t.test()
import importlib
m = importlib.import_module('web1.web2.t') 定位到调用模块
print(m) m = t
m.test()
3、类的attr属性
class Foo():
x = 1
def __init__(self,y):
self.y = y
def __getattr__(self,item):
print('你要查的属性不存在')
def __setattr__(self,key,value):
print('--from setattr')
#self.key = value 注:这种设置会导致无限递归,错误
self.__dict__[key] = value 应该这样设置
def __delattr__(self,item)
print('---from delattr')
#del self.item 注:这种删除会导致无限递归,错误
self.__dict__.pop(item) 这样删除正确
__getattr__:查找的属性不存在时会执行该函数;
__setattr__\__delattr__:设置属性或者删除属性时会执行函数。
f1 = foo(10) 实例化就是设置属性(赋值)的过程,会执行setattr
f1.z = 3
f1.y
f1.ssssss 查找的属性不存在执行__getattr__
del f1.x
4、包装/授权
继承的方式完成包装:
python中提供了标准数据类型和很多内置方法,但是在很多场景下需要根据标准数据类型来
定制我们自己的数据类型,新增/改写方法,这就利用到了继承和派生。
class List(list):
def append(self,obj):
if type(obj) is str:
super().append(obj)
@property
def mid(self):
index = len(self)//2
return self[index]
l = List('hello')
l.append('23')
print(l.mid)
组合的方式完成授权:
授权是包装的一个特性,包装一个类型通常是对已存在的类型进行定制(新建、修改和删除原功能),
其他保持原样。授权是已更新的功能由新类的某部分处理,但已存在的功能授权给对象的默认属性。
授权的关键:__getattr__方法
class Handfile():
def __init__(self,filename,mode,encoding='utf8')
self.file = open(filename,mode,encoding)
self.mode = mode
self.encoding = encoding
def __getattr__(self,item)
return getattr(self.file,item)
def write(self,line):
t = time.strftime('%Y-%m-%d %X')
self.file.write('%s %s'%(t,line))
f1 = Handfile('a.txt','a')
f1.read
f1.write('内存不足')
5、isinstance(obj,cls)/issubclass(sub,super)/__getattrbute__
isinstance(obj,cls):判断对象是否由类实例化而来
issubcass(sub,super):判断sub是否是super的子类
__getattrbute__:了解即可和__getattr__配合使用时的情况
class Foo():
def __init__(self,x):
self.x = x
def __getattr__(self, item):
print('执行的是getattr')
def __getattribute__(self, item):
print('执行的是getattribute')
raise AttributeError('抛出异常')
f1 = Foo(10)
f1.x /
f1.xxxxxx
属性不管存在不存在,输出结果都是'执行的是getattribute'和'执行的是getattr',这是因为
不管属性是否存在都会执行__getattribute__方法,raise AttributeError('抛出异常')会
导致出现异常,而__getattr__的存在,接收了异常,因此不影响程序的运行。
5、item系列
item和attr效果一样,仅仅是调用方式不一样,item:通过字典,attr:通过.
class Foo:
def __getitem__(self, item):
print('getitem',item)
return self.__dict__[item]
def __setitem__(self, key, value):
print('setitem')
self.__dict__[key]=value
def __delitem__(self, key):
print('delitem')
self.__dict__.pop(key)
f1 = Foo()
f1['name']='egon'
print(f1.__dict__)
print(f1['name']) 查看属性,不存在报错
del f1['name']
print(f1.__dict__)
6、str、repr和自定制format
都属于包装范畴,对原有的功能进行编辑。
format_dic = {
'ymd':'{0.year}{0.mon}{0.day}',
'm-d-y':'{0.mon}{0.day}{0.year}'
}
class Date():
def __init__(self,year,mon,day):
self.year = year
self.mon = mon
self.day = day
def ff(self,format_spec):
# def __format__(self,format_spec):
print('-----')
fm = format_dic[format_spec]
return fm.format(self)
d1 = Date(2021,7,5)
print(d1.ff('ymd'))
# print(d1.__format__('m-d-y'))
7、slots和doc属性
slots是一个类变量,变量值可以是列表、元组等可迭代对象,意味着其实例对象只有数据属性
为了节省内存空间,用__slots__来取代实例的__dict__属性
class Foo:
__slots__ = ['name','age']
f1 = Foo()
f1.name = [1,2,3]
f1.age = 18
print(f1.name)
print(f1.age)
print(f1.__slots__)
class Foo():
'文档信息'
pass
class Bar(Foo):
pass
print(Foo.__dict__)
print(Bar.__dict__)
注:文档属性无法被继承
8、module、name和析构方法
from lib.aa import C
c1 = C()
print(c1.__module__)
print(c1.__class__)
c1的模块来自类的模块
析构方法:当对象在内存中被释放时,自动触发进行,
析构函数的调用是解释器进行垃圾回收自动触发的。
class Foo():
def __init__(self,name):
self.name = name
def __del__(self):
print('我执行了')
f1 = Foo('alex')
f2 = Foo('ssss')
del f1 只有删除实例f1时,才会触发__del__函数,删除实例的某个属性则不会
print(----) 当打印完成后整个程序运行结束,f2的内存被释放也会触发__del__函数
9、描述符
描述符:至少实现了__get__()\__set__()\__delete__()中的一个,也称为描述符协议
__get__() :被代理属性调用时触发
__set__() :被代理属性赋值时触发
__delete__() :被代理属性删除时触发
作用:用来代理另外一个类的类属性
描述符分为数据描述符(至少实现了__get__和__set__)和非数据描述符(没有实现__set__)
注意:必须把描述符定义成这个类的类属性,不能定义到构造函数中;
要严格遵循优先级:类属性>数据描述符>实例属性>非数据描述符>找不到
class Foo:
def __get__(self, instance, owner):
print('get方法')
def __set__(self, instance, value):
print('set')
# print(self,instance,value)
# instance.__dict__['x'] = value
def __delete__(self, instance):
print('delete')
instance.__dict__.pop('x')
class Bar:
x = Foo()
def __init__(self,name):
self.name = name
print(Bar./x)
Bar.x = 333
b1 = Bar('ales')
b1.x
b1.x = 'ss'
print(b1.__dict__)
del b1.x
print(b1.__dict__)
b1.ddddd
描述符的应用:对传入的参数进行自定制类型
class Typed:
def __init__(self,key,ex_type):
self.key = key
self.ex_type = ex_type
def __get__(self, instance, owner):
print('get方法')
return instance.__dict__[self.key]
def __set__(self, instance, value):
print('set方法')
if not instance or type(value) is not str:
raise TabError('%s传入的不是%s'%(self.key,self.ex_type))
instance.__dict__[self.key] = value
def __delete__(self, instance):
print('delete方法')
instance.__dict__.pop(self.key)
class People:
name = Typed('name',str)
def __init__(self,name,age,salary):
self.name = name
self.age = age
self.salary =salary
# p1 = People('alex',29,13000)
p1 = People(111,29,10100)
# print(p1.name)
p1.name = 'lili'
利用描述符自定制property
class La:
def __init__(self,func):
print(func)
self.func = func
print('---->')
def __get__(self, instance, owner):
print('get方法')
if instance is None:
return self
res = self.func(instance)
setattr(instance,self.func.__name__,res)
# print(self.func.__name__)
return res
class Room:
def __init__(self,name,w,l):
self.name = name
self.w = w
self.l = l
@La #area = La(area)
def area(self):
return self.w*self.l
r1 = Room('alex',1,1)
# print(Room.__dict__)
print(r1.area)
property补充
class Foo:
@property
def AAA(self):
print('get的时候运行我')
@AAA.setter
def AAA(self,val):
print('set的时候运行',val)
@AAA.deleter
def AAA(self):
print('删除的时候运行')
f1 =Foo()
# f1.AAA
# f1.AAA = 123
print(Foo.__dict__)
del f1.AAA
# print(f1.__dict__)
print(Foo.__dict__)
注:只有property静态属性不能赋值和删除,如果需要,必须设置需加@AAA.setter和@AAA.deleter
并且只有在属性AAA定义property之后才能定义AAA.setter和AAA.deleter
10、__call__\__next__\__iter__
__call__:对象后面加括号,触发执行。
class Foo:
def __call__(self, *args, **kwargs):
print('执行了')
f1 = Foo()
f1()
定义一个类,类实例的对象能够实现可迭代
class Foo:
def __init__(self,n):
self.n = n
def __iter__(self):
return self
def __next__(self):
if self.n == 13:
raise StopIteration('出现异常')
else:
self.n +=1
return self.n
f1 = Foo(10)
print(f1.__iter__())
11、上下文管理协议
上下文管理操作即with语句,为了让一个对象能够兼容with语句,必须在这个对象中声明
__enter__和__exit__方法。
class Foo:
def __init__(self,name):
self.name = name
def __enter__(self):
print('执行enter')
return self
def __exit__(self, exc_type, exc_val, exc_tb):
print('执行exit')
return True 当句举存在时,就把异常吃掉,不会报错,但是异常后的with的代码块
就不在执行,但会继续执行with外后面的代码
with Foo('a.txt') as f: 触发__enter__函数,拿到的结果赋值给f
print(f)
print(f.xxxxxx) 当with中代码出现错误时,会直接触发__exit__
# print(f.name) 当没有异常时,with下的代码运行结束触发__exit__.
print('-------->')
12、类的装饰器
给类添加数据属性功能
def Typed(**kwargs):
def deco(obj):
print(kwargs)
print(obj)
for key,val in kwargs.items():
setattr(obj,key,val)
return obj
print(kwargs)
return deco
@Typed(x=1,y=2,z=3) Typed(x=1,y=2,z=3)-->deco @deco----->Foo=deco(Foo)
class Foo:
pass
print(Foo.__dict__)
设置参数类型功能(描述符+装饰器)
class Typed:
def __init__(self,key,ex_type):
self.key = key
self.ex_type = ex_type
def __get__(self, instance, owner):
print('get方法')
return instance.__dict__[self.key]
def __set__(self, instance, value):
print('set方法')
if not instance or type(value) is not str:
raise TabError('%s传入的不是%s'%(self.key,self.ex_type))
instance.__dict__[self.key] = value
def __delete__(self, instance):
print('delete方法')
instance.__dict__.pop(self.key)
def deco(**kwargs):
def wapper(obj):
for k,v in kwargs.items():
setattr(obj,k,Typed(k,v))
return obj
@deco
class People():
# name = Typed('name', str)
# age = Typed('age',int)
# salary = Typed('salary',float)
def __init__(self,name,age,salary):
self.name = name
self.age = age
self.salary = salary
13、元类metaclass
元类是类的类,是类的模板,元类是用来控制如何创建类的,正如类是创建对象的模板
元类的实例是类,类的实例是对象
python中任何class定义的类都是type实例化的对象
一个类没有声明自己的元类,那么他的元类就是type
# 定义类的两种方式:
class Foo:
def __init__(self):
pass
print(Foo)
FFo = type('FFo',(object,),{'x':1}) #类名,继承的父类(可以多个),类的属性字典
print(FFo)
第六篇:面向对象高级
最新推荐文章于 2024-09-16 21:12:47 发布