Python基础学习总结(六)
8.函數(shù)
8.1實參和形參
形參:函數(shù)完成其工作所需要的一項信息。
實參:調(diào)用函數(shù)時專遞給給函數(shù)的信息。
8.2傳遞參數(shù)
函數(shù)定義中可能包含多個形參,因此函數(shù)調(diào)用時也可能包含多個實參。向函數(shù)傳遞實參的方式很多,可使用位置實參,這要求實參的順序與形參的順序相同;也可使用關(guān)鍵字實參,其中每個實參都由變量名和值組成;還可使用列表和字典。
8.2.1位置實參
1.你調(diào)用函數(shù)時,Python必須將函數(shù)調(diào)用中的每個實參都關(guān)聯(lián)到函數(shù)定義中的一個形參。簡單的關(guān)聯(lián)方式是基于實參的順序。這種關(guān)聯(lián)方式被稱為位置實參。
2.在函數(shù)中,可根據(jù)需要使用任意數(shù)量的位置實參,Python將按順序?qū)⒑瘮?shù)調(diào)用中的實參關(guān)聯(lián)到函數(shù)定義中相應(yīng)的形參。
3.使用位置實參來調(diào)用函數(shù)時,如果實參的順序不正確,輸出也不會正確。
8.2.2關(guān)鍵字實參和關(guān)鍵字參數(shù)
關(guān)鍵字實參是傳遞給函數(shù)的(名稱—值)對。你直接在實參中將名稱和值關(guān)聯(lián)起來了,因此向函數(shù)傳遞實參時不會混淆。關(guān)鍵字實參讓你無需考慮函數(shù)調(diào)用中的實參順序,還清楚地指出了函數(shù)調(diào)用中各個值的用途。
1 describe_pet(animal_type='hamster', pet_name='harry')可以傳入任意個數(shù)的關(guān)鍵字參數(shù):
>>> person('Bob', 35, city='Beijing') name: Bob age: 35 other: {'city': 'Beijing'} >>> person('Adam', 45, gender='M', job='Engineer') name: Adam age: 45 other: {'gender': 'M', 'job': 'Engineer'}8.2.3默認值
編寫函數(shù)時,可給每個形參指定默認值 。在調(diào)用函數(shù)中給形參提供了實參時,Python將使用指定的實參值;否則,將使用形參的默認值。因此,給形參指定默認值后,可在函數(shù)調(diào)用中省略相應(yīng)的實參。使用默認值可簡化函數(shù)調(diào)用,還可清楚地指出函數(shù)的典型用法。最大的好處是能降低調(diào)用函數(shù)的難度。
默認參數(shù)必須指向不變對象!
1 def add_end(L=None): 2 if L is None: 3 L = [] 4 L.append('END') 5 return L8.2.4可變參數(shù)
定義可變參數(shù)和定義一個list或tuple參數(shù)相比,僅僅在參數(shù)前面加了一個 * 號。在函數(shù)內(nèi)部,參數(shù)numbers接收到的是一個tuple,因此,函數(shù)代碼完全不變。但是,調(diào)用該函數(shù)時,可以傳入任意個參數(shù),包括0個參數(shù)。
1 def calc(*numbers): 2 sum = 0 3 for n in numbers: 4 sum = sum + n * n 5 return sum >>> calc(1, 2) 5 >>> calc() 0Python允許你在list或tuple前面加一個*號,把list或tuple的元素變成可變參數(shù)傳進去:
>>> nums = [1, 2, 3] >>> calc(*nums) 14*nums表示把nums這個list的所有元素作為可變參數(shù)傳進去。
8.2.5命名關(guān)鍵詞參數(shù)
對于關(guān)鍵字參數(shù),函數(shù)的調(diào)用者可以傳入任意不受限制的關(guān)鍵字參數(shù)。至于到底傳入了哪些,就需要在函數(shù)內(nèi)部通過kw檢查。
如果要限制關(guān)鍵字參數(shù)的名字,就可以用命名關(guān)鍵字參數(shù),例如,只接收city和job作為關(guān)鍵字參數(shù)。這種方式定義的函數(shù)如下:
1 def person(name, age, *, city, job): 2 print(name, age, city, job)和關(guān)鍵字參數(shù)**kw不同,命名關(guān)鍵字參數(shù)需要一個特殊分隔符*,*后面的參數(shù)被視為命名關(guān)鍵字參數(shù)。
如果函數(shù)定義中已經(jīng)有了一個可變參數(shù),后面跟著的命名關(guān)鍵字參數(shù)就不再需要一個特殊分隔符*了:
1 def person(name, age, *args, city, job): 2 print(name, age, args, city, job)命名關(guān)鍵字參數(shù)必須傳入?yún)?shù)名,這和位置參數(shù)不同。如果沒有傳入?yún)?shù)名,調(diào)用將報錯:
>>> person('Jack', 24, 'Beijing', 'Engineer') Traceback (most recent call last):File "<stdin>", line 1, in <module> TypeError: person() takes 2 positional arguments but 4 were given由于調(diào)用時缺少參數(shù)名city和job,Python解釋器把這4個參數(shù)均視為位置參數(shù),但person()函數(shù)僅接受2個位置參數(shù)。
命名關(guān)鍵字參數(shù)可以有缺省值(默認值),從而簡化調(diào)用:
1 def person(name, age, *, city='Beijing', job): 2 print(name, age, city, job)由于命名關(guān)鍵字參數(shù)city具有默認值,調(diào)用時,可不傳入city參數(shù):
>>> person('Jack', 24, job='Engineer') Jack 24 Beijing Engineer定義命名的關(guān)鍵字參數(shù)在沒有可變參數(shù)的情況下不要忘了寫分隔符*,否則定義的將是位置參數(shù)。
8.2.5等效的函數(shù)調(diào)用
輸出結(jié)果相同,調(diào)用方法不同。
注意:使用哪種調(diào)用方式無關(guān)緊要,只要函數(shù)調(diào)用能生成你希望的輸出就行。使用對你來說最容易理解的調(diào)用方式即可。
8.2.6空函數(shù)(pass)
如果想定義一個什么事也不做的空函數(shù),可以用pass語句:
1 def nop(): 2 passpass語句什么都不做,pass可以用來作為占位符,比如現(xiàn)在還沒想好怎么寫函數(shù)的代碼,就可以先放一個pass,讓代碼能運行起來。
8.2.7避免實參錯誤
沒有給定實參,實參順序錯誤,沒有注意實參格式(引號等)。
8.2.8 global語句(全局變量)
如果想在一個函數(shù)中修改全局變量中存儲的值,就必須對該變量使用 global 語句。盡量避免使用全局變量,因為它引入了多余變量到全局作用域。
1 # 1 2 def add(value1, value2): 3 return value1 + value2 4 result = add(3, 5) 5 print(result) 6 # Output: 8 7 8 # 2 9 def add(value1, value2): 10 global result # 全局變量,可以在函數(shù)外訪問變量 11 result = value1 + value2 12 add(3,5) 13 print(result) # 在函數(shù)外訪問變量,可以輸出結(jié)果 14 # Output: 8 15 16 # 3 17 def add(value1, value2): 18 result = value1 + value2 19 add(2, 4) # 沒有設(shè)置全局變量 20 print(result) 21 Traceback (most recent call last): # 返回錯誤提示,不能再函數(shù)外訪問 22 File "", line 1, in result 23 NameError: name 'result' is not defined8.3返回值
函數(shù)并非總是直接顯示輸出,相反,它可以處理一些數(shù)據(jù),并返回一個或一組值。函數(shù)返回的值被稱為返回值。函數(shù)的返回值用return語句返回。
在函數(shù)中,可使用return 語句將值返回到調(diào)用函數(shù)的代碼行。返回值讓你能夠?qū)⒊绦虻拇蟛糠址敝毓ぷ饕频胶瘮?shù)中去完成,從而簡化主程序。
8.3.1返回多個值
import math語句表示導(dǎo)入math包,并允許后續(xù)代碼引用math包里的sin、cos等函數(shù)。就可以返回多個值了。
>>>import math >>> x, y = move(100, 100, 60, math.pi / 6) >>> print(x, y) 151.96152422706632 70.0但其實這只是一種假象,Python函數(shù)返回的仍然是單一值:
>>> r = move(100, 100, 60, math.pi / 6) >>> print(r) (151.96152422706632, 70.0) # 返回一個元組返回值是一個tuple!但是,在語法上,返回一個tuple可以省略括號,而多個變量可以同時接收一個tuple,按位置賦給對應(yīng)的值,所以,Python的函數(shù)返回多值其實就是返回一個tuple,但寫起來更方便。
8.3.2讓實參變得可選
通過if語句,來判斷是否需要這個實參。
8.3.3返回字典
函數(shù)可返回任何類型的值,包括列表和字典等較復(fù)雜的數(shù)據(jù)結(jié)構(gòu)。
8.3.4返回函數(shù)
高階函數(shù)除了可以接受函數(shù)作為參數(shù)外,還可以把函數(shù)作為結(jié)果值返回。如果不需要立刻求和,可以不返回求和的結(jié)果,而是返回求和的函數(shù):
1 def lazy_sum(*args): 2 def sum(): 3 ax = 0 4 for n in args: 5 ax = ax + n 6 return ax 7 return sum當我們調(diào)用lazy_sum()時,返回的并不是求和結(jié)果,而是求和函數(shù):
>>> f = lazy_sum(1, 3, 5, 7, 9) >>> f <function lazy_sum.<locals>.sum at 0x101c6ed90>調(diào)用函數(shù)f時,才真正計算求和的結(jié)果:
>>> f() 25注意:當我們調(diào)用lazy_sum()時,每次調(diào)用都會返回一個新的函數(shù),即使傳入相同的參數(shù):
>>> f1 = lazy_sum(1, 3, 5, 7, 9) >>> f2 = lazy_sum(1, 3, 5, 7, 9) >>> f1==f2 Falsef1()和f2()的調(diào)用結(jié)果互不影響。
8.3.5結(jié)合使用函數(shù)和while
1 def get_formatted_name(first_name, last_name): 2 """返回整潔的姓名""" 3 full_name = first_name + ' ' + last_name 4 return full_name.title() 5 while True: 6 print("\nPlease tell me your name:") 7 print("(enter 'q' at any time to quit)") 8 f_name = input("First name: ") 9 if f_name == 'q': 10 break 11 l_name = input("Last name: ") 12 if l_name == 'q': 13 break 14 formatted_name = get_formatted_name(f_name, l_name) 15 print("\nHello, " + formatted_name + "!")8.3.6閉包
返回閉包時牢記的一點就是:返回函數(shù)不要引用任何循環(huán)變量,或者后續(xù)會發(fā)生變化的變量。如果一定要引用循環(huán)變量,方法是再創(chuàng)建一個函數(shù),用該函數(shù)的參數(shù)綁定循環(huán)變量當前的值,無論該循環(huán)變量后續(xù)如何更改,已綁定到函數(shù)參數(shù)的值不變,缺點是代碼較長,可利用lambda函數(shù)縮短代碼。
1 def count(): 2 def f(j): 3 def g(): 4 return j*j 5 return g 6 fs = [] 7 for i in range(1, 4): 8 fs.append(f(i)) # f(i)立刻被執(zhí)行,因此i的當前值被傳入f() 9 return fs 10 >>> f1, f2, f3 = count() 11 >>> f1() 12 1 13 >>> f2() 14 4 15 >>> f3() 16 98.3.7匿名函數(shù)lambda
當我們在傳入函數(shù)時,有些時候,不需要顯式地定義函數(shù),直接傳入匿名函數(shù)更方便。
在Python中,對匿名函數(shù)提供了有限支持。還是以map()函數(shù)為例,計算f(x)=x2時,除了定義一個f(x)的函數(shù)外,還可以直接傳入匿名函數(shù):
>>> list(map(lambda x: x * x, [1, 2, 3, 4, 5, 6, 7, 8, 9])) [1, 4, 9, 16, 25, 36, 49, 64, 81]通過對比可以看出,匿名函數(shù)lambda x: x * x實際上就是:
def f(x):return x * x關(guān)鍵字lambda表示匿名函數(shù),冒號前面的x表示函數(shù)參數(shù)。匿名函數(shù)有個限制,就是只能有一個表達式,不用寫return,返回值就是該表達式的結(jié)果。
用匿名函數(shù)有個好處,因為函數(shù)沒有名字,不必擔心函數(shù)名沖突。此外,匿名函數(shù)也是一個函數(shù)對象,也可以把匿名函數(shù)賦值給一個變量,再利用變量來調(diào)用該函數(shù):
>>> f = lambda x: x * x >>> f <function <lambda> at 0x101c6ef28> >>> f(5) 258.4傳遞列表
for name in names:你經(jīng)常會發(fā)現(xiàn),向函數(shù)傳遞列表很有用,這種列表包含的可能是名字、數(shù)字或更復(fù)雜的對象(如字典)。將列表傳遞給函數(shù)后,函數(shù)就能直接訪問其內(nèi)容。下面使用函數(shù)來提高處理列表的效率。
8.4.1在函數(shù)中修改列表
1.將列表傳遞給函數(shù)后,函數(shù)就可對其進行修改。在函數(shù)中對這個列表所做的任何修改都是永久性的,這讓你能夠高效地處理大量的數(shù)據(jù)。
2.增加或刪除, append ; pop
3.一個函數(shù)完成一個任務(wù),函數(shù)可以相互調(diào)用。優(yōu)化函數(shù),方便維護和修改。
8.4.2禁止修改函數(shù)
為解決這個問題,可向函數(shù)傳遞列表的副本而不是原件;這樣函數(shù)所做的任何修改都只影響副本,而絲毫不影響原件。
function_name(list_name[:]),[:]相當于復(fù)制。
8.5傳遞任意數(shù)量的實參(可變參數(shù))
有時候,你預(yù)先不知道函數(shù)需要接受多少個實參,好在Python允許函數(shù)從調(diào)用語句中收集任意數(shù)量的實參。
def make_pizza(*toppings):
形參名*toppings 中的星號讓Python創(chuàng)建一個名為toppings 的空元組,并將收到的所有值都封裝到這個元組中。函數(shù)體內(nèi)的print 語句通過生成輸出來證明Python能夠處理 使用一個值調(diào)用函數(shù)的情形,也能處理使用三個值來調(diào)用函數(shù)的情形。它以類似的方式處理不同的調(diào)用,注意,Python將實參封裝到一個元組中,即便函數(shù)只收到一個值也如此。
8.5.1結(jié)合使用位置實參和可變實參
如果要讓函數(shù)接受不同類型的實參,必須在函數(shù)定義中將接納任意數(shù)量實參的形參放在最后。Python先匹配位置實參和關(guān)鍵字實參,再將余下的實參都收集到最后一個形參中。
8.5.2使用可變實參和關(guān)鍵字實參
def build_profile(first, last, **user_info):
函數(shù)build_profile() 的定義要求提供名和姓,同時允許用戶根據(jù)需要提供任意數(shù)量的名稱—值對。形參**user_info 中的兩個星號讓Python創(chuàng)建一個名為user_info 的 空字典,并將收到的所有名稱—值對都封裝到這個字典中。在這個函數(shù)中,可以像訪問其他字典那樣訪問user_info 中的名稱—值對。
for key, value in user_info.items(): profile[key] = value user_profile = build_profile('albert', 'einstein',location='princeton', field='physics')8.5.3使用參數(shù)組合
1.在Python中定義函數(shù),可以用必選參數(shù)、默認參數(shù)、可變參數(shù)、關(guān)鍵字參數(shù)和命名關(guān)鍵字參數(shù),這5種參數(shù)都可以組合使用。但是請注意,參數(shù)定義的順序必須是:必選參數(shù)、默認參數(shù)、可變參數(shù)、命名關(guān)鍵字參數(shù)和關(guān)鍵字參數(shù)。
2.python的函數(shù)具有非常靈活的參數(shù)形態(tài),既可以實現(xiàn)簡單的調(diào)用,又可以傳入非常復(fù)雜的參數(shù)。
3.默認參數(shù)一定要用不可變對象,如果是可變對象,程序運行時會有邏輯錯誤!
4.要注意定義可變參數(shù)和關(guān)鍵字參數(shù)的語法:
5.*args是可變參數(shù),args接收的是一個tuple;
6.**kw是關(guān)鍵字參數(shù),kw接收的是一個dict。
7.以及調(diào)用函數(shù)時如何傳入可變參數(shù)和關(guān)鍵字參數(shù)的語法:
可變參數(shù)既可以直接傳入:func(1, 2, 3),又可以先組裝list或tuple,再通過*args傳入:func(*(1, 2, 3));
關(guān)鍵字參數(shù)既可以直接傳入:func(a=1, b=2),又可以先組裝dict,再通過**kw傳入:func(**{'a': 1, 'b': 2})。
使用*args和**kw是Python的習慣寫法,當然也可以用其他參數(shù)名,但最好使用習慣用法。
8.5.4遞歸參數(shù)
在函數(shù)內(nèi)部,可以調(diào)用其他函數(shù)。如果一個函數(shù)在內(nèi)部調(diào)用自身本身,這個函數(shù)就是遞歸函數(shù)。遞歸函數(shù)的優(yōu)點是定義簡單,邏輯清晰。理論上,所有的遞歸函數(shù)都可以寫成循環(huán)的方式,但循環(huán)的邏輯不如遞歸清晰。
1 def fact(n): 2 if n==1: 3 return 1 4 return n * fact(n - 1)使用遞歸函數(shù)需要注意防止棧溢出。在計算機中,函數(shù)調(diào)用是通過棧(stack)這種數(shù)據(jù)結(jié)構(gòu)實現(xiàn)的,每當進入一個函數(shù)調(diào)用,棧就會加一層棧幀,每當函數(shù)返回,棧就會減一層棧幀。由于棧的大小不是無限的,所以,遞歸調(diào)用的次數(shù)過多,會導(dǎo)致棧溢出。
8.6高階函數(shù)
8.6.1高階函數(shù)
既然變量可以指向函數(shù),函數(shù)的參數(shù)能接收變量,那么一個函數(shù)就可以接收另一個函數(shù)作為參數(shù),這種函數(shù)就稱之為高階函數(shù)。
1 def add(x, y, f): 2 return f(x) + f(y)8.6.2內(nèi)建函數(shù)
1.求絕對值的函數(shù)abs(),只有一個參數(shù)。
2.判斷對象類型,使用type()函數(shù):
>>> type(123) <class 'int'> >>> type('str') <class 'str'> >>> type(None) <type(None) 'NoneType'>3.計算平方根可以調(diào)用math.sqrt()函數(shù)。
4.lower()返回小寫的字符串。
5.__len__方法返回長度。在Python中,如果你調(diào)用len()函數(shù)試圖獲取一個對象的長度,實際上,在len()函數(shù)內(nèi)部,它自動去調(diào)用該對象的__len__()方法,所以,下面的代碼是等價的:
>>> len('ABC') 3 >>> 'ABC'.__len__() 36.max函數(shù)max()可以接收任意多個參數(shù),并返回最大的那個。
7.如果要獲得一個對象的所有屬性和方法,可以使用dir()函數(shù),它返回一個包含字符串的list,比如,獲得一個str對象的所有屬性和方法:
8.Python內(nèi)置的hex()函數(shù)把一個整數(shù)轉(zhuǎn)換成十六進制表示的字符串。
9.對于class的繼承關(guān)系來說,使用type()就很不方便。我們要判斷class的類型,可以使用isinstance()函數(shù)。參數(shù)類型做檢查,只允許整數(shù)和浮點數(shù)類型的參數(shù)。數(shù)據(jù)類型檢查可以用內(nèi)置函數(shù)isinstance()實現(xiàn)。使用內(nèi)建的isinstance函數(shù)可以判斷一個變量是不是字符串。
10.配合getattr()、setattr()以及hasattr(),我們可以直接操作一個對象的狀態(tài)。
>>> hasattr(obj, 'x') # 有屬性'x'嗎? True >>> obj.x 9 >>> hasattr(obj, 'y') # 有屬性'y'嗎? False >>> setattr(obj, 'y', 19) # 設(shè)置一個屬性'y' >>> hasattr(obj, 'y') # 有屬性'y'嗎? True >>> getattr(obj, 'y') # 獲取屬性'y' 19 >>> obj.y # 獲取屬性'y' 19通過內(nèi)置的一系列函數(shù),我們可以對任意一個Python對象進行剖析,拿到其內(nèi)部的數(shù)據(jù)。要注意的是,只有在不知道對象信息的時候,我們才會去獲取對象信息。
11.Python內(nèi)建了map()和reduce()函數(shù)。map將傳入的函數(shù)依次作用到序列的每個元素,并把結(jié)果作為新的Iterator返回。
>>> def f(x): ... return x * x ... >>> r = map(f, [1, 2, 3, 4, 5, 6, 7, 8, 9]) >>> list(r) [1, 4, 9, 16, 25, 36, 49, 64, 81]reduce的用法。reduce把一個函數(shù)作用在一個序列[x1, x2, x3, ...]上,這個函數(shù)必須接收兩個參數(shù),reduce把結(jié)果繼續(xù)和序列的下一個元素做累積計算。
>>> from functools import reduce >>> def fn(x, y): ... return x * 10 + y ... >>> reduce(fn, [1, 3, 5, 7, 9]) 1357912.Python內(nèi)建的filter()函數(shù)用于過濾序列。filter()也接收一個函數(shù)和一個序列。和map()不同的是,filter()把傳入的函數(shù)依次作用于每個元素,然后根據(jù)返回值是True還是False決定保留還是丟棄該元素。關(guān)鍵在于正確實現(xiàn)一個“篩選”函數(shù)。注意到filter()函數(shù)返回的是一個Iterator,也就是一個惰性序列,所以要強迫filter()完成計算結(jié)果,需要用list()函數(shù)獲得所有結(jié)果并返回list。
1 def is_odd(n): 2 return n % 2 == 1 3 4 list(filter(is_odd, [1, 2, 4, 5, 6, 9, 10, 15])) 5 # 結(jié)果: [1, 5, 9, 15]13.Python內(nèi)置的sorted()函數(shù)就可以對list進行排序。
>>> sorted([36, 5, -12, 9, -21]) [-21, -12, 5, 9, 36]14.sorted()函數(shù)也是一個高階函數(shù),它還可以接收一個key函數(shù)來實現(xiàn)自定義的排序,例如按絕對值大小排序。要進行反向排序,不必改動key函數(shù),可以傳入第三個參數(shù)reverse=True。
>>> sorted(['bob', 'about', 'Zoo', 'Credit'], key=str.lower, reverse=True) ['Zoo', 'Credit', 'bob', 'about']15.Python內(nèi)置的enumerate函數(shù)可以把一個list變成索引-元素對,這樣就可以在for循環(huán)中同時迭代索引和元素本身。
16.round()函數(shù)可以返回任意位的小數(shù)。例如:round(2.33333333, 3) 返回 2.333,也可以用來四舍五入,round(1.6) 輸出:2
8.6.3裝飾器
在代碼運行期間動態(tài)增加功能的方式,稱之為“裝飾器”(Decorator)。本質(zhì)上,decorator就是一個返回函數(shù)的高階函數(shù)。裝飾器:不改變函數(shù)本身,增加新的功能。
函數(shù)對象有一個__name__屬性,可以拿到函數(shù)的名字:
>>> def now(): ... print('2015-3-25') ... >>> f = now >>> f() 2015-3-25 >>> now.__name__ 'now' >>> f.__name__ 'now'Python內(nèi)置的@property裝飾器就是負責把一個方法變成屬性調(diào)用的:
1 class Student(object): 2 3 @property 4 def score(self): 5 return self._score 6 7 @score.setter 8 def score(self, value): 9 if not isinstance(value, int): 10 raise ValueError('score must be an integer!') 11 if value < 0 or value > 100: 12 raise ValueError('score must between 0 ~ 100!') 13 self._score = value@property廣泛應(yīng)用在類的定義中,可以讓調(diào)用者寫出簡短的代碼,同時保證對參數(shù)進行必要的檢查,這樣,程序運行時就減少了出錯的可能性。
@unique裝飾器可以幫助我們檢查保證沒有重復(fù)值。
8.7將函數(shù)儲存在模塊中
1.為了編寫可維護的代碼,可以把很多函數(shù)分組,分別放到不同的文件里,這樣,每個文件包含的代碼就相對較少。在Python中,一個.py文件就稱之為一個模塊(Module)。
2.函數(shù)的優(yōu)點之一是,使用它們可將代碼塊與主程序分離。通過給函數(shù)指定描述性名稱,可讓主程序容易理解得多。你還可以更進一步,將函數(shù)存儲在被稱為模塊的獨立文件中, 再將模塊導(dǎo)入到主程序中。import 語句允許在當前運行的程序文件中使用模塊中的代碼。
3.通過將函數(shù)存儲在獨立的文件中,可隱藏程序代碼的細節(jié),將重點放在程序的高層邏輯上。這還能讓你在眾多不同的程序中重用函數(shù)。將函數(shù)存儲在獨立文件中后,可與其他程序員共享這些文件而不是整個程序。知道如何導(dǎo)入函數(shù)還能讓你使用其他程序員編寫的函數(shù)庫。
4.為了避免模塊名沖突,Python又引入了按目錄來組織模塊的方法,稱為包(Package)。引入了包以后,只要頂層的包名不與別人沖突,那所有模塊都不會與別人沖突。現(xiàn)在,abc.py模塊的名字就變成了mycompany.abc,類似的,xyz.py的模塊名變成了mycompany.xyz。
5.注意:每一個包目錄下面都會有一個__init__.py的文件,這個文件是必須存在的,否則,Python就把這個目錄當成普通目錄,而不是一個包。__init__.py可以是空文件,也可以有Python代碼,因為__init__.py本身就是一個模塊。
8.7.1導(dǎo)入整個模塊
要讓函數(shù)是可導(dǎo)入的,得先創(chuàng)建模塊。模塊是擴展名為.py的文件,包含要導(dǎo)入到程序中的代碼。
1 if __name__=='__main__': 2 test()使用模塊的第一步就是導(dǎo)入模塊,當我們在命令行運行模塊文件時,Python解釋器把一個特殊變量__name__置為__main__,而如果在其他地方導(dǎo)入該模塊時,if判斷將失敗,因此,這種if測試可以讓一個模塊通過命令行運行時執(zhí)行一些額外的代碼,最常見的就是運行測試。
8.7.2作用域
在一個模塊中,我們可能會定義很多函數(shù)和變量,但有的函數(shù)和變量我們希望給別人使用,有的函數(shù)和變量我們希望僅僅在模塊內(nèi)部使用。在Python中,是通過_前綴來實現(xiàn)的。正常的函數(shù)和變量名是公開的(public),可以被直接引用,比如:abc,x123,PI等;類似__xxx__這樣的變量是特殊變量,可以被直接引用,但是有特殊用途,比如上面的__author__,__name__就是特殊變量,hello模塊定義的文檔注釋也可以用特殊變量__doc__訪問,我們自己的變量一般不要用這種變量名;類似_xxx和__xxx這樣的函數(shù)或變量就是非公開的(private),不應(yīng)該被直接引用,比如_abc,__abc等;
private函數(shù)或變量不應(yīng)該被別人引用:
1 def _private_1(name): 2 return 'Hello, %s' % name 3 4 def _private_2(name): 5 return 'Hi, %s' % name 6 7 def greeting(name): 8 if len(name) > 3: 9 return _private_1(name) 10 else: 11 return _private_2(name)我們在模塊里公開greeting()函數(shù),而把內(nèi)部邏輯用private函數(shù)隱藏起來了,這樣,調(diào)用greeting()函數(shù)不用關(guān)心內(nèi)部的private函數(shù)細節(jié),這也是一種非常有用的代碼封裝和抽象的方法,即:外部不需要引用的函數(shù)全部定義成private,只有外部需要引用的函數(shù)才定義為public。
8.7.3導(dǎo)入特定模塊
把多個函數(shù)儲存在一個模塊中,用逗號隔開可以從模塊中導(dǎo)入任意數(shù)量函數(shù)。
8.7.4使用as給函數(shù)指定別名
1 from pizza import make_pizza as mp 2 3 import pandas as pd 4 5 import numpy as np如果要導(dǎo)入的函數(shù)的名稱可能與程序中現(xiàn)有的名稱沖突,或者函數(shù)的名稱太長,可指定簡短而獨一無二的別名——函數(shù)的另一個名稱,類似于外號。要給函數(shù)指定這種特殊外號,需要在導(dǎo)入它時這樣做。
8.7.5使用as給模塊指定別名
你還可以給模塊指定別名。通過給模塊指定簡短的別名(如給模塊pizza 指定別名p ),讓你能夠更輕松地調(diào)用模塊中的函數(shù)。相比于pizza.make_pizza() ,p.make_pizza() 更為簡潔。
8.7.6使用*導(dǎo)入模塊中所有函數(shù)
使用星號(* )運算符可讓Python導(dǎo)入模塊中的所有函數(shù)。
然而,使用并非自己編寫的大型模塊時,最好不要采用這種導(dǎo)入方法:如果模塊中有函數(shù)的名稱與你的項目中使用的名稱相同,可能導(dǎo)致意想不到的結(jié)果:Python可能遇到多個名稱相同的函數(shù)或變量,進而覆蓋函數(shù),而不是分別導(dǎo)入所有的函數(shù)。
8.8函數(shù)編寫指南
編寫函數(shù)時,需要牢記幾個細節(jié)。
1.應(yīng)給函數(shù)指定描述性名稱,且只在其中使用小寫字母和下劃線。描述性名稱可幫助你和別人明白代碼想要做什么。給模塊命名時也應(yīng)遵循上述約定。
2.每個函數(shù)都應(yīng)包含簡要地闡述其功能的注釋,該注釋應(yīng)緊跟在函數(shù)定義后面,并采用文檔字符串格式。文檔良好的函數(shù)讓其他程序員只需閱讀文檔字符串中的描述就能夠使用它:他們完全可以相信代碼如描述的那樣運行;只要知道函數(shù)的名稱、需要的實參以及返回值的類型,就能在自己的程序中使用它。
3.給形參指定默認值時,等號兩邊不要有空格。
?
轉(zhuǎn)載于:https://www.cnblogs.com/zt19994/p/7152162.html
總結(jié)
以上是生活随笔為你收集整理的Python基础学习总结(六)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 运用OpenMP提速图像处理速度
- 下一篇: 【Alpha 冲刺】 1/12