1.11 函數classmethod()
在Python程式中,函數classmethod()的功能是将函數包裝成類方法。其文法格式如下所示:
classmethod(function)
在Python程式中,經常使用@classmethod修飾符的用法。在聲明一個類方法時,通常使用如下所示的用法:
class C:
@classmethod
def f(cls, arg1, arg2, ...): ...
修飾符@classmethod對應的函數不需要執行個體化,不需要 self 參數,但第一個參數需要是表示自身類的 cls 參數,可以來調用類的屬性,類的方法,執行個體化對象等。@classmethod形式的用法是一個函數裝飾器,用于檢視函數定義中關于函數定義的詳細說明。@classmethod既可以在類上調用(如C.f()),也可以在執行個體上調用(如C().f())。除了執行個體的類,執行個體本身被忽略。如果一個類方法在子類上調用,那麼子類對象被傳遞為隐式的第一個參數。類方法不同于C++或Java中的靜态方法,如果需要靜态方法,請參考本章後面介紹的staticmethod()函數。
在下面的執行個體檔案xiu.py中,示範了使用@classmethod修飾符的過程。
class A(object):
bar = 1
def func1(self):
print('foo')
@classmethod
def func2(cls):
print('func2')
print(cls.bar)
cls().func1() # 調用 foo 方法
A.func2() # 不需要執行個體化
執行後會輸出:
func2
1
foo
在下面的執行個體檔案xiu1.py中,示範了使用修飾符@classmethod修飾指定方法的過程。
class C:
@classmethod
def f(cls, arg1):
print(cls)
print(arg1)
C.f('類對象調用類方法')
c = C()
c.f('類執行個體對象調用類方法')
執行後會輸出:
<class '__main__.C'>
類對象調用類方法
<class '__main__.C'>
類執行個體對象調用類方法
在類中使用修飾符@classmethod後,當類被繼承後,子類也可以調用父類的類方法,但是第一個參數傳入的是子類的類對象。例如下面的執行個體檔案xiu2.py示範了這一用法。
class C:
@classmethod
def f(cls, arg1):
print(cls)
print(arg1)
class D(C):
pass
D.f("子類的類對象調用父類的類方法")
執行後會輸出:
<class '__main__.D'>
子類的類對象調用父類的類方法
1.12 函數compile()
在Python程式中,函數compile()的功能是将一個字元串編譯為位元組代碼。使用函數compile()的文法格式如下所示。
compile(source, filename, mode, flags=0, dont_inherit=False, optimize=-1)
- source:字元串或者AST(Abstract Syntax Trees)對象,函數compile()能夠将source編譯成代碼對象,或者AST(Abstract Syntax Tree,抽象文法樹)對象。代碼對象可以由exec()或eval()執行。源可以是普通字元串,位元組字元串或AST對象。
- filename:代碼檔案名稱,如果不是從檔案讀取代碼則傳遞一些可辨認的值;
- mode:指定編譯代碼的模式,可以指定為 exec、eval、single。如果source由語句序列組成,則它可以是'exec';如果它是單個語句,則可以使用'eval';如果它由單個互動式語句組成,則可以使用'single'。
- flags:變量作用域,局部命名空間,如果被提供,可以是任何映射對象;
- flags和dont_inherit:是用來控制編譯源碼時的标志。
- optimize:指定編譯器的優化級别;預設值-1選擇由-O選項給出的解釋器的優化級别。顯式級别為0(無優化; __debug__為真),1(聲明被删除,__debug__為假 )或2(docstrings也被删除)。
在上述參數中,可選參數flags和dont_inherit控制哪些未來版本的語句會應用于源編譯。如果兩者都不存在(或兩者都為零),則使用在調用compile()的代碼中生效的未來語句來編譯代碼。如果給出了flags參數且沒有給出dont_inherit參數(或者為0),除了本該使用的future語句之外,由flags參數指明的future語句也會影響編譯。如果dont_inherit是非0整數,flags參數被忽略(調用compile周圍的有效的future語句被忽略)。
在下面的執行個體檔案com.py中,示範了使用函數compile()編譯字元串的過程。
str = "for i in range(0,10): print(i)"
c = compile(str,'','exec') # 編譯為位元組代碼對象
print(c)
print(exec(c))
str = "3 * 4 + 5"
a = compile(str,'','eval')
print(eval(a))
在上述代碼中分别使用了函數compile()的exec和eval兩種編譯類型,執行後會輸出:
<code object <module> at 0x0000026B6382EA50, file "", line 1>
0
1
2
3
4
5
6
7
8
9
None
17
在下面的執行個體檔案comp.py中,示範了在互動語句中使用single的過程。
#流程語句使用exec
code1 = 'for i in range(0,10): print (i)'
compile1 = compile(code1,'','exec')
print(exec (compile1))
#簡單求值表達式用eval
code2 = '1 + 2 + 3 + 4'
compile2 = compile(code2,'','eval')
print(eval(compile2))
#互動語句用single
code3 = 'name = input("please input your name:")'
compile3 = compile(code3,'','single')
①print(exec(compile3)) #執行時顯示互動指令,提示輸入
②print(name) #執行後name變量有值
執行後會輸出:
0
1
2
3
4
5
6
7
8
9
None
10
please input your name:py
None
py
在上述代碼中,當執行到①時會顯示一個互動指令語句,提示我們輸入一個變量值,這樣變量name便會有一個值,執行②代碼時不會出錯。如果在執行②前變量name的值不存在,則會出現執行錯誤,例如下面代碼的執行過程:
>>> #互動語句用single
>>> code3 = 'name = input("please input your name:")'
>>> compile3 = compile(code3,'','single')
>>> name #執行前name變量不存在
Traceback (most recent call last):
File "<pyshell#29>", line 1, in <module>
name
NameError: name 'name' is not defined
1.13 函數complex()
在Python程式中,函數complex()的功能是建立一個值為“real + imag * j”的複數或者轉化一個字元串或數為複數。如果第一個參數為字元串,則不需要指定第二個參數。使用函數complex()的文法格式如下所示。
class complex([real[, imag]])
real:int、long、float或字元串;
imag:int、long或float類型。
函數complex()的傳回值形式為“real + imag * j”的複數,或将字元串或數字轉換為複數。如果第一個參數是一個字元串,它将被解釋成複數,同時函數不能有第二個參數。第二個參數不能是字元串。每個參數必須是數值類型(包括複數)。如果省略參數imag,則預設為零,構造函數會像int和float一樣進行轉換。如果省略這兩個參數,則傳回0j。
在下面的執行個體檔案compl.py中,示範了使用函數complex()建立複數的過程。
print(complex()) #當兩個參數都不提供時,傳回複數 0j。
print(complex(1, 2))
print(complex(1)) # 數字
print(complex("1")) # 當做字元串處理
# 注意:下面的代碼在"+"号兩邊不能有空格,也就是不能寫成"1 + 2j",應該是"1+2j",否則會報錯
print(complex("1+2j"))
print(complex(2)) #當第一個參數為int或者float時,第二個參數可為空,表示虛部為0
print((2+0j)) #如果提供第二個參數,第二個參數也需為int或者float。
執行後會輸出:
0j
(1+2j)
(1+0j)
(1+0j)
(1+2j)
(2+0j)
(2+0j)
在Python程式中,當函數complex()中的第一個參數為字元串時,在調用時不能提供第二個參數。此時的字元串參數,需要是一個能表示複數的字元串,而且加号或者減号左右不能出現空格。例如在下面的代碼中,函數complex()的第一個參數為字元串,不能接受第二個參數。接受第二個參數時會出錯。
>>> complex('1+2j',2) #第一個參數為字元串,不能接受第二個參數,
Traceback (most recent call last):
File "<pyshell#2>", line 1, in <module>
complex('1+2j',2)
TypeError: complex() can't take second arg if first is a string
在函數complex()中的"+"号兩邊不能有空格,否則也會出現編譯錯誤,例如下面的代碼。
>>> complex('1 + 2j') #不能有空格
Traceback (most recent call last):
File "<pyshell#3>", line 1, in <module>
complex('1 + 2j')
ValueError: complex() arg is a malformed string
1.14 函數delattr()
在Python程式中,函數delattr()的功能是删除指定對象的某個屬性。使用函數delattr()的文法格式如下所示。
delattr(object, name)
- object:對象;
- name:是一個字元串,這個字元串必須是對象的某個屬性的名字。
例如代碼“delattr(x, 'foobar')”等同于“del x.foobar”,表示删除對象x中的屬性foobar。在下面的執行個體檔案del.py中,示範了使用函數delattr()删除指定屬性的過程。
class Coordinate:
x = 10
y = -5
z = 0
point1 = Coordinate()
print('x = ', point1.x)
print('y = ', point1.y)
print('z = ', point1.z)
delattr(Coordinate, 'z')
print('--删除 z 屬性後--')
print('x = ', point1.x)
print('y = ', point1.y)
# 因為已經删除了,是以執行後會觸發錯誤
print('z = ', point1.z)
執行後會輸出:
x = 10
Traceback (most recent call last):
y = -5
File " del.py", line 19, in <module>
z = 0
print('z = ', point1.z)
--删除 z 屬性後--
AttributeError: 'Coordinate' object has no attribute 'z'
x = 10
y = -5
當使用函數delattr()删除某個屬性時,如果這個屬性不存在則會報錯,例如下面的代碼:
>>> a.name #屬性name已經删掉,不存在
Traceback (most recent call last):
File "<pyshell#47>", line 1, in <module>
a.name
AttributeError: 'A' object has no attribute 'name'
>>> delattr(a,'name') #再删除會報錯
Traceback (most recent call last):
File "<pyshell#48>", line 1, in <module>
delattr(a,'name')
AttributeError: name
當使用函數delattr()删除某個屬性時,不能删除對象的方法,否則将會出錯,例如下面的示範代碼:
>>> a.sayHello
<bound method A.sayHello of <__main__.A object at 0x03F014B0>>
>>> delattr(a,'sayHello') #不能用于删除方法
Traceback (most recent call last):
File "<pyshell#50>", line 1, in <module>
delattr(a,'sayHello')
AttributeError: sayHello
>>>
1.15 函數dict()
在Python程式中,函數dict()的功能是建立一個字典。在現實中有如下三種使用函數dict()的文法格式。
class dict(**kwarg)
class dict(mapping, **kwarg)
class dict(iterable, **kwarg)
- **kwargs:關鍵字;
- Mapping:元素的容器;
- Iterable:可疊代對象。
在下面的執行個體檔案dict.py中,示範了使用函數dict()建立字典的過程。
#不傳入任何參數時,傳回空字典。
print(dict())
#可以傳入鍵值對建立字典。
print(dict(a = 1))
print(dict(a = 1,b = 2))
#可以傳入映射函數建立字典。
print(dict(zip(['a','b'],[1,2])))
#可以傳入可疊代對象建立字典。
print(dict((('a',1),('b',2))))
執行後會輸出:
{}
{'a': 1}
{'a': 1, 'b': 2}
{'a': 1, 'b': 2}
{'a': 1, 'b': 2}