在python中,定義了結構之後就産生了相應的命名空間,對類和函數的定義都會形成相應的命名空間。但是在兩者的命名空間中有個差别值得我們關注,尤其在定義類中的函數時應該注意類命名空間的特性。
定義函數時産生的命名空間
定義一個簡單函數:
def foo():
a =
b =
c =
d = a + b + c
print(d)
調用這個函數:
In []: foo()
在我們定義的函數foo中,變量a,b,c,d都屬于同一個命名空間,是以它們各自的作用域都會擴充到整個函數的命名空間,d可以直接通路a,b,c。
定義類時産生的命名空間
我們再來定義一個類:
class A:
a =
b =
c =
def foo(self):
d = a + b + c
print(d)
我們對A執行個體化之後調用其中的foo函數:
In []: a = A()
In []: a.foo()
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
<ipython-input--ae930c5e3b4a> in <module>()
----> a.foo()
<ipython-input--eb5cb5b2468> in foo(self)
c =
def foo(self):
----> d = a + b + c
print(d)
NameError: name 'b' is not defined
報錯,明明a,b,c和foo都在同一個命名空間,但是在foo中不能解析變量a,b,c指向的對象(python中一切都是對象,程式中存儲的所有資料都是對象)。和公共命名空間及函數定義形成的命名空間中的規則不同。
In []: a =
In []: def foo():
...: b =
...: print(b)
In []: foo()
In []: def foo():
...: a =
...: def inner():
...: b = a
...: print(b)
...: return inner()
In []: foo()
上面的例子說明在公共命名空間和定義函數形成的命名空間中,引用處于同一命名空間的變量時隻需要直接寫出變量名就可以了。
那麼我們應該怎麼去引用類中的屬性呢?有兩種方式:類名.屬性名和self.屬性名
重新改寫類A的定義:
class A:
a =
b =
def foo(self):
c = self.a + self.b
print(c)
a = A()
用a調用foo:
In []: a.foo()
用self.變量名引用類中的變量有個問題,就是這些變量和對象執行個體有關,而不是和類有關。看個例子:
class A:
a =
def foo():
b = self.a
print(b)
A中的屬性foo不是方法而是普通函數,我們需要通過類名來調用:
In []: A.foo()
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
<ipython-input--cb0580e7a09> in <module>()
----> A.foo()
<ipython-input--d314e2303> in foo()
a =
def foo():
----> b = self.a
print(b)
NameError: name 'self' is not defined
因為沒有對A執行個體化,是以self.變量名的方式行不通。
再來看個例子:
class A:
count =
def __init__(self):
self.count +=
@classmethod
def countTheInitNum(cls):
print(self.count)
a = A()
b = A()
我們希望A的類方法countTheInitNum可以記錄A的執行個體化對象數量。現在有a和b兩個執行個體化對象,countTheInitNum應該輸出2才對,我們來試試:
In []: a.countTheInitNum()
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
<ipython-input--ab33913b354f> in <module>()
----> a.countTheInitNum()
<ipython-input--e0179896d160> in countTheInitNum(cls)
@classmethod
def countTheInitNum(cls):
----> print(self.count)
a = A()
b = A()
NameError: name 'self' is not defined
因為countTheInitNum是類方法,是以它是跟A綁定的,a.countTheInitNum就相當于A.countTheInitNum。
In []: A.countTheInitNum
Out[]: <bound method A.countTheInitNum of <class '__main__.A'>>
類方法是和類綁定的,類的執行個體方法是和執行個體綁定的。
我們改寫一下A:
class A:
count =
def __init__(self):
A.count +=
@classmethod
def countTheInitNum(cls):
print(A.count)
a = A()
b = A()
c = A()
調用A的類方法countTheInitNum:
In []: A.countTheInitNum()
這次A的類方法countTheInitNum輸出了正确的A類的執行個體化次數。
涉及到的幾個概念
- 命名空間
- 類方法
- 類的執行個體化
- 綁定方法
- 非綁定方法