一,反射
反射即在类的外部访问或者修改对象的属性,可以通过Python内置的四个函数来操作
class Foo: def __init__(self, name): self.name = name # def method(self): # print("this is a method") if __name__ == '__main__': f = Foo("abc") if hasattr(f, "name"): #获取 有则为True print(getattr(f, "name")) # 获取对象的属性或者方法 else: setattr(f, "name", "abc") # 设置 if hasattr(f, "method"): func = getattr(f, "method") func() else: setattr(f, "func", lambda: print("aaaa")) # 设置方法 f.func() delattr(f, "name") # 删除 print(f.__dict__) # {'func': <function <lambda> at 0x0000000002718950>},成功删除 "name"
二,自定制对象的显示格式
class Foo: def __init__(self, name): self.name = name def __str__(self): return self.name #将对象的某个属性作为打印对象时的输出
三,自定制调用实例方法
class Foo(object): def func(self): print('hello') def __setitem__(self, key, value): print('__setitem__') self.__dict__[key] = value def __getitem__(self, item): print('__getitem__') if item in self.__dict__: return self.__dict__[item] elif item in Foo.__dict__: return Foo.__dict__[item] else: raise ValueError def __setattr__(self, key, value): print('__setattr__') self.__dict__[key] = value def __delattr__(self, item): print('__delattr__') def __delitem__(self, key): print('__delitem__') f = Foo() func = f['func'] # __getitem__ f['func1'] = lambda: print('hello 1') # __setitem__ f.func2 = lambda: print('hello 2') f.func1() # hello 1 f.func2() # hello 2 del f['func'] # _delitem__ del f.func # __delattr__ """" __setattr__ , __delattr 和 __setitem__ , delitem__区别是如果通过f.来修改则使用前者, f["xxx"] 来操作访问,则使用后者,__getitem__通过f["xxx"] 访问时触发 """
四,上下文管理协议
当一块代码执行完之后会自动释放,保存资源,如打开一个文件,申请一个线程,打开数据库等待。这就是上下文管理。在Python中用with..as..语法来实现
with open('a.txt','rb') as f: info = f.read()
自定制类,使该类的实例对象也能实现上下文管理
class Open(): def __init__(self,filename,mode): self.obj = open(filename,mode) def write(self): pass def __enter__(self): #必须实现的方法,赋值给as 后的元素 return self.obj def __exit__(self, exc_type, exc_val, exc_tb): #必须实现的方法,自动退出 return True with Open('111.txt','rb') as f: print(f.read())
五,迭代器对象
给外界提供了一种对对象的遍历方法,类中需要实现__iter__方法,__next__方法
class Foo: def __init__(self, n): self.n = n def __iter__(self): # 用于返回一个可迭代对象 return self def __next__(self): if self.n > 10: raise StopIteration # 必须抛出异常,终止迭代 else: self.n += 1 return self.n f = Foo(0) for i in f: print(i)
六,描述符理论
定义:python描述符是一个“绑定行为”的对象属性,在描述符协议中,它可以通过方法重写属性的访问。这些方法有 __get__(), __set__(), 和__delete__()。如果这些方法中的任何一个被定义在一个对象中,
这个对象就是一个描述符。即一个对象含有 __get__(), __set__(),或__delete__()方法
class Foo(object): def __int__(self): pass def __get__(self, instance, owner): print("__get__") def __set__(self, instance, value): print("__set__") def __delete__(self, instance): print("__delete__") class Test(object): name = Foo() def __init__(self,name): self.name = name #1, __set__ def display(self): return self.name t=Test('bokeyuan') t.name #2,__get__ t.name = 'aaa' #3 __set__ del t.name #4 __delete__
描述符有两种:
1,数据描述符(实现了__get__()和__set__()方法)
2,非数据描述符(仅仅实现了__get__()方法)
对于以上可以这样理解:当通过实例为某个变量(对象)赋值时,如 self.name = 'aaa'时。
若name是非数据描述符时,即没有__set__方法,就只能调用实例属性字典来设置值,实例属性将覆盖非数据描述符,之后对name操作与非数据描述符无关。
若name为数据描述符对象时,因为其所属的类实现了get和set方法,因而比实例属性有更高的优先级,那么对实例的属性操作,触发的都是描述符的。
而官方文档对于描述符还有一个规定,类属性优先级高于数据描述符,即通过类本身为类设置属性时不会触发描述符。
因为可以得出关于描述符的优先级
1.类属性
2.数据描述符
3.实例属性
4.非数据描述符
5.找不到的属性触发__getattr__()
应用示例:自定制实现@propety
class Property(object): def __init__(self,func): self.func = func def __get__(self, instance, owner): return self.func(instance) class Foo(object): def __init__(self,name): self.__name = name @Property #name = Property(name) 装饰器 def name(self): return self.__name f=Foo('bokeyuan') print(f.name)
实现@classmethod:
class Classmethod(object): def __init__(self,func): self.func = func def __get__(self, instance, owner): def deco(): return self.func(owner) return deco class Foo(object): name = 'bokeyuan' def __init__(self,name): self.__name = name @Classmethod #tag = classmethod(tag) def tag(cls): return cls.name f=Foo('bokeyuan') print(f.tag())
实现@staticmethod
class Classmethod(object): def __init__(self,func): self.func = func def __get__(self, instance, owner): def deco(): print(instance,owner) return self.func(owner) return deco class Staticmethod(object): def __init__(self,func): self.func = func def __get__(self, instance, owner): def deco(*args): return self.func(*args) return deco class Foo(object): name = 'bokeyuan' def __init__(self,name): self.__name = name @Staticmethod def add(*args): print(args) sum = 0 for i in args: sum+=i return sum f=Foo('bokeyuan') print(f.add(1,2,3))