1. 程式人生 > >python 描述符 上下文管理協議 類裝飾器 property metaclass

python 描述符 上下文管理協議 類裝飾器 property metaclass

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