內建函式isinstance,issubclass ,反射,自定義內建方法來定製類的功能,元類
一:內建函式
1,isinstance 判斷某個物件是不是屬於某一型別?
class Foo:pass
obj=Foo()
print(isinstance(obj,Foo))# 在python3中統一類與型別的概念返回True 或者False
2,issubclass 判斷一個類是不是另一個類的子類
class Parent:
pass
class Sub(Parent):
pass
print(issubclass(Sub,Parent))
print(issubclass(Parent,object))#返回True或者False
二:反射
反射:就是通過字串來操作類或者物件的屬性
用:hasattr
getattr
setattr
delattr
class People:
country='China'
def __init__(self,name):
self.name=name
def eat(self):
print('%s is eating' %self.name)
peo1=People('egon')
# print(hasattr(peo1,'eat')) #peo1.eat
# print(getattr(peo1,'eat')) #peo1.eat
# print(getattr(peo1,'xxxxx',None))
# setattr(peo1,'age',18) #peo1.age=18
# print(peo1.age)
# print(peo1.__dict__)
# delattr(peo1,'name') #del peo1.name
# print(peo1.__dict__)
應用場景:
class Ftp:
def __init__(self,ip,port):
self.ip=ip
self.port=port
def get(self):
print('GET function')
def put(self):
print('PUT function')
def run(self):
while True:
choice=input('>>>: ').strip()#接收使用者輸入的字串對映到具體的屬性
# print(choice,type(choice))
# if hasattr(self,choice):
# method=getattr(self,choice)
# method()
# else:
# print('輸入的命令不存在')
method=getattr(self,choice,None)
if method is None:
print('輸入的命令不存在')
else:
method()
conn=Ftp('1.1.1.1',23)
conn.run()
三:自定義內建函式方法?
#1、__str__方法
# class People:
# def __init__(self,name,age):
# self.name=name
# self.age=age
# #在物件被列印時,自動觸發,應該在該方法內採集與物件self有關的資訊,然後拼成字串返回
# def __str__(self):# # print('======>')
# return '<name:%s age:%s>' %(self.name,self.age)
# obj=People('egon',18)
# obj1=People('alex',18)
# print(obj) #obj.__str__()
# print(obj) #obj.__str__()
# print(obj) #obj.__str__()
# print(obj1) #obj1.__str__()
#1、__del__析構方法
# __del__會在物件被刪除之前自動觸發#只要是針對物件使用的
class People:
def __init__(self,name,age):
self.name=name
self.age=age
self.f=open('a.txt','rt',encoding='utf-8')
def __del__(self):
# print('run=-====>')
# 做回收系統資源相關的事情
self.f.close()
obj=People('egon',18)#物件obj已經被創建出來之後不會受類的影響,刪除類之後也不會影響物件的使用
print('主')
四:元類
4.1, 元類:在python中一切皆物件,那麼我們用class 關鍵字定義的類本身也是一個物件。關鍵字定義的類本身也是一個物件。
4.2,為什麼要用元類:元類是負責產生類的,所以我們學習元類或者自定義元類的目的是為了控制類的產生過程,還可以控制物件的產生過程
4.3 使用:
#1、儲備知識:內建函式exec的用法
# cmd="""
# x=1
# def func(self):
# pass
# """
# class_dic={}
# exec(cmd,{},class_dic)#excu用來模擬python直譯器解釋執行字串格式的程式碼
# print(class_dic)#得到一個名稱空間放到class—dic中去
#2、建立類的方法有兩種
# 大前提:如果說類也是物件的化,那麼用class關鍵字的去建立類的過程也是一個例項化的過程
# 該例項化的目的是為了得到一個類,呼叫的是元類
#2.1 方式一:用的預設的元類type
# class People: #People=type(...)
# country='China'
# def __init__(self,name,age):
# self.name=name
# self.age=age
# def eat(self):
# print('%s is eating' %self.name)
# print(type(People))
#2.1.1 建立類的3個要素:類名,基類,類的名稱空間
class_name='People'
class_bases=(object,)#基類寫成元祖形式,用內建方法__bases__檢視基類
class_dic={}
class_body=""" #類體程式碼
country='China'
def __init__(self,name,age):
self.name=name
self.age=age
def eat(self):
print('%s is eating' %self.name)
"""
exec(class_body,{},class_dic)
# 準備好建立類的三要素
# print(class_name)
# print(class_bases)
# print(class_dic)
# People=type(類名,基類,類的名稱空間)
# People1=type(class_name,class_bases,class_dic)
# print(People1)
# obj1=People1('egon',18)
# print(People)
# obj=People('egon',18)
#
# obj1.eat()
# obj.eat()
#2.2 方式二:用的自定義的元類
class Mymeta(type): #只有繼承了type類才能稱之為一個元類,否則就是一個普通的自定義類
def __init__(self,class_name,class_bases,class_dic):
print(self) #現在是People
print(class_name)
print(class_bases)
print(class_dic)
super(Mymeta,self).__init__(class_name,class_bases,class_dic) #重用父類的功能
# 分析用class自定義類的執行原理(而非元類的的執行原理):
#1、拿到一個字串格式的類名class_name='People'
#2、拿到一個類的基類們class_bases=(obejct,)
#3、執行類體程式碼,拿到一個類的名稱空間class_dic={...}
#4、呼叫People=type(class_name,class_bases,class_dic)
class People(object,metaclass=Mymeta): #People=Mymeta(類名,基類們,類的名稱空間)
country='China'
def __init__(self,name,age):
self.name=name
self.age=age
def eat(self):
print('%s is eating' %self.name)
# 應用:自定義元類控制類的產生過程,類的產生過程其實就是元類的呼叫過程
class Mymeta(type): #只有繼承了type類才能稱之為一個元類,否則就是一個普通的自定義類
def __init__(self,class_name,class_bases,class_dic):
if class_dic.get('__doc__') is None or len(class_dic.get('__doc__').strip()) == 0:
raise TypeError('類中必須有文件註釋,並且文件註釋不能為空')
if not class_name.istitle():
raise TypeError('類名首字母必須大寫')
super(Mymeta,self).__init__(class_name,class_bases,class_dic) #重用父類的功能
class People(object,metaclass=Mymeta): #People=Mymeta('People',(object,),{....})
"""這是People類"""
country='China'
def __init__(self,name,age):
self.name=name
self.age=age
def eat(self):
print('%s is eating' %self.name)
#3 儲備知識:__call__
# class Foo:
# def __call__(self, *args, **kwargs):
# print(self)
# print(args)
# print(kwargs)
# obj=Foo()
#
# # 要想讓obj這個物件變成一個可呼叫的物件,需要在該物件的類中定義一個方法__call__方法
# # 該方法會在呼叫物件時自動觸發
# obj(1,2,3,x=1,y=2)
# 4、自定義元類來控制類的呼叫的過程,即類的例項化過程
class Mymeta(type):
def __call__(self, *args, **kwargs):
# print(self) # self是People
# print(args)
# print(kwargs)
# return 123
# 1、先造出一個People的空物件
obj=self.__new__(self)
# 2、為該對空物件初始化獨有的屬性
# print(args,kwargs)
self.__init__(obj,*args,**kwargs)
# 3、返回一個初始好的物件
return obj
class People(object,metaclass=Mymeta):
country='China'
def __init__(self,name,age):
self.name=name
self.age=age
def eat(self):
print('%s is eating' %self.name)
def __new__(cls, *args, **kwargs):
print(cls)
# cls.__new__(cls) # 錯誤
obj=object.__new__(cls)
return obj
# 分析:呼叫Pepole的目的
#1、先造出一個People的空物件
#2、為該對空物件初始化獨有的屬性
# obj1=People('egon1',age=18)
# obj2=People('egon2',age=18)
# print(obj1)
# print(obj2)
obj=People('egon',age=18)
print(obj.__dict__)
print(obj.name)
obj.eat()