概覽:
類成員之字段:
-普通字段,保存在對象中,執行職能通過對象訪問
-靜態字段,保存在類中,執行可以通過對象訪問,也可以通過類訪問
類成員之方法:
-普通方法,保存在類中,由對象來調用,self->對象
-靜態方法,保存在類中,由類直接調用
-類方法,保存在類中,由類直接調用,cl->s當前類
應用場景:
如果對象中需要保存一些值,執行某功能時,需要使用對象中的值-->普通方法
不需要任何對象中的值-->靜態方法
類成員之屬性:property
1.類成員之字段
class Province: country = '中國'#靜態字段,屬於類,跟對象沒有關系,從上之下執行 def __init__(self,name): self.name=name#普通字段,屬於對象,通過對象訪問 # sef.country='中國' henna=Province('河南') hebei=Province('河北') print(hebei.country) #中國 print(Province.country) #中國 print(hebei.name) #河北
靜態字段在內存中只保存一份
普通字段在每個對象中都要保存一份
應用場景: 通過類創建對象時,如果每個對象都具有相同的字段,那么就使用靜態字段
2.方法
class Bar: def __init__(self,name,age):#self=z,name=greg,age=84 self.n=name self.a=age def foo(self): print(self.n,self.a) z=Bar('greg',25) print(z.a) z.foo()
創建方法
構造方法,__init__(self,arg)
obj = 類('a1')
普通方法
obj = 類(‘xxx’)
obj.普通方法名()
構造方法不同於其它方法之處在於:當一個對象被創建時,會立即調用構造方法,而且可以繼承。
# -*- coding: utf-8 -*- # 2017/12/3 13:50 class Foo: def bar(self):#self是對象 print('bar') print(self)#<__main__.Foo object at 0x000001E82A4D13C8> @staticmethod def sta(): print('123') @staticmethod def stas(a1,a2):#靜態方法self不必須 print(a1,a2) @classmethod def classmd(cls):#cls是類名 print('classmd') print(cls) #<class '__main__.Foo'> #普通方法 obj=Foo() obj.bar() #bar Foo.bar(obj ) #bar #靜態方法 obj.sta() #123 obj.classmd() Foo.sta() #123 Foo.stas(1,2) #1,2 Foo.classmd() """ bar <__main__.Foo object at 0x000001C83C765390> bar <__main__.Foo object at 0x000001C83C765390> 123 classmd <class '__main__.Foo'> 123 1 2 classmd <class '__main__.Foo'> """
普通方法:可以在實例化后直接調用,由對象調用;至少一個self參數;執行普通方法時,自動將調用該方法的對象賦值給self,self.調用實例變量或類變量
類方法:由類調用; 實例也可調用,至少一個cls參數;執行類方法時,自動將調用該方法的類復制給cls;類方法和普通方法的區別是, 類方法只能訪問類變量,不能訪問實例變量
靜態方法:由類調用;實例也可調用,無默認參數;不可以訪問實例變量或類變量的,一個不能訪問實例變量和類變量的方法,其實相當於跟類本身已經沒什么關系了,它與類唯一的關聯就是需要通過類名來調用這個方法
類變量定義在類的定義之后,實例變量則是以為self.開頭,實例也能夠訪問類變量
class Foo(object): val = 0 valu=2 def __init__(self): self.val = 1 if __name__ == '__main__': foo = Foo() print(foo.val)#1 print(foo.valu)#2 print( Foo.val)#0
沒有init方式時
class Foo(object): val = 0 def __init__(self): pass if __name__ == '__main__': foo = Foo() print(foo.val)#0 print( Foo.val)#0
還可以通過以下方式訪問類變量
class Foo(object): val = 3 def __init__(self): print(self.__class__.val) if __name__ == '__main__': foo = Foo() #3
類方法可以訪問類變量
class Foo(object): val = 3 def __init__(self): pass @classmethod def echo(cls): print(cls.val) if __name__ == '__main__': Foo.echo()#3
3.屬性
新式類中的屬性有三種訪問方式,並分別對應了三個被@property、@方法名.setter、@方法名.deleter修飾的方法
分別將三個方法定義為對同一個屬性:獲取、修改、刪除
class Foo: def __init__(self): self.name='a' self.name_list=['greg'] def bar(self): print('bar') @property #屬性 def per(self): # print('124') del self.name_list[0] print(self.name_list) return 123 @per.setter def per(self,val): print(val) @per.deleter def per(self): print(666) obj=Foo() obj.bar() #bar r=obj.per #[] print(r) #123 obj.per=345 #345 del obj.per #666
property的構造方法中有個四個參數,分別叫做:fget,fset,fdel ,doc
如果沒有參數,產生的屬性既不可讀,也不可寫
如果有一個參數,說明是取值方法,產生的屬性是只讀的。
第一個參數是方法名,調用 對象.屬性 時自動觸發執行方法
第二個參數是方法名,調用 對象.屬性 = XXX 時自動觸發執行方法
第三個參數是方法名,調用 del 對象.屬性 時自動觸發執行方法,用於刪除特性的方法
第四個參數是字符串,調用 對象.屬性.__doc__ ,此參數是該屬性的描述信息,即文檔字符串
class Foo: def f1(self): return 123 def f2(self,v): print(v) def f3(self): print('del') # per=property(fget=f1)#等同於下面三句 # @property # def per(self): # return 123 per = property(fget=f1,fset=f2,fdel=f3,doc='f4') obj=Foo() ret=obj.per print(ret) obj.per=12345 del obj.per # print(obj.per.__doc__)
4.類的私有(private)特性
為了讓方法或者特性變為 私有(從外部無法訪問),只要在它的名字前面加上雙下划線即可。
- 公有成員,在任何地方都能訪問
- 私有成員,只有在類的內部才能方法
class Secretive: def __inaccessible(self): print("你看不到我") def accessible(self): print("密碼是:") self.__inaccessible() s=Secretive() # s.__inaccessible() #AttributeError: 'Secretive' object has no attribute '__inaccessible' s.accessible() # 密碼是: # 你看不到我
非要訪問私有屬性的話,可以通過 對象._類__屬性名,比如Secretive._Secretive.__inaccessible
特殊成員
__init__() 構造方法 類()自動執行
__call__() 對象() 類()()自動執行
構造方法的執行是由創建對象觸發的,即:對象 = 類名() ;而對於 __call__ 方法的執行是由對象后加括號觸發的,即:對象() 或者 類()()
class Foo: def __init__(self): print('__init__') def __call__(self, *args, **kwargs): print('__call__') obj = Foo() # 執行 __init__ obj() # 執行 __call__
__str__ str()
class Foo: def __init__(self,n,a): self.name=n self.age=a def __str__(self): return '%s-%s'%(self.name,self.age) obj=Foo('greg',89) print(obj) #print(str(obj)) str(obj)
__int__ int(對象)
class Foo: def __init__(self): pass def __int__(self): return 1111 def __str__(self): return 'greg' obj=Foo() print(obj,type(obj)) #int,對象,自動執行對象的__init__方法,並將返回值賦值給int對象 r=int(obj) print(r) i=str(obj) print(i)
__add__
class Foo: def __init__(self,name,age): self.name=name self.age=age def __add__(self, other): self=obj1 other=obj2 # return self.age+other.age#37 <class 'int'> return Foo('tt',99)#<__main__.Foo object at 0x0000017B7E2FC9B0> <class '__main__.Foo'> obj1=Foo('greg',19) obj2=Foo('gregory',18) r=obj1+obj2#兩個對象相加時,自動執行第一個對象的__add__, # 並且將第二個對象當做參數傳遞 print(r,type(r))
__dict__ 將對象中封裝的所有內容通過字典的形式返回
class Foo: def __init__(self,name,age): self.name=name self.age=age def show(self): return "%s-%s"%(self.name,self.age) obj=Foo('greg',18) print(obj.name) #greg b="name" print(obj.__dict__) #{'name': 'greg', 'age': 18} print(obj.__dict__['name'])#greg print(obj.__dict__[b])#greg
__getitem__切片(slice類型)或者索引,返回與所給鍵對應的值
__setitem__,按一定的方式存儲於key相關的value
__delitem__,刪除和key相關的鍵
class Foo(object): def __getitem__(self, key): print('__getitem__', key) def __setitem__(self, key, value): print('__setitem__', key, value) def __delitem__(self, key): print('__delitem__', key) obj = Foo() result = obj['k1'] # 自動觸發執行 __getitem__,輸出__getitem__ k1 obj['k2'] = 'greg' # 自動觸發執行 __setitem__,輸出__setitem__ k2 greg del obj['k1'] # 自動觸發執行 __delitem__,輸出__delitem__ k1
__iter__
# 如果類中有 __iter__ 方法,對象=》可迭代對象
# 對象.__iter__() 的返回值: 迭代器
# for 循環,迭代器,next
# for 循環,可迭代對象,對象.__iter__(),迭代器,next
# 1、執行li對象的類F類中的 __iter__方法,並獲取其返回值
# 2、循環上一步中返回的對象
class Foo: def __init__(self,name,age): self.name=name self.age=age def __iter__(self): return iter([11,22,33]) li=Foo('greg',18) #如果類中由__iter__方法,對象—》可迭代對象 #執行li對象的類Foo類中的__iter__方法 #循環上一步中的返回的對象 for i in li: print(i)
__doc__
class Foo: '描述' """ 描述類信息 """ def func(self): pass print(Foo.__doc__) #輸出:描述
__module__ 和 __class__
__module__ 表示當前操作的對象在那個模塊
__class__ 表示當前操作的對象的類是什么
from A.B import C obj = C() print obj.__module__ # 輸出A.B,即:輸出模塊 print obj.__class__ # 輸出 A.B.C,即:輸出類
__new__ 和 __metaclass__
class Foo: def func(self): print(123) return 1 def function(self): print(123) obj=Foo() print(type(obj))#<class '__main__.Foo'> print(type(Foo))#<class 'type'> #obj對象是Foo類的一個實例,Foo類對象是 type 類的一個實例,即:Foo類對象 是通過type類的構造方法創建 Foo2=type('Foo2',(object,),{'func2':function})#聲明一個類 obj2=Foo2() obj2.func2() #type第一個參數:類名,type第二個參數:當前類的基類,type第三個參數:類的成員

