python 描述符 上下文管理協議 類裝飾器 property metaclass
阿新 • • 發佈:2019-03-02
get stat www. 類方法 aaa 部分 函數裝飾器 delete elf
1.描述符
#!/usr/bin/python env # coding=utf-8 # 數據描述符__get__ __set__ __delete__ ‘‘‘ 描述符總結
描述符是可以實現大部分python類特性中的底層魔法,包括@classmethod,@staticmethd,@property甚至是__slots__屬性
描述符是很多高級庫和框架的重要工具之一,描述符通常是使用到裝飾器或者元類的大型框架中的一個組件
註意事項:
一 描述符本身應該定義成新式類,被代理的類也應該是新式類
二 必須把描述符定義成這個類的類屬性,不能為定義到構造函數中
三 要嚴格遵循該優先級,優先級由高到底分別是1.類屬性
2.數據描述符
3.實例屬性
4.非數據描述符
5.找不到的屬性觸發__getattr__()
描述符分2種 1.數據描述符:至少有get set方法 2.非數據描述符:沒有set方法 ‘‘‘ class Str: def __init__(self, name,val_type): self.name = name self.val_type = val_type # instance 實例對象 owner實例的類 def __get__(self, instance, owner): print(‘get方法‘, instance, owner) return instance.__dict__[self.name] # instance 實例對象 value實例的值 def __set__(self, instance, value): print(‘set方法‘, instance, value) if not isinstance(value, self.val_type): raise TypeError("%s 的數據類型不是 %s" % (value, self.val_type)) instance.__dict__[self.name] = value def __delete__(self, instance): print(‘delete方法‘, instance) instance.__dict__.pop(self.name) class People: # 描述符 name = Str(‘name‘, str) age = Str(‘age‘, int) salary = Str(‘salary‘, int) def __init__(self, name, age, salary): self.name = name self.age = age self.salary = salary p1 = People(‘wangwu‘, 12, 98921) # 調用 print(p1.__dict__) # print(p1) # p1.name # #賦值 # print(p1.__dict__) # p1.name=‘egonlin‘ # print(p1.__dict__) # # #刪除 # print(p1.__dict__) # del p1.name # print(p1.__dict__)
2.上下文管理協議
操作文件對象寫法
1 with open(‘a.txt‘) as f:
2 ‘代碼塊‘
上述叫做上下文管理協議,即with語句,為了讓一個對象兼容with語句,必須在這個對象的類中聲明__enter__和__exit__方法
# 上下文管理協議 with ‘‘‘ # with open(‘filename‘) as f: # 代碼塊 1.with.obj ---> obj.__enter__(), return val 2.as f ----> f=val 3.with obj as f === f=obj.__enter() 4.執行 1)沒有異常時,all code運行後,__exit__ 三個參數都為None 2)有異常時,從異常的的位置觸發__exit__ a。如果exit的返回值為True,吞掉了異常 b.反之,拋出異常 c.exit的代碼執行完畢代表了整個with語句執行完畢 ‘‘‘ class Foo: def __init__(self, name): self.name = name def __enter__(self): # 出現with語句,對象的__enter__被觸發,有返回值則賦值給as聲明的變量 return self # exc_type 異常類:NameError
# exc_val 異常值:name ‘abc異常abc‘ is not defined
# exc_tb 追蹤信息: Traceback後面的內容 # Traceback(most recent call last): # NameError: name ‘abc異常abc‘ is not defined def __exit__(self, exc_type, exc_val, exc_tb): # with裏有異常時 觸發改函數 print("%s %s %s" % (exc_type, exc_val, exc_tb)) return True # 如果__exit()返回值為True,那麽異常會被清空,就好像啥都沒發生一樣,with後的語句正常執行 with Foo(‘a.txt‘) as f: print(f) # print(abc異常abc) print(f.name) print("*"*100)
# 上下文管理實例
class Open: def __init__(self,filepath,mode=‘r‘,encoding=‘utf-8‘): self.filepath=filepath self.mode=mode self.encoding=encoding def __enter__(self): # print(‘enter‘) self.f=open(self.filepath,mode=self.mode,encoding=self.encoding) return self.f def __exit__(self, exc_type, exc_val, exc_tb): # print(‘exit‘) self.f.close() return True def __getattr__(self, item): return getattr(self.f,item) with Open(‘a.txt‘,‘w‘) as f: print(f) f.write(‘aaaaaa‘) f.wasdf #拋出異常,交給__exit__處理
3.類裝飾器
# 函數裝飾器範式 # def wrap(func): # def wrapper(*args, **kwargs): # func(*args, **kwargs) # return True # return wrapper # 無參類裝飾器範式 # def wrap(cls): # return cls # 有參類裝飾器範式 # def wrap(**kwargs): # def wrapper(obj): # # 操作kwargs # return obj # return wrapper # 有參類裝飾器 class Check_type: def __init__(self, name, val_type): self.name = name self.val_type = val_type # instance 實例對象 owner實例的類 def __get__(self, instance, owner): # print(‘get方法‘, instance, owner) return instance.__dict__[self.name] # instance 實例對象 value實例的值 def __set__(self, instance, value): # print(‘set方法‘, instance, value) if not isinstance(value, self.val_type): raise TypeError("%s的數據類型不是 %s" % (value, self.val_type)) instance.__dict__[self.name] = value def __delete__(self, instance): # print(‘delete方法‘, instance) instance.__dict__.pop(self.name) def Typed(**kwargs): # kwargs ===> name=str, age= int, salary=int def wrapper(obj): for key, val in kwargs.items(): # 描述符 val是key的類型 # val = Check_type(‘val‘, str) setattr(obj, key, Check_type(key, val)) return obj return wrapper @Typed(y=2, x=1, z=3) class Foo: pass @Typed(name=‘wangwu‘) class foo: pass @Typed(name=str, age=int, salary=int) # @warpper -->People=warper(people) class People: # 描述符 # name = Str(‘name‘, str) # age = Str(‘age‘, int) # salary = Str(‘salary‘, int) def __init__(self, name, age, salary): self.name = name self.age = age self.salary = salary print(People.__dict__) p1 = People(‘wangwu‘, "d", 98921) # 調用 print(p1.__dict__)
4.仿property
# 類裝飾器 # class Cls_property: # def __init__(self,func): # self.func = func # 仿property類裝飾器 class Cls_property: def __init__(self, func): # print("func屬性 %s " %(func)) self.func = func # 描述get有兩個參數 第一個是實例 第二個是類 def __get__(self, instance, owner): # val = self.func() print(‘get---->‘) print(‘instance: %s‘ % instance) # 實例對象 r1 print(‘owner: %s‘ % owner) # 類 Room if instance is None: return self res = self.func(instance) # property延時計算 setattr(instance, self.func.__name__, res) return res # 加上set 數據描述符 # def __set__(self, instance, value): # pass class Room: tag = 168 def __init__(self, owner, width, length): self.owner = owner self.width = width self.length = length # @cls_property @Cls_property # area=property(area) def area(self): return self.width * self.length # @cls_property @property # area=property(area) def area1(self): return self.width * self.length # 類方法 能訪問類的屬性不能訪問實例屬性 @classmethod def test_tag(cls, x): print(cls) print("from test_tag %s %s" % (cls.tag, x)) # 靜態方法 不能訪問類、實例屬性 @staticmethod def action(a, b, c): print("%s %s %s" % (a, b, c)) # 類可以調用,實例不可調用test def test(cls, x): print(cls) print("from test_tag %s %s" % (cls.tag, x)) @property # <property object at 0x01FE80F0> def pro_test(self): return "pro_test" r1 = Room(‘zq‘, 1, 100) print(r1.__dict__) # 沒找到area屬性值 那就調用代理的Roo的area值 print(r1.area) print(r1.__dict__) # 沒找到area屬性值 那就調用代理的Roo的area值 print(r1.area) print(r1.area) print(r1.area) # print(Room.__dict__[‘area‘]) # print(Room.area) # print(Room.pro_test) # 一個靜態屬性property本質就是實現了get,set,delete三種方法 # 方法一 class Foo: @property def AAA(self): print(‘get的時候運行我啊‘) @AAA.setter def AAA(self,value): print(‘set的時候運行我啊‘, value) @AAA.deleter def AAA(self): print(‘delete的時候運行我啊‘) #只有在屬性AAA定義property後才能定義AAA.setter,AAA.deleter f1=Foo() f1.AAA f1.AAA=‘aaa‘ del f1.AAA print("<----------------------->") # 方法二 class Foo: def get_AAA(self): print(‘get的時候運行我啊‘) def set_AAA(self,value): print(‘set的時候運行我啊‘, value) def delete_AAA(self): print(‘delete的時候運行我啊‘) AAA=property(get_AAA,set_AAA,delete_AAA) #內置property三個參數與get,set,delete一一對應 f1=Foo() f1.AAA f1.AAA=‘aaa‘ del f1.AAA
5.元類 metaclass
元類是類的類,是類的模板
元類的實例是類,類的實例是 對象
type是python的一個內建元類 ,用來控制生成類,python中任何class定義的類其實都是type類實例化的對象
# 創建類有2種方法 # metaclass # 類的默認元類是type # 1. class Foo: pass # 2.tpye(str) t = type(Foo) print(t) # print(t.__dict__) def test(self): pass def __init__(self, name, age): self.name = name self.age = age # s三個參數 類名 (父類,), {屬性字典} # 3.type(str,(object,),{}) t = type(‘str‘, (object,), {‘a‘: 1, ‘__init__‘: __init__, ‘test‘: test}) print(t.__dict__) print(t) print("------------------------->") # 自定義元類 class Mytype(type): def __init__(self, *args, **kwargs): print("元類的自定義類") # for i in args: # print(i) def __call__(self, *args, **kwargs): # self == Foo # print("__call__函數:",self) obj = object.__new__(self) # object.__nee__(Foo) --> 產生 f1 產生實例obj # print("obj產生: ",obj) self.__init__(obj, *args, **kwargs) # Foo.__init__() return obj class Foo(metaclass=Mytype): # Mytype(傳了4個參數: self,Foo,(),{})-->觸發mytype __init__ def __init__(self, name): self.name = name # f1.name = name print(Foo) f1 = Foo(‘wangwu‘) print(f1) # print(f1.__dict__)
參考:http://www.cnblogs.com/linhaifeng/articles/6204014.html#_label15
python 描述符 上下文管理協議 類裝飾器 property metaclass