類的成員-反射-雙下方法
類的私有成員:
私有成員只是做了一個簡單是變相加密,直接訪問不了
1.私有靜態屬性
在變量名前加 __ 可以在本類的內部訪問,在類的外部和派生類中無法訪問
class A: country = ‘中國‘ __country = ‘加拿大‘ # 私有靜態屬性 def func(self): print(A.country) print(A.__country) class B(A): def func1(self): print(super().country) obj = A()# 在類的內部訪問: 可以 obj.func() # 類的外部訪問: 不可以 print(A.__country) obj.__country # 在派生類訪問: 不可以 obj1 = B() obj1.func1()
2.私有方法
可以在本類的內部訪問,在類的外部和派生類中無法訪問
class A: def __f1(self): print(‘in A f1‘) def func(self): self.__f1() class B(A): def f1(self): super().__f1() obj= A() # 類內部可以訪問 obj.func() # 類外部不可以訪問 obj.__f1() # 類的派生類: 不可以訪問 b = B() b.f1()
3.私有對象屬性
class A: def __init__(self,name,age): self.name = name self.__age = age def func(self): print(self.__age) obj = A(‘靜哥‘,24) #類內部可以訪問: obj.func() #類的外部不能訪問: print(obj.__age)#派生類也不能訪問
什麽時候使用私有成員:
密碼,年齡,個人信息,只是類內部使用的方法等,需要設置私有成員
類的其他成員
1)類方法:
@classmethod
通過類名調用的方法,第一個參數主動接收類名,為了區分,參數名為cls
對象也可以調用類方法,傳給cls的參數也是類空間(一般不這麽用)
主動接收類名,與類的靜態屬性相關的需求,與對象無關的功能需要類方法
class Student: stu_num = 0 def __init__(self,name,age): self.name = name self.__age = age Student.calc_num() # 應該放在__new__裏面 @classmethod def calc_num(cls): cls.stu_num += 1 @classmethod def get_num(cls): return cls.stu_num denge = Student(‘鄧哥‘,18) jinge = Student(‘靜哥‘,18) print(Student.get_num()) 結果: 2
2)靜態方法
@staticmethod
不依賴與類以及對象的方法,是函數
靜態方法雖然不依賴與對象,類,但是為了保持代碼的整體性和一致性,才將其設置為靜態方法,而不是放在類外面當普通函數用
class A: def __init__(self,name,age): # 雙下方法 特殊方法 self.name = name self.__age = age def func(self): # 實例方法:通常是通過對象去調用的方法,主動將對象傳給self print(‘in func‘) @classmethod def func1(cls): # 類方法: 是通過類名調用的方法,第一個參數主動接受類名 print(‘類方法‘) @staticmethod # 靜態方法:不依賴於類以及對象的方法,是函數. def func2(): pass
3)屬性
@property
將方法偽裝成屬性,雖然在代碼邏輯上沒有提升,但是看起來更合理
class Bmi: def __init__(self,name,weight,height): self.name = name self.__weight = weight self.height = height @property def bmi(self): return self.__weight/(self.height**2) obj = Bmi(‘hu‘,75,1.75) print(obj.bmi) #bmi本身是一個方法,通過@property裝飾器之後,直接用調用屬性的方式進行打印就可以
另外有更改和刪除的方法:
class A: @property def AAA(self): print(‘調用屬性‘) @AAA.setter def AAA(self,new): #更改屬性時要傳參 print(‘更改屬性‘) @AAA.deleter def AAA(self): print(‘刪除屬性‘) obj = A() # obj.AAA #調用 # obj.AAA = 111 #更改 # del obj.AAA #刪除
####練習: class Goods: def __init__(self,name,money,sale): self.name = name self.money = money self.sale = sale @property def price(self): return self.money*self.sale @price.setter def price(self,new): self.money = new / self.sale apple = Goods(‘蘋果‘,5,0.9) #計算現價 # print(apple.price) #要求改過之後的價格為10 apple.price = 10 print(apple.price)
源碼見的最多的是 property
對象自己的屬性 如果與類的偽裝的屬性重名時,對對象屬性進行修改時,則只會執行@setter方法
為了避免這個坑,給對象設置的屬性名,不要與property偽裝的屬性名重名
4)isinstance issubclass
isinstance(o,a) 判斷o是否是a或者a的派生類的對象
class A: pass class B(A): pass obj = B() print(isinstance(obj,B)) #True print(isinstance(obj,A)) #True
issubclass(a,b) 判斷a是否是b的子類或孫類
class A: pass class B(A): pass class C(B): pass print(issubclass(B,A)) #True print(issubclass(C,A)) #True
list str等這些可叠代對象與 Iterable是什麽關系?
from collections import Iterable l1 = [1,2,3] print(isinstance(l1,Iterable)) # l1是Iterable(派生類)的實例的對象
list類與Iterable類是什麽關系?
print(issubclass(list,Iterable)) # list是Iterable的派生類
元類
python 一切皆對象原則
類也是對象
type 元類,也叫構建類,產出了python中大量的內置類(str,list...)以及自建類
反射
通過字符串對對象進行相應的操作(對象:實例化對象 類 其他模塊 本模塊)
hasattr() 判斷有沒有
getattr() 取值
setattr() 設置(增)
delattr() 刪除
class A: country = ‘中國‘ def __init__(self,name,age): self.name = name self.age = age def func(self): print(‘in A func‘) obj = A(‘棍哥‘,20) print(hasattr(obj,‘name‘)) #判斷有沒有‘name‘屬性 print(getattr(obj,‘name‘)) #取‘name‘的值 setattr(obj,‘height‘,180) #增加‘height‘ print(obj.__dict__) delattr(obj,‘age‘) #刪除‘age‘ print(obj.__dict__)
註意事項:
反射只能用在都可以通過 . 去操作的對象
class User: def login(self): print(‘歡迎來到登錄頁面‘) def register(self): print(‘歡迎來到註冊頁面‘) def save(self): print(‘歡迎來到存儲頁面‘) while 1: choose = input(‘請輸入‘).strip() obj = User() if hasattr(obj,choose): getattr(obj,choose)()
判斷函數與方法:
def func(): pass class A: def func1(self): pass #1.通過打印名字的方式判斷 print(func) #函數 print(A.func1) #函數 obj = A() print(obj.func1) #方法 #2.通過引用模塊 from types import FunctionType 函數 from types import Methodtype 方法 print(isinstance(func,FunctionType)) # True print(isinstance(A.func1,FunctionType)) # True print(isinstance(obj.func1,FunctionType)) # Flase print(isinstance(obj.func1,MethodType)) # True
之前學的函數就是函數
通過類名調用,就是函數
通過實例調用,就是方法
類中的靜態方法是函數
類中的類方法,是方法
函數與方法的區別:
函數是顯性傳參,不依賴於對象
方法是隱形傳參(默認接收對象空間或者類空間),依賴對象,類
特殊的雙下方法
解釋器提供的,由__方法名__的具有特殊意義的方法,主要是python源碼程序員使用的元編程,開發中盡量不使用
__init__ 類名()觸發
1)len ****
一個實例能否使用len操作,完全取決於它的類中有沒有__len__方法
class A: def __init__(self,name,age,sex,weight): self.name = name self.age = age self.sex = sex self.weight = weight def __len__(self): print(666) return len(self.__dict__) obj = A(‘劉姐‘,18, ‘女‘,100) len(obj) # 只要對對象len() 就會觸發對象從屬於的類中的 __len__ print(len(obj))
結果:
666
666
4
2)__hash__
class A: def __init__(self): pass def __hash__(self): return 666 obj = A() print(hash(obj)) #觸發__hash__方法
3)__str__
class A: def __init__(self,name,age): self.name = name self.age = age def __str__(self): return str(self.__dict__) obj = A(‘alex‘,73) print(obj) 結果: {‘name‘: ‘alex‘, ‘age‘: 73}
4)__repr__
class A: def __repr__(self): return ‘alex‘ obj = A() print(repr(obj)) 結果: alex
5)_call__: 對象() 執行 __call__方法 *****
class A: def __init__(self): print(111) def __call__(self, *args, **kwargs): print(666) obj = A() #觸發__init__方法 obj() #觸發__call__方法
6)__eq__
class A: def __init__(self): self.a = 1 self.b = 2 def __eq__(self,obj): print(666) a = A() b = A() print(a == b) # 同一個類的兩個實例進行比較就會觸發類中 __eq__方法 結果: 666 None
6)__del__ 析構方法
class A: def __del__(self): print(666) obj = A() 結果: 666
7)__new__ 構造方法 ***
類名() 調用__new__方法
class A: def __init__(self,name,age): self.name = name self.age = age print(111) def __new__(cls, *args, **kwargs): print(222) return object.__new__(cls) obj = A(‘barry‘,18) 結果: 222 111
單例模式 規定一個類只能實例化一個對象(面試題)
class A: pass ret = A() print(ret) ret = A() print(ret) ret = A() print(ret) #以上三個ret內存地址是不同的
class A: __instance = None def __new__(cls, *args, **kwargs): if not cls.__instance: obj = object.__new__(cls) cls.__instance = obj return cls.__instance ret = A() print(ret) ret = A() print(ret) ret = A() print(ret) #以上三個ret內存地址是一樣的
8)__item__: *****
對對象進行類似於字典的操作的時候,就會觸發相應的方法.
class Foo: def __init__(self,name): self.name=name def __getitem__(self, item): return self.__dict__[item] def __setitem__(self, key, value): # print(key,value) self.__dict__[key]=value def __delitem__(self, key): print(key) print(‘del obj[key]時,我執行‘) self.__dict__.pop(key) def __delattr__(self, item): print(‘del obj.key時,我執行‘) self.__dict__.pop(item) f = Foo(‘alexsb‘) print(f[‘name‘]) print(f.__dict__) f[‘name‘] = ‘sb‘ # 觸發 __setitem__方法 print(f.__dict__) del f[‘name‘] 結果: alexsb {‘name‘: ‘alexsb‘} {‘name‘: ‘sb‘} name del obj[key]時,我執行
9)上下文管理
class A: def __init__(self, text): self.text = text def __enter__(self): # 開啟上下文管理器對象時觸發此方法 self.text = self.text + ‘您來啦‘ return self # 將實例化的對象返回f1 def __exit__(self, exc_type, exc_val, exc_tb): # 執行完上下文管理器對象f1時觸發此方法 self.text = self.text + ‘這就走啦‘ f1 = A(‘大爺‘) # print(f1.text) with A(‘大爺‘) as f1: print(f1.text) print(f1.text) 結果: 大爺您來啦 大爺您來啦這就走啦
類的成員-反射-雙下方法