python全棧開發【第十七篇】面向對象反射和內置方法
一、靜態方法(staticmethod)和類方法(classmethod)
類方法:有個默認參數cls,並且可以直接用類名去調用,可以與類屬性交互(也就是可以使用類屬性)
靜態方法:讓類裏的方法直接被類調用,就像正常調用函數一樣
類方法和靜態方法的相同點:都可以直接被類調用,不需要實例化
類方法和靜態方法的不同點:
類方法必須有一個cls參數表示這個類,可以使用類屬性
靜態方法不需要參數
綁定方法:分為普通方法和類方法
普通方法:默認有一個self對象傳進來,並且只能被對象調用-------綁定到對象
類方法:默認有一個cls對象傳進來,並且可以被類和對象(不推薦)調用-----綁定到類
非綁定方法:靜態方法:沒有設置默認參數,並且可以被類和對象(不推薦)調用-----非綁定
# staticmethod和classmethod class Student: f = open(‘student‘, encoding=‘utf-8‘) def __init__(self): pass @classmethod #類方法 :有個默認參數cls,並且可以直接使用類名去 #調用,還可以與類屬性交互(也就是可以使用類屬性) def show_student_info_class(cls): # f = open(‘student‘, encoding=‘utf-8‘) for line in cls.f: name,sex = line.strip().split(‘,‘) print(name,sex) @staticmethod #靜態方法:可以直接使用類名去調用,就像正常的函數調用一樣 def show_student_info_static(): #不用傳self f = open(‘student‘,encoding=‘utf-8‘) for line in f: name,sex = line.strip().split(‘,‘) print(name,sex) # egon = Student() # egon.show_student_info_static() #也可以這樣調,但是還是推薦用類名去調 # egon.show_student_info_class() Student.show_student_info_class()#類名.方法名() print(‘-------------------‘) Student.show_student_info_static()#類名.方法名()
isinstance 和 issubclass
isinstance(obj,cls):檢查obj是不是cls的對象(傳兩個參數,一個是對象,一個是類)
issubclass(sub,super):檢查sub是不是super的子類(傳兩個參數,一個是子類,一個是父類)
class Foo: pass class Son(Foo): pass s = Son() print(isinstance(s,Son)) #判斷s是不是Son的對象 print(type(s) is Son) print(isinstance(s,Foo)) #判斷s是不是Foo的對象 不精準 print(type(s) is Foo) #type比較精準 print(issubclass(Son,Foo)) #判斷Son是不是Foo的子類 print(issubclass(Son,object)) print(issubclass(Foo,object)) print(issubclass(int,object))
二、反射
反射:可以用字符串的方式去訪問對象的屬性,調用對象的方法(但是不能去訪問方法),python中一切皆對象,都可以使用反射。
反射有四種方法:
hasattr:hasattr(object,name)判斷一個對象是否有name屬性或者name方法。有就返回True,沒有就返回False
getattr:獲取對象的屬性或者方法,如果存在則打印出來。hasattr和getattr配套使用
需要註意的是,如果返回的是對象的方法,返回出來的是對象的內存地址,如果需要運行這個方法,可以在後面添加一對()
setattr:給對象的屬性賦值,若屬性不存在,先創建後賦值
delattr:刪除該對象指定的一個屬性
# setattr class Foo: def __init__(self): self.name = ‘egon‘ self.age = 51 def func(self): print(‘hello‘) egg = Foo() setattr(egg,‘sex‘,‘男‘) print(egg.sex) # 2. def show_name(self): print(self.name+‘sb‘) setattr(egg,‘sh_name‘,show_name) egg.sh_name(egg) show_name(egg)
delattr(egg,‘name‘) print(egg.name)
1.對象應用反射
# 對象應用反射 class Foo: def __init__(self): self.name = ‘egon‘ self.age = 51 def func(self): print(‘hello‘) egg = Foo() print(hasattr(egg,‘name‘)) #先判斷name在egg裏面存在不存在 print(getattr(egg,‘name‘)) #如果為True它才去得到 print(hasattr(egg,‘func‘)) print(getattr(egg,‘func‘)) #得到的是地址 # getattr(egg,‘func‘)() #在這裏加括號才能得到,因為func是方法 if hasattr(egg,‘func‘): getattr(egg,‘func‘)() else: print(‘沒找到‘)
2.類應用反射
# 類應用反射 class Foo: f = 123 @classmethod def class_method_dome(cls): print(‘class_method_dome‘) @staticmethod def static_method_dome(): print(‘static_method_dome‘) print(hasattr(Foo,‘class_method_dome‘)) method = getattr(Foo,‘class_method_dome‘) method() print(‘------------‘) print(hasattr(Foo,‘static_method_dome‘)) method1 = getattr(Foo,‘static_method_dome‘) method1()
3.模塊應用反射
模塊的應用又分為導入其他模塊反射和在本模塊中反射
# 1.導入其他模塊引用 import mymodule print(hasattr(mymodule,‘test‘)) getattr(mymodule,‘test‘)() # # 這裏的getattr(mymodule,‘test‘)()這一句相當於 # p = getattr(mymodule,‘test‘) # p()
# 2.在本模塊中應用反射 def demo1(): print(‘wwww‘) import sys # print(sys.modules) module_obj = sys.modules[__name__] #相當於‘__main__‘ print(module_obj) print(hasattr(module_obj,‘demo1‘)) getattr(module_obj,‘demo1‘)()
# 舉例 def 註冊(): print(‘regiester‘) def 登錄(): print(‘login‘) def 購物(): pass print(‘註冊,登錄,購物‘) ret = input(‘請輸入你要做的操作:‘) import sys my_module = sys.modules[__name__] #利用sys模塊導入一個自己的模塊 if hasattr(my_module,ret): getattr(my_module,ret)()
三、內置方法
1.__str__和__repr__
改變對象的字符串顯示
# __str__和__repr__ class Foo: def __init__(self,name): self.name = name def __repr__(self): return ‘obj in str‘ #這裏只能是return # def __str__(self): # return ‘%s obj in str‘%self.name f = Foo(‘egon‘) print(f) #優先執行__str__裏面的內容 # 那麽你是不是據地__repr__沒用呢? # print(‘%s‘%f) #執行的是__str__裏面的返回值 # print(‘%r‘%f) #執行的是__repr__裏面的返回值 print(‘==============‘) print(str(f)) #當執行str(f)時,會去找__str__這個方法,如果找不到的時候,__repr__這個方法就給替補了 print(repr(f)) #1.當打印一個對象的時候,如果實現了__str__方法,打印__str__中的返回值 # 2.當__str__沒有被實現的時候,就會調用__repr__方法 # 3.但是當你用字符串格式化的時候,%s和%r會分別調用__str__和__repr__方法 # 4.不管是在字符串格式化的時候還是在打印對象的時候, # __repr__方法都可以作為__str__方法的替補,但反之則不行 # 5.用於友好的表示對象。如果__str__和__repr__方法你只能實現一個:先實現__repr__
2.__del__
析構方法,當對象在內存中被釋放時,自動觸發執行。
註:此方法一般無須定義,因為Python是一門高級語言,程序員在使用時無需關心內存的分配和釋放,因為此工作都是交給Python解釋器來執行,所以,析構函數的調用是由解釋器在進行垃圾回收時自動觸發執行的。
class Foo: def __del__(self): print(‘執行我啦‘) f= Foo() print(123) print(123) print(123) print(123)
3.item系列
分別有__getitem__ ,__setitem__ ,__delitem__
class Foo: def __init__(self): self.name = ‘egon‘ self.age = 73 self.l=[1,2,3] def __getitem__(self, item): #得到 # return self.l[item] # return self.__dict__[item] # print(Foo.__dict__) return 123 def __setitem__(self, key, value): #修改 print(key,value) self.__dict__[key] = value def __delitem__(self, key): #刪除 del self.__dict__[key] f = Foo() print(f[‘qqq‘]) #不管裏面放的啥值,它都會得到返回值的內容,調用的是__getitem__方法 f[‘name‘]=‘alex‘ #修改egon的值為alex,調用 __setitem__方法 # del f[‘name‘] #刪除name,就會報錯了,說明在調用__delitem__方法調用成功了,就已經刪了,就會報錯了 print(f.name) f1 = Foo() print(f == f1) # print(f.name) # print(f[0]) #一開始不能這樣取值,但是提供了一個__getitem__方法,這樣就可以用了 # print(f[1]) # print(f[2])
4.__new__(創建)
# 單例模式 # 4.__new__方法 # 單例模式:是一種設計模式 class Singleton: def __new__(cls, *args, **kw): if not hasattr(cls, ‘_instance‘): orig = super(Singleton, cls) cls._instance = orig.__new__(cls, *args, **kw) return cls._instance one = Singleton() two = Singleton() print(one,two) #他們兩個的地址一樣 one.name = ‘alex‘ print(two.name)
#__new__
# class A: # def __init__(self): #有一個方法在幫你創造self # print(‘in init function‘) # self.x = 1 # # def __new__(cls, *args, **kwargs): # print(‘in new function‘) # return object.__new__(A, *args, **kwargs) # a = A() # b = A() # c = A() # d = A() # print(a,b,c,d)
5.__call__
對象後面加括號,觸發執行
註:構造方法的執行是由創建對象觸發的,即:對象 = 類名() ;而對於 __call__ 方法的執行是由對象後加括號觸發的,即:對象() 或者 類()()
class Foo: def __call__(self, *args, **kwargs): print(123) # f = Foo() # f() #如果不寫上面的__call__方法,就不會調用。如果加上,就正確了 Foo()() #也可以這樣表示
6.__len__
7.__hash__
class Foo:
def __hash__(self):
print(‘aaaaaaaaaa‘)
return hash(self.name)
# print(‘aaas‘)
f = Foo()
f.name = ‘egon‘
print(hash(f)) #hash方法是可以重寫的
8.__eq__
class A:
def __eq__(self, other):
return True
a = A()
b = A()
print(a==b) #不加方法的時候返回的是False,加了個__eq__方法就返回了個True
# ‘==‘內部就調用了__eq__方法
print(a is b)
一道面試題
# 紙牌遊戲 from collections import namedtuple Card = namedtuple(‘Card‘,[‘rank‘,‘suit‘]) #兩個屬性:一個是數,一個是花色(每一個card的對象就是一張紙牌) class FranchDeck: #紙牌數據類型 ranks = [str(n) for n in range(2,11)] + list(‘JQKA‘) suits = [‘紅心‘,‘方板‘,‘梅花‘,‘黑桃‘] def __init__(self): self._cards = [Card(rank,suit) for rank in FranchDeck.ranks #先循環這個,在循環下面的那個循環 for suit in FranchDeck.suits] def __len__(self): return len(self._cards) def __getitem__(self, item): return self._cards[item] def __setitem__(self, key, value): self._cards[key] = value deck = FranchDeck() # print(deck[0]) # print(deck[0]) # print(deck[0]) # print(deck[0]) from random import choice print(choice(deck)) print(choice(deck)) from random import shuffle shuffle(deck) print(deck[:5])
python全棧開發【第十七篇】面向對象反射和內置方法