1. 程式人生 > >面向物件-高階(三 __setattr__,__delattr__,__getattr__ 四 二次加工標準型別(包裝))

面向物件-高階(三 __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

三者的用法演示

複製程式碼
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
複製程式碼

 

四 二次加工標準型別(包裝)

包裝: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)

二次加工標準型別(基於繼承實現)

class List(list):
def __init__(self,item,tag=False):
super().__init__(item)
self.tag=tag
def append(self, p_object):
if not isinstance(p_object,str):
raise TypeError
super().append(p_object)
def clear(self):
if not self.tag:
raise PermissionError
super().clear()

l=List([1,2,3],False)
print(l)
print(l.tag)

l.append('saf')
print(l)

# l.clear() #異常

l.tag=True
l.clear()

練習(clear加許可權限制)

複製程式碼
class List(list):
    def __init__(self,item,tag=False):
        super().__init__(item)
        self.tag=tag
    def append(self, p_object):
        if not isinstance(p_object,str):
            raise TypeError
        super().append(p_object)
    def clear(self):
        if not self.tag:
            raise PermissionError
        super().clear()

l=List([1,2,3],False)
print(l)
print(l.tag)

l.append('saf')
print(l)

# l.clear() #異常

l.tag=True
l.clear()
複製程式碼

 

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

實現授權的關鍵點就是覆蓋__getattr__方法

import time

class FileHandle:
def __init__(self,filename,mode='r',encoding='utf-8'):
self.file=open(filename,mode,encoding=encoding)
def write(self,line):
t=time.strftime('%Y-%m-%d %T')
self.file.write('%s %s' %(t,line))

def __getattr__(self, item):
return getattr(self.file,item)

f1=FileHandle('b.txt','w+')
f1.write('你好啊')
f1.seek(0)
print(f1.read())
f1.close()

授權示範一

#_*_coding:utf-8_*_
__author__ = 'Linhaifeng'
#我們來加上b模式支援
import time
class FileHandle:
def __init__(self,filename,mode='r',encoding='utf-8'):
if 'b' in mode:
self.file=open(filename,mode)
else:
self.file=open(filename,mode,encoding=encoding)
self.filename=filename
self.mode=mode
self.encoding=encoding

def write(self,line):
if 'b' in self.mode:
if not isinstance(line,bytes):
raise TypeError('must be bytes')
self.file.write(line)

def __getattr__(self, item):
return getattr(self.file,item)

def __str__(self):
if 'b' in self.mode:
res="<_io.BufferedReader name='%s'>" %self.filename
else:
res="<_io.TextIOWrapper name='%s' mode='%s' encoding='%s'>" %(self.filename,self.mode,self.encoding)
return res
f1=FileHandle('b.txt','wb')
# f1.write('你好啊啊啊啊啊') #自定製的write,不用在進行encode轉成二進位制去寫了,簡單,大氣
f1.write('你好啊'.encode('utf-8'))
print(f1)
f1.close()

授權示範二

#練習一
class List:
def __init__(self,seq):
self.seq=seq

def append(self, p_object):
' 派生自己的append加上型別檢查,覆蓋原有的append'
if not isinstance(p_object,int):
raise TypeError('must be int')
self.seq.append(p_object)

@property
def mid(self):
'新增自己的方法'
index=len(self.seq)//2
return self.seq[index]

def __getattr__(self, item):
return getattr(self.seq,item)

def __str__(self):
return str(self.seq)

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

print(l.mid)

#基於授權,獲得insert方法
l.insert(0,-123)
print(l)

 

 

#練習二
class List:
def __init__(self,seq,permission=False):
self.seq=seq
self.permission=permission
def clear(self):
if not self.permission:
raise PermissionError('not allow the operation')
self.seq.clear()

def __getattr__(self, item):
return getattr(self.seq,item)

def __str__(self):
return str(self.seq)
l=List([1,2,3])
# l.clear() #此時沒有許可權,丟擲異常


l.permission=True
print(l)
l.clear()
print(l)

#基於授權,獲得insert方法
l.insert(0,-123)
print(l)

練習題(授權)

複製程式碼
#練習一
class List:
    def __init__(self,seq):
        self.seq=seq

    def append(self, p_object):
        ' 派生自己的append加上型別檢查,覆蓋原有的append'
        if not isinstance(p_object,int):
            raise TypeError('must be int')
        self.seq.append(p_object)

    @property
    def mid(self):
        '新增自己的方法'
        index=len(self.seq)//2
        return self.seq[index]

    def __getattr__(self, item):
        return getattr(self.seq,item)

    def __str__(self):
        return str(self.seq)

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

print(l.mid)

#基於授權,獲得insert方法
l.insert(0,-123)
print(l)





#練習二
class List:
    def __init__(self,seq,permission=False):
        self.seq=seq
        self.permission=permission
    def clear(self):
        if not self.permission:
            raise PermissionError('not allow the operation')
        self.seq.clear()

    def __getattr__(self, item):
        return getattr(self.seq,item)

    def __str__(self):
        return str(self.seq)
l=List([1,2,3])
# l.clear() #此時沒有許可權,丟擲異常


l.permission=True
print(l)
l.clear()
print(l)

#基於授權,獲得insert方法
l.insert(0,-123)
print(l)
複製程式碼