isinstance() 判斷isinstance(obj,cls)中obj是否是cls類的對象 issubclass() 判斷issubclass(sub,super)中sub是否是super類的派生類 反射 反射就是用字元串類型的名字去操作變數,python中的一切事物皆為對象(都可以使用反射) ...
isinstance()
判斷isinstance(obj,cls)中obj是否是cls類的對象
class Person: def __init__(self,name): self.name = name p = Person('Jane') print(isinstance(p,Person)) #True
issubclass()
判斷issubclass(sub,super)中sub是否是super類的派生類
class Person: def __init__(self,name): self.name = name class Father(Person): pass print(issubclass(Father,Person)) #True print(issubclass(Person,Father)) #False
反射
反射就是用字元串類型的名字去操作變數,python中的一切事物皆為對象(都可以使用反射)
1.hasattr()
函數用於判斷對象是否包含對應的屬性,通常和getattr一起搭配使用,先用hasattr判斷是否這個對象含有這個屬性,如果有就通過getattr來拿值,如果沒有就提示沒有這個屬性
class Person: age = 20 def __init__(self,name,height,weight): self.name = name self.height = height self.weight = weight def fuc(self): print('weight...height...') #1 if hasattr(Person,'age'): print(getattr(Person,'age')) #20 else: print('沒有這個類屬性!') #2 p = Person('Adson',1.6,75) if hasattr(p,'bmi'): print(getattr(p,'bmi')) else: print('沒有這個屬性!') #沒有這個屬性! #3 if hasattr(p,'fuc'): getattr(p,'fuc')() #weight...height... else: print('沒有這個方法!')
2.getattr()
函數用於返回一個對象屬性值
(1)反射對象的屬性
class A: def __init__(self,name): self.name = name a = A('Adson') ret = getattr(a,'name') print(ret) #Adson
(2)反射對象的方法
class A: def fuc(self): print('This is fuc!') a = A() ret = getattr(a,'fuc') print(ret) #<bound method A.fuc of <__main__.A object at 0x00000000024E1C88>> 獲得一個綁定方法的地址 ret() #This is fuc! 在ret後加上括弧去調用方法
(3)反射類的屬性
class A: age = 18 ret = getattr(A,'age') print(ret) #18
(4)反射類的方法(classmethod、staticmethod)
一般的調用方式是類名.方法名
class A: @classmethod def fuc(cls): print('This is class fuc!') ret = getattr(A,'fuc') print(ret) #<bound method A.fuc of <class '__main__.A'>> 獲得一個綁定方法 ret() #This is class fuc! getattr(A,'fuc')() #This is class fuc! 簡寫
(5)反射模塊的變數
先建立一個模塊,模塊名pyfile.py,增加一個變數
dic = {'apple' : 18,'banana' : 20}
然後通過我的模塊反射pyfile模塊的變數
import pyfile print(pyfile.dic) #{'apple': 18, 'banana': 20} ret = getattr(pyfile,'dic') print(ret) #{'apple': 18, 'banana': 20}
(6)反射模塊的方法
先建立一個模塊,模塊名pyfile.py,增加一個方法
def fuc(): print('abc123aaa!!!')
然後通過我的模塊反射pyfile模塊方法
import pyfile ret = getattr(pyfile,'fuc') print(ret) #<function fuc at 0x0000000002498D08> ret() #abc123aaa!!! getattr(pyfile,'fuc')() #abc123aaa!!!
(7)反射模塊的類
先建立一個模塊,模塊名pyfile.py,增加一個類
class B: price = 200 def __init__(self,name): self.name = name def fuc(self): print('This classB fuc..' + self.name)
然後通過我的模塊反射pyfile模塊方法
import pyfile b = getattr(pyfile,'B')('Josn') #getattr相當於拿到了這個模塊的B類 併進行實例化了一個b對象 print(b.__dict__) #{'name': 'Josn'} print(b.price) #200 b.fuc() #This classB fuc..Josn
(8)反射自身模塊的變數
通過sys.modules['__main__']找到當前的模塊
import time import sys t = time.asctime(time.localtime(time.time())) print(t) #Mon Sep 9 22:36:40 2019 print(sys.modules['__main__']) #<module '__main__' from 'C:/Users/Administrator/PycharmProjects/PYL/temp_file/temp_py.py'> print(sys.modules['__main__'].t) #Mon Sep 9 22:38:01 2019 ret = getattr(sys.modules['__main__'],'t') print(ret) #Mon Sep 9 22:39:05 2019
(9)反射自身模塊的方法
import sys def fuc(): print('abc123...') ret = getattr(sys.modules['__main__'],'fuc') print(ret) #<function fuc at 0x0000000002798730> ret() #abc123... getattr(sys.modules['__main__'],'fuc')() #abc123...
3.setattr()
用於設置屬性值,該屬性不一定是存在的
class Person: age = 20 def __init__(self,name,height,weight): self.name = name self.height = height self.weight = weight #對一個對象修改 p = Person('Adson',1.6,75) setattr(p,'name','Jane') setattr(p,'height',1.7) setattr(p,'gender','male') print(p.__dict__) #{'name': 'Jane', 'height': 1.7, 'weight': 75, 'gender': 'male'} #對一個類修改 print(Person.__dict__) #{'__module__': '__main__', 'age': 20, '__init__': <function Person.__init__ at 0x0000000002548950>,
'__dict__': <attribute '__dict__' of 'Person' objects>, '__weakref__':
<attribute '__weakref__' of 'Person' objects>, '__doc__': None} setattr(Person,'age',21) setattr(Person,'name','Jane') setattr(Person,'height',1.7) setattr(Person,'gender','male') print(Person.__dict__) #{'__module__': '__main__', 'age': 21, '__init__': <function Person.__init__ at 0x0000000002548950>,
'__dict__': <attribute '__dict__' of 'Person' objects>, '__weakref__':
<attribute '__weakref__' of 'Person' objects>, '__doc__': None,
'name': 'Jane', 'height': 1.7, 'gender': 'male'}
這裡的不同之處在於對象和類它們存放值的命名空間不同
4.delattr()
用於刪除屬性
class Person: age = 20 def __init__(self,name,height,weight): self.name = name self.height = height self.weight = weight p = Person('Adson',1.6,75) print(p.__dict__) #{'name': 'Adson', 'height': 1.6, 'weight': 75} delattr(p,'height') print(p.__dict__) #{'name': 'Adson', 'weight': 75}
print(Person.__dict__['age']) #20 delattr(Person,'age') print(Person.__dict__['age']) #KeyError: 'age'
內置類方法
內置的類方法和內置函數之間有著千絲萬縷的關係
1.__str__
當我們定義一個類,並實例化一個對象,再對這個對象去print
class A: def __init__(self,name,price,types): self.name = name self.price = price self.types = types a = A('AAA',200,'A') print(str(a)) #<__main__.A object at 0x00000000020D7A58>
這裡返回了這個對象的記憶體地址,我們再在A類裡面添加一個__str__方法,看一看結果是什麼
class A: def __init__(self,name,price,types): self.name = name self.price = price self.types = types def __str__(self): return 'name = %s,price = %s,types = %s'%(self.name,self.price,self.types) a = A('AAA',200,'A') print(a) #name = AAA,price = 200,types = A
可以這麼說我們在每次列印一個對象的時候就是在調用obj.__str__,且__str__方法需要返回一個字元串,當做這個類的描寫;當我們使用print這個對象時會列印出__str__方法return出來的字元串
2.__repr__
先說一下repr()方法,它能讓我們輸入的數據原形畢露
print(repr(1)) #1 print(repr('1')) #'1' print(repr('aaa')) #'aaa' print(repr({'a':1,'b':2})) #{'a': 1, 'b': 2}
和__str__一樣我們在定義一個類後去print它實例化的對象,會獲得到一個對象的記憶體地址
class A: def __init__(self,name,price,types): self.name = name self.price = price self.types = types a = A('AAA',200,'A') print(repr(a)) #<__main__.A object at 0x00000000024E7A58>
然後我們再在A中添加__repr__方法看一下print的結果
class A: def __init__(self,name,price,types): self.name = name self.price = price self.types = types def __repr__(self): return 'name = %s,price = %s,types = %s' % (self.name, self.price, self.types) a = A('AAA',200,'A') print(repr(a)) #name = AAA,price = 200,types = A print(a) #name = AAA,price = 200,types = A
因為我們在類中定義了一個__repr__方法,這裡我們print對象a的時候就相當於是調用了裡面的__repr__方法即a.__repr__
如果一個類中的__str__和__repr__同時存在的話,那麼最後的列印結果是什麼呢?
class A: def __init__(self,name,price,types): self.name = name self.price = price self.types = types def __str__(self): return 'str(name = %s,price = %s,types = %s)'%(self.name,self.price,self.types) def __repr__(self): return 'repr(name = %s,price = %s,types = %s)' % (self.name, self.price, self.types) a = A('AAA',200,'A') print(repr(a)) #repr(name = AAA,price = 200,types = A) 即a.__repr__ print('%r'%a) #repr(name = AAA,price = 200,types = A) print(str(a)) #str(name = AAA,price = 200,types = A) 即a.__str__ print('%s'%a) #str(name = AAA,price = 200,types = A) print(a) #str(name = AAA,price = 200,types = A)
如果一個類中有__str__方法,那麼它就會先找__str__,沒有的話就再找__repr__方法,再沒有的話就會找它父類的__str__方法
__str__方法和__repr__方法能夠返回該對象一個規範化的信息
3.__len__
我們將一個實例化的對象直接print它的len看一看會出現什麼結果
class A: def __init__(self,name,price,types): self.name = name self.price = price self.types = types a = A('AAA',200,'A') print(len(a)) #TypeError: object of type 'A' has no len()
結果報錯說A少了一個len函數,也就是我們只有在A中加上一個__len__的方法才能去計算長度相關的東西
計算屬性的長度:
class A: def __init__(self,name,price,types): self.name = name self.price = price self.types = types def __len__(self): return len(self.name) a = A('AAA',200,'A') print(len(a)) #3
計算一個列表屬性有幾個元素:
class A: def __init__(self,goods = []): self.goods = [] def __len__(self): return len(self.goods) a = A() print(len(a)) #0 a.goods.append('Banana') a.goods.append('Apple') a.goods.append('Orange') a.goods.append('Pear') print(len(a)) #4
4.__call__
用於列印這個對象的屬性
class A: gender = 'male' def __init__(self,name,price,types): self.name = name self.price = price self.types = types def __call__(self, *args, **kwargs): return self.name,self.price,self.types,self.gender a = A('AAA',200,'A') print(a()) #('AAA', 200, 'A', 'male') print(A('AAA',200,'A')()) #('AAA', 200, 'A', 'male')
5.__eq__
class A: __instance = False def __init__(self,name,age,height): self.name = name self.age = age self.height = height def __eq__(self, other): if self.name == other.name and self.height == other.height: return True else: return False a1 = A('Jane',20,55) a2 = A('Jane',18,55) print(a1 == a2) #True
6.__hash__
控制對象中的哈希值和另外一個對象的哈希值是否相等
class A: def __init__(self,name,age,height): self.name = name self.age = age self.height = height def __hash__(self): return hash(self.age + self.height) + hash(self.name) a1 = A('Jane',20,55) a2 = A('Jane',18,55) print(hash(a1)) #-1393240518857837779 print(hash(a2)) #-1393240518857837781
7.__new__
創建一個對象
class A: height = 18 def __init__(self): self.name = 'Aane' self.price = 300 self.types = 'aaa' def __new__(cls, *args, **kwargs): print('實例化一個對象...') return object.__new__(cls, *args, **kwargs) a = A() #實例化一個對象... print(a.__dict__) #{'name': 'Aane', 'price': 300, 'types': 'aaa'}
單例模式:限制一個類始終只有一個實例,因為一般來講一個類可以產生無數個對象
在這裡我們創建三個對象並列印它們的記憶體地址可以發現它們是不同的
class A: def __init__(self): self.name = 'aaa' a1 = A() a2 = A() a3 = A() print(a1) #<__main__.A object at 0x00000000025B1D68> print(a2) #<__main__.A object at 0x00000000025CD0F0> print(a3) #<__main__.A object at 0x00000000025CD128>
所以在我們第一次實例化這個類的時候就創建一個實例化的對象,那麼我們再一次實例化一個對象的話該如何再去使用之前的實例化對象呢?
class A: __instance = False def __init__(self,name,age): self.name = name self.age = age def __new__(cls,*args,**kwargs): if cls.__instance: return cls.__instance cls.__instance = object.__new__(A) return cls.__instance a1 = A('Jogn',33) a2 = A('Jane',35) a3 = A('KKK',55) print(a1) #<__main__.A object at 0x000000000217D198> print(a1.__dict__) #{'name': 'KKK', 'age': 55} print(a2) #<__main__.A object at 0x000000000217D198> print(a2.__dict__) #{'name': 'KKK', 'age': 55} print(a3) #<__main__.A object at 0x000000000217D198> print(a3.__dict__) #{'name': 'KKK', 'age': 55} print(id(a1),id(a2),id(a3)) #41734552 41734552 41734552
8.__del__
析構函數:當對象結束其生命周期,如對象所在的函數已調用完畢時,系統自動執行析構函數,它往往用來做"清理善後"的工作。當我們直接刪除一個實例化的對象再去列印它,就會報錯告訴我們這個對象已經不存在了
class A: def __init__(self,name,price,types): self.name = name self.price = price self.types = types a = A('AAA',200,'A') del a print(a) #NameError: name 'a' is not defined
我們再在A中添加一個__del__方法
class A: def __init__(self,name,price,types): self.name = name self.price = price self.types = types def __del__(self): print('這個對象%s已被刪除!' % self.name) del self a = A('AAA',200,'A') del a #這個對象AAA已被刪除! 這裡相當於調用了a.__dict__ print(a) #NameError: name 'a' is not defined
8.__getitem__
模擬字典的方式來拿值
class A: gender = 'male' def __init__(self,name,price,types): self.name = name self.price = price self.types = types def __getitem__(self, item): if hasattr(self,item): return getattr(self,item) return '沒有找到這個值!' a = A('AAA',200,'A') print(a['name']) #AAA print(a['price']) #200 print(a['types']) #A print(a['gender']) #male print(a['sex']) #沒有找到這個值!
9.__setitem__
模擬字典的方式來設值
class A: def __init__(self,name,price,types): self.name = name self.price = price self.types = types def __setitem__(self,key,value): #重新設定一個新的值 self.__dict__['key'] = value a = A('AAA',200,'A') print(a.__dict__) #{'name': 'AAA', 'price': 200, 'types': 'A'} a.__dict__['name'] = 'BBB' a.__dict__['price'] = 300 a.__dict__['types'] = 'C' a.__dict__['gender'] = 'male' #增加了一個新的屬性gender print(a.__dict__) #{'name': 'BBB', 'price': 300, 'types': 'C', 'gender': 'male'}
10.__delitem__
模擬字典的方式來刪除
class A: gender = 'male' def __init__(self,name,price,types): self.name = name self.price = price self.types = types def __delitem__(self, key): print('%s已刪除!'%key) del self.__dict__[key] a = A('AAA',200,'A') del a['name'] #name已刪除! del a['price'] #price已刪除! print(a.__dict__) #{'types': 'A'}
問題總結
1.有很多對象,它們的姓名和性別相同但是年齡不同,如何這種情況的對象去重?
class A: def __init__(self,name,sex,age): self.name = name self.sex = sex self.age =