一.反射
1.定义:指的是通过字符串来操作类或者对象的属性
2.为什么用反射?
减少冗余代码,提升代码质量。
3.如何用反射?
class People: country=‘China‘ def __init__(self,name): self.name=name obj=People(‘jame‘) #hasattr #print(‘country‘ in People.__dict__) print(hasattr(People,‘country‘)) #getattr #print(People.__dict__[‘country‘]) #print(getattr(People,‘country)) #如果取不到值,会报错。 print(getattr(People,‘country‘,None)) #None如果取不到值不报错,返回None #setattr #obj.age=18 #print(obj.__dict__) setattr(obj,‘age‘,18) print(obj.__dict__) #{‘name‘: ‘jame‘, ‘age‘: 18} setattr(People,‘x‘,111) print(People.__dict__) #{......, ‘__doc__‘: None, ‘x‘: 111} #delattr delattr(People,‘x‘) print(People.__dict__) #{......, ‘__doc__‘: None}
例1:反射涉及的4个内置函数
class Ftp: def get(self): print(‘get...‘) def put(self): print(‘put...‘) def auth(self): print(‘auth...‘) def run(self): while True: cmd=input(‘Please input:‘).strip() #cmd=‘get if hasattr(self,cmd): method=getattr(self,cmd) method() else: print(‘You please input error‘) obj=Ftp() obj.run()
例2:反射的简单使用
动态导入模块<了解>:
import importlib __import__(‘import_lib.metaclass‘) #这是解释器自己内部用的 #importlib.import_module(‘import_lib.metaclass‘) #与上面这句效果一样,官方建议用这个
二.一些内置方法 和 函数介绍
1.isinstance(obj,cls)和issubclass(sub,super)
isinstance(obj,cls)检查是否obj是否是类 cls 的对象。
issubclass(sub,super) 检查sub类是否是 super类的派生类。
class Foo(object): pass class bar(Foo): pass obj=Foo() #1 isinstance判断对象是否属于某类 res1=isinstance(obj,Foo) print(res1) #True #2 issubclass 判断bar类是否是 Foo 类的派生类 res2=issubclass(bar,Foo) print(res2) #true
2.__setattr__ ,__delattr__ ,__getattr__
配合反射机制使用,效果还不错.
class People: country=‘China‘ def __init__(self,name): self.name=name obj=People(‘jame‘) #hasattr #print(‘country‘ in People.__dict__) print(hasattr(People,‘country‘)) #getattr #print(People.__dict__[‘country‘]) #print(getattr(People,‘country123‘)) #如果取不到值,会报错。AttributeError: type object ‘People‘ has no attribute ‘country123‘ print(getattr(People,‘country123‘,None)) #None如果取不到值不报错,返回None #setattr #obj.age=18 #print(obj.__dict__) setattr(obj,‘age‘,18) print(obj.__dict__) #{‘name‘: ‘jame‘, ‘age‘: 18} setattr(People,‘x‘,111) print(People.__dict__) #{......, ‘__doc__‘: None, ‘x‘: 111} #delattr delattr(People,‘x‘) print(People.__dict__) #{......, ‘__doc__‘: None}
在类外部使用实例
class Foo: x=1 def __init__(self,y): self.y=y def __getattr__(self, item): print(‘from getattr:你找的属性不存在.‘) def __setattr__(self, key, value): print(‘from setattr‘) def __delattr__(self, item): print(‘from delattr‘) self.__dict__.pop(item) #1 __setattr__ 添加、修改属性会触发它的执行 f1=Foo(10) #from setattr print(f1.__dict__) #{} #因为你重写了__setattr__,凡是赋值操作都会触发它的运行,你啥都没写,就是根本没赋值,除非你直接操作属性字典,否则永远无法赋值 f1.__dict__[‘a‘]=3 f1.__dict__[‘b‘]=4 print(f1.__dict__) #{‘a‘: 3, ‘b‘: 4} #2 __deattr__ 删除属性的时候会触发 #f1.__dict__[‘a‘]=10 #我们可以通过修改属性字典,来完成添加、修改属性的操作 del f1.a #from delattr print(f1.__dict__) #{‘b‘:4}还剩b # 3 __getattr__ 只有使用点调用属性且属性不存在的时候才会触发 f1.abc #from getattr:你找的属性不存在.
class Ftp: def get(self): print(‘get...‘) def put(self): print(‘put...‘) def auth(self): print(‘auth...‘) def run(self): while True: cmd=input(‘Please input:‘).strip() #cmd=‘get if hasattr(self,cmd): method=getattr(self,cmd) method() else: print(‘You please input error‘) obj=Ftp() obj.run()
配合反射使用实例
3.__getattribute__
# @Time : 2018/8/20 17:19 # @Author : Jame # class Foo: # def __init__(self,x): # self.x=x # # def __getattr__(self, item): # print(‘执行的是__getattr__‘) # # # # # f1=Foo(100) # print(f1.x) # f1.xxx #若访问的不存在,则 “执行的是__getattr__” class Foo: def __init__(self,x): self.x=x def __getattribute__(self, item): print(‘不管是否存在都执行的是__getattribute__‘) f1=Foo(200) f1.x f1.xxx
getattr与getattribute的使用
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(200) f1.x f1.xxx
getattr和getattribute同时存在实例
#当__getattribute__与__getattr__同时存在,只会执行__getattrbute__,除非__getattribute__在执行过程中抛出异常AttributeError
4.描述符(__get__,__set__,__delete__)
(1).1 描述符是什么?
描述符本质就是一个新式类,在这个新式类中,至少实现了__get__(),__set__(),__delete__()中的一个,这也被称为描述符协议
__get__():调用一个属性时,触发
__set__():为一个属性赋值时,触发
__delete__():采用del删除属性时,触发
#1 定义一个描述符 class Foo: def __get__(self, instance, owner): print(‘__get__‘) def __set__(self, instance, value): print(‘__set__‘) def __delete__(self, instance): print(‘__delete__‘)
定义一个描述符
(2).描述符是干什么的,何时触发描述符中的3个方法呢?
描述符的作用是用来代理另外一个类的属性的(必须把描述符定义成这个类的类属性,不能定义到构造函数中__init__())
包含这三个方法的新式类称为描述符,由这个类产生的实例进行属性的调用/赋值/删除,并不会触发这三个方法!例如:
#2 描述符的使用 class Foo2: def __get__(self, instance, owner): print(‘触发 __get__‘) def __set__(self, instance, value): print(‘触发 __set__‘) def __delete__(self, instance): print(‘触发 __delete__‘) #包含这三个方法的新式类称为描述符,由这个类产生的实例进行属性的调用/赋值/删除,并不会触发这三个方法! f2=Foo2() f2.name=‘jame‘ print(f2.name) del f2.name
描述符的实例进行调用/赋值/删除不会触发
#何地?:定义成另外一个类的类属性 #何时?:且看下列演示
class Str: def __get__(self, instance, owner): print(‘Str 调用‘) def __set__(self, instance, value): print(‘str 设置‘) def __delete__(self, instance): print(‘str 删除‘) class Int: def __get__(self, instance, owner): print(‘Int 调用‘) def __set__(self, instance, value): print(‘Int 设置‘) def __delete__(self, instance): print(‘Int 删除‘) class People: name=Str() age=Int() def __init__(self,name,age): #name 被设置为Str类的的代理,age被设置Int类的代理。 self.name=name self.age=age #何地?:定义成另外一个类的类属性 #何时?:且看下列演示 p1=People(‘jame‘,18) #触发Str 设置,Int 设置! #1 描述符str的使用 调用,设置,删除 #p1.name #p1.name=‘tom‘ #del p1.name ‘‘‘ Str 调用 str 设置 str 删除 ‘‘‘ #2 描述符int的使用 调用,设置,删除 #p1.age #p1.age=30 #del p1.age ‘‘‘ Int 调用 Int 设置 Int 删除 ‘‘‘ #3 我们来瞅瞅到底发生了什么? print(p1.__dict__) print(People.__dict__) #补充 print(type(p1) == People) #True,type(p1) 查看p1是哪个类实例化来的。 print(type(p1).__dict__==People.__dict__) #True
触发描述符的场景
(3).描述符分两种
1).数据描述符:至少实现了__get__()和__set__()
1 class Foo: 2 def __set__(self, instance, value): 3 print(‘set‘) 4 def __get__(self, instance, owner): 5 print(‘get‘)
2).非数据描述符:没有实现__set__()
class Foo: 2 def __get__(self, instance, owner): 3 print(‘get‘)
(4).注意事项:
一 描述符本身应该定义成新式类,被代理的类也应该是新式类
二 必须把描述符定义成这个类的类属性,不能为定义到构造函数中
三 要严格遵循该优先级,优先级由高到底分别是
1.类属性
2.数据描述符
3.实例属性
4.非数据描述符
5.找不到的属性触发__getattr__()
。。。。。。
三.元类
四.异常处理
原文地址:https://www.cnblogs.com/Jame-mei/p/9507442.html