1 def func(self): 2 print("hello %s"%self.name) 3 4 def __init__(self,name,age): 5 self.name = name 6 self.age = age 7 Foo = type('Foo',(object,),{'func':func,'__init__':__init__}) 8 9 f = Foo("jack",22) 10 f.func()
類 是由 type 類實例化產生
那么問題來了,類默認是由 type 類實例化產生,type類中如何實現的創建類?類又是如何創建對象?
答:類中有一個屬性 __metaclass__,其用來表示該類由 誰 來實例化創建,所以,我們可以為 __metaclass__ 設置一個type類的派生類,從而查看 類 創建的過程。
class MyType(type): def __init__(self,*args,**kwargs): #self=Foo類 self永遠是類名 print(123) pass def __call__(self, *args, **kwargs): #self=Foo print(456) class Foo(object,metaclass=MyType):#Foo是MyType的對象 def __init__(self): print('Foo') pass def __new__(cls, *args, **kwargs): x=cls return x def func(self): print("hello world") obj=Foo() #加()是執行MyType的call方法,Foo里面要執行,要用call中的方法 #call不會調用Foo中init方法
結果:123
456
單下划線、雙下划線、頭尾雙下划線說明:
-
__foo__: 定義的是特列方法,類似 __init__() 之類的。
-
_foo: 以單下划線開頭的表示的是 protected 類型的變量,即保護類型只能允許其本身與子類進行訪問,不能用於 from module import *
-
__foo: 雙下划線的表示的是私有類型(private)的變量, 只能是允許這個類本身進行訪問了。