在Python的類中,有着類屬性、實例屬性,靜態方法、類方法、實例方法的區別。到底有什麼不同呢?接下來咱們就一探究竟。python
來看下簡單的 Student
類的例子程序員
class Student(object):
# 類屬性
school = '井岡山大學'
def __init__(self, name):
# 實例屬性
self.name = name
複製代碼
其中 school
是 Student
類的類屬性,name
則是實例屬性。編程
在 ipython
中測試一下如何訪問其屬性markdown
In [5]: stu1 = Student('hui')
In [6]: stu2 = Student('wang')
In [7]: stu3 = Student('zack')
In [8]: stu1.name, Student.school
Out[8]: ('hui', '井岡山大學')
In [9]: stu2.name, Student.school
Out[9]: ('wang', '井岡山大學')
In [10]: stu3.name, Student.school
Out[10]: ('zack', '井岡山大學')
# 看看實例對象能不能訪問類屬性,類對象能不能訪問實例屬性
In [11]: stu1.name, stu1.school
Out[11]: ('hui', '井岡山大學')
In [12]: Student.name, stu1.school
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-12-b897e001b174> in <module>
----> 1 Student.name, stu1.school
AttributeError: type object 'Student' has no attribute 'name'
複製代碼
通過測試能夠發現 實例屬性須要經過實例對象來訪問,類屬性經過類來訪問,但在測驗中 stu1.school
實例對象也能訪問類屬性,爲何呢?編程語言
其實,實例對象也是間接的經過類對象進行訪問的,在每個實例對象中都有一個 __class__
的屬性,其指向的就是建立實例對象的類對象。stu1.__class__
的指向就是 Student
類對象。而後實例對象訪問屬性的規則是先訪問實例屬性,而後再根據實例對象的 __class__
來訪問類屬性。若是都沒有找到則報錯。測試
In [15]: dir(stu1)
Out[15]:
['__class__',
'__delattr__',
'__dict__',
'__dir__',
....
'name',
'school']
In [16]: stu1.__class__
Out[16]: __main__.Student
In [17]: stu1.__class__.school
Out[17]: '井岡山大學'
In [18]: id(Student)
Out[18]: 2011692023944
In [19]: id(stu1.__class__)
Out[19]: 2011692023944
複製代碼
能夠看出 Student
,stu1.__class__
的 id()
都同樣,說明其內存地址都同樣。所以實例屬性能夠經過 __class__
訪問類屬性。ui
存儲方式以下圖spa
由上圖能夠看出:code
仍是以上面的例子在 ipython
中對類屬性的修改進行測驗orm
In [24]: class Student(object):
...:
...: # 類屬性
...: school = '井岡山大學'
...:
...: def __init__(self, name):
...:
...: # 實例屬性
...: self.name = name
...:
In [25]: stu1 = Student('hui')
In [26]: stu2 = Student('jack')
In [27]: stu1.name, stu1.school
Out[27]: ('hui', '井岡山大學')
In [28]: stu2.name, stu2.school
Out[28]: ('jack', '井岡山大學')
# 經過類對象進行修改
In [29]: Student.school = '清華大學'
In [30]: stu2.name, stu2.school
Out[30]: ('jack', '清華大學')
In [31]: stu1.name, stu1.school
Out[31]: ('hui', '清華大學')
# 經過實例對象進行修改
IIn [33]: stu1.school = '北京大學'
In [34]: stu1.name, stu1.school
Out[34]: ('hui', '北京大學')
In [35]: stu2.name, stu2.school
Out[35]: ('jack', '清華大學')
In [36]: Student.school
Out[36]: '清華大學'
In [37]: stu1.__class__.school
Out[37]: '清華大學'
In [39]: id(stu2.school)
Out[39]: 2011720409808
In [40]: id(Student.school)
Out[40]: 2011720409808
In [41]: id(stu1.school)
Out[41]: 2011720494992
# 經過實例對象的__class__屬性修改
IIn [42]: stu2.__class__.school = '井岡山大學'
In [43]: stu1.name, stu1.school
Out[43]: ('hui', '北京大學')
In [44]: stu2.name, stu2.school
Out[44]: ('jack', '井岡山大學')
In [45]: Student.school
Out[45]: '井岡山大學'
複製代碼
說明: 實例對象.類屬性 = xxx 並無修改到其類屬性,而是在實例對象中建立了一個與類屬性同名的實例屬性。所以修改類屬性,應該使用類對象進行修改。再外界最好不要使用 實例對象.新屬性 = xxx,動態建立實例屬性。
究竟是用類屬性,仍是實例屬性?
若是每一個實例對象須要具備相同值的屬性,那麼就使用類屬性,用一份既可。
class Province(object):
# 類屬性
country = '中國'
def __init__(self, name):
# 實例屬性
self.name = name
p1 = Province('江西省')
p2 = Province('四川省')
複製代碼
類中方法包括:實例方法、靜態方法和類方法,三種方法在內存中都歸屬於類,區別在於調用方式不一樣。
self
參數;執行實例方法時,自動將調用該方法的對象賦值給 self
。cls
參數;執行類方法時,自動將調用該方法的類賦值給 cls
。class Foo(object):
foo = 'Foo'
def __init__(self, name):
self.name = name
def instance_func(self):
print(self.name)
print(self.foo)
print('實例方法')
@classmethod
def class_func1(cls):
print(cls.foo)
print('類方法1')
@classmethod
def class_func2(cls):
print(cls.name)
print('類方法二')
@staticmethod
def static_func():
print('靜態方法')
複製代碼
其中 @classmethod
是裝飾器,說明這是類方法,@staticmethod
則說明是靜態方法。關於裝飾器的內容這裏就不在贅述了。
在 ipython
中測驗一下各方法
# 實例對象調用
In [71]: f = Foo('hui')
In [72]: f.instance_func()
hui
Foo
實例方法
In [73]: f.class_func1()
Foo
類方法1
In [74]: f.class_func2()
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-74-7d161e9e60ec> in <module>
----> 1 f.class_func2()
<ipython-input-60-7fc48649a96a> in class_func2(cls)
18 @classmethod
19 def class_func2(cls):
---> 20 print(cls.name)
21 print('類方法二')
22
AttributeError: type object 'Foo' has no attribute 'name'
In [75]: f.static_func()
靜態方法
# 類對象自身調用
In [76]: Foo.instance_func()
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-76-883efcb56130> in <module>
----> 1 Foo.instance_func()
TypeError: instance_func() missing 1 required positional argument: 'self'
In [77]: Foo.class_func1()
Foo
類方法1
In [78]: Foo.static_func()
靜態方法
複製代碼
能夠發現實例對象三種方法均可以調用,但 cls
類對象不能訪問實例屬性。類對象不能直接調用實例方法,類、靜態方法能夠。
self
指的是類實例對象自己(注意:不是類自己)。cls
指的是類對象自己self
能夠訪問到類屬性、實例屬性,cls
只能訪問類屬性。其中 self, cls
只是代指實例對象和類對象,所以換成其餘變量也能夠,可是約定成俗(爲了和其餘編程語言統一,減小理解難度),不要搞另類,你們會不明白的。
須要操做類屬性的定義成類方法。
須要操做實例屬性的定義成實例方法。
既不須要操做類屬性,也不須要操做實例屬性就定義成靜態方法。
新建文件夾X
大天然用數百億年創造出咱們現實世界,而程序員用幾百年創造出一個徹底不一樣的虛擬世界。咱們用鍵盤敲出一磚一瓦,用大腦構建一切。人們把1000視爲權威,咱們反其道行之,捍衛1024的地位。咱們不是鍵盤俠,咱們只是平凡世界中不凡的締造者 。