天天看點

python-面向對象進階一、isinstance(obj,cls)和issubclass(sub,super)二、反射三、二次加工标準類型(包裝)四、_getattribute_五、_str_,_repr_,_format_六、__del__

一、isinstance(obj,cls)和issubclass(sub,super)

isinstance(obj,cls)檢查obj是否是cls的對象

issubclass(sub,super)檢查sub是否是super的派生類

class Bar:
    pass

class Foo(Bar):
    pass

obj =Foo()

print(isinstance(obj,Foo))#True
print(issubclass(Foo,Bar))#True      

二、反射

python面向對象中的反射:通過字元串的形式操作對象相關的屬性

通過下面四個函數可以實作,适用于類和對象

hasattr(object,name):判斷一個object中有沒有name屬性或者方法

getatrr(object,name,default=None):擷取object中的name屬性或方法,設定defult=None時沒找到傳回None,沒設定報錯

setattr(x,y,z)修改x中y的值為z,當y不存在時添加y的值為z

delattr(x,y)删除x中的y屬性或方法

示範代碼:

python-面向對象進階一、isinstance(obj,cls)和issubclass(sub,super)二、反射三、二次加工标準類型(包裝)四、_getattribute_五、_str_,_repr_,_format_六、__del__
python-面向對象進階一、isinstance(obj,cls)和issubclass(sub,super)二、反射三、二次加工标準類型(包裝)四、_getattribute_五、_str_,_repr_,_format_六、__del__
class BlackMedium:
    feature='Ugly'
    def __init__(self,name,addr):
        self.name=name
        self.addr=addr

    def sell_house(self):
        print('%s 黑中介賣房子啦,傻逼才買呢,但是誰能證明自己不傻逼' %self.name)
    def rent_house(self):
        print('%s 黑中介租房子啦,傻逼才租呢' %self.name)

b1=BlackMedium('萬成置地','回龍觀天露園')

#檢測是否含有某屬性
print(hasattr(b1,'name'))
print(hasattr(b1,'sell_house'))

#擷取屬性
n=getattr(b1,'name')
print(n)
func=getattr(b1,'rent_house')
func()

# getattr(b1,'aaaaaaaa') #報錯
print(getattr(b1,'aaaaaaaa','不存在啊'))

#設定屬性
setattr(b1,'sb',True)
setattr(b1,'show_name',lambda self:self.name+'sb')
print(b1.__dict__)
print(b1.show_name(b1))

#删除屬性
delattr(b1,'addr')
delattr(b1,'show_name')
delattr(b1,'show_name111')#不存在,則報錯

print(b1.__dict__)

四個方法的使用示範      

View Code

python中一切皆對象,也可以對類使用反射

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

包裝: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__方法

python-面向對象進階一、isinstance(obj,cls)和issubclass(sub,super)二、反射三、二次加工标準類型(包裝)四、_getattribute_五、_str_,_repr_,_format_六、__del__

授權示範代碼一

python-面向對象進階一、isinstance(obj,cls)和issubclass(sub,super)二、反射三、二次加工标準類型(包裝)四、_getattribute_五、_str_,_repr_,_format_六、__del__
python-面向對象進階一、isinstance(obj,cls)和issubclass(sub,super)二、反射三、二次加工标準類型(包裝)四、_getattribute_五、_str_,_repr_,_format_六、__del__
#_*_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()

授權示範二      

授權示範代碼二

四、_getattribute_

當__getattribute__與__getattr__同時存在,隻會執行__getattrbute__,除非__getattribute__在執行過程中抛出異常AttributeError

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

    def __getattr__(self, item):
        print('執行的是我')
        # return self.__dict__[item]
    def __getattribute__(self, item):
        print('不管是否存在,我都會執行')
        raise AttributeError('哈哈')

f1=Foo(10)
f1.x
f1.xxxxxx      

五、_str_,_repr_,_format_

定制對象被列印時的輸出資訊,必須傳回一個字元串類型的值!    __str__,__repr__

自定制格式化字元串__format__

format_dict={
    'nat':'{obj.name}-{obj.addr}-{obj.type}',#學校名-學校位址-學校類型
    'tna':'{obj.type}:{obj.name}:{obj.addr}',#學校類型:學校名:學校位址
    'tan':'{obj.type}/{obj.addr}/{obj.name}',#學校類型/學校位址/學校名
}
class School:
    def __init__(self,name,addr,type):
        self.name=name
        self.addr=addr
        self.type=type

    def __repr__(self):
        return 'School(%s,%s)' %(self.name,self.addr)
    def __str__(self):
        return '(%s,%s)' %(self.name,self.addr)

    def __format__(self, format_spec):
        # if format_spec
        if not format_spec or format_spec not in format_dict:
            format_spec='nat'
        fmt=format_dict[format_spec]
        return fmt.format(obj=self)

s1=School('oldboy1','北京','私立')
print('from repr: ',repr(s1))
print('from str: ',str(s1))
print(s1)

'''
str函數或者print函數--->obj.__str__()
repr或者互動式解釋器--->obj.__repr__()
如果__str__沒有被定義,那麼就會使用__repr__來代替輸出
注意:這倆方法的傳回值必須是字元串,否則抛出異常
'''
print(format(s1,'nat'))
print(format(s1,'tna'))
print(format(s1,'tan'))
print(format(s1,'asfdasdffd'))      

六、__del__

析構方法,當對象在記憶體中被釋放時,會自動觸發執行。

當程式結束時,python隻會回收自己的記憶體空間,即使用者态記憶體,而作業系統的資源則沒有被回收,這就需要我們定制__del__,在對象被删除前向作業系統發起關閉資料庫連結的系統調用,回收資源

# class Foo:
#     def __del__(self):
#         print('run....')
# obj = Foo()

#__call__:在對象被調用時會自動觸發該方法,
class Foo:
    def __init__(self,x,y):
        self.x=x
        self.y=y

    def __call__(self, *args, **kwargs):
        print(self,args,kwargs)

obj = Foo()      

焚膏油以繼晷,恒兀兀以窮年。