天天看點

python内置屬性__setattr__,__delattr__,__getattr__四 二次加工标準類型(包裝)

三 __setattr__,__delattr__,__getattr__ 

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')
        # self.key=value #這就無限遞歸了,你好好想想
        self.__dict__[key]=value #應該使用它

    def __delattr__(self, item):
        print('----> from delattr')
        # del self.item #無限遞歸了
        self.__dict__.pop(item)

#__setattr__添加/修改屬性會觸發它的執行
f1=Foo(10)
print(f1.__dict__) # 因為你重寫了__setattr__,凡是指派操作都會觸發它的運作,你啥都沒寫,就是根本沒指派,除非你直接操作屬性字典,否則永遠無法指派
f1.z=3
print(f1.__dict__)

#__delattr__删除屬性的時候會觸發
f1.__dict__['a']=3#我們可以直接修改屬性字典,來完成添加/修改屬性的操作
del f1.a
print(f1.__dict__)

#__getattr__隻有在使用點調用屬性且屬性不存在的時候才會觸發
f1.xxxxxx
           

lower的示例:

class Foo:
    def __init__(self,name):
        self.name = name

    def __getattr__(self, item):
        print('【%s】這個屬性不存在!'%item)

    def __setattr__(self, key, value):
        # 設定值為str
        if type(value) is str:
            print('設定成功![%s,%s]'%(key,value))
            self.__dict__[key] = value
        else:
            print('[%s]不是是字元串'%value)

    def __delattr__(self, item):
        print('%s 不允許删除'%item)
        # print('執行了delattr',item)
        # self.__dict__.pop(item)



f1 = Foo('long')
# f1.age  # 【age】這個屬性不存在!

# f1.age = 11
# print(f1.__dict__)

print(f1.__dict__)
del f1.name
print(f1.__dict__)
           

四 二次加工标準類型(包裝)

包裝:python為大家提供了标準資料類型,以及豐富的内置方法,其實在很多場景下我們都需要基于标準資料類型來定制我們自己的資料類型,新增/改寫方法,這就用到了我們剛學的繼承/派生知識(其他的标準類型均可以通過下面的方式進行二次加工)

class List(list): #繼承list所有的屬性,也可以派生出自己新的,比如append和mid
    def append(self, p_object):
        ' 派生自己的append:加上類型檢查'
        if not isinstance(p_object,int):
            raise TypeError('must be int')
        super().append(p_object)

    @property
    def mid(self):
        '新增自己的屬性'
        index=len(self)//2
        return self[index]

l=List([1,2,3,4])
print(l)
l.append(5)
print(l)
# l.append('1111111') #報錯,必須為int類型

print(l.mid)

#其餘的方法都繼承list的
l.insert(0,-123)
print(l)
l.clear()
print(l)

二次加工标準類型(基于繼承實作)
           

授權:授權是包裝的一個特性, 包裝一個類型通常是對已存在的類型的一些定制,這種做法可以建立,修改或删除原有産品的功能。其它的則保持原樣。授權的過程,即是所有更新的功能都是由新類的某部分來處理,但已存在的功能就授權給對象的預設屬性。

實作授權的關鍵點就是覆寫__getattr__方法

import time
class Open:
    def __init__(self,filename,mode='r',encoding='utf-8'):
        self.file = open(filename,mode,encoding=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))

f = Open('a.txt','w+','utf-8')
print(f.write)
# f.write('a') # 先從自己類中查找,沒有調用__getattr__,通過getattr()在系統提供的類中查找
# data = f.read()
# print(data)
f.write('cup好熱\n')
f.write('aaaaaaaaa\n')
           

繼續閱讀