-
python之導入模塊
要使用一個模塊,我們必須首先導入該模塊。Python使用import語句導入一個模塊。例如,導入系統自帶的模塊?math:
import?math
你可以認為math就是一個指向已導入模塊的變量,通過該變量,我們可以訪問math模塊中所定義的所有公開的函數、變量和類:
>>>?math.pow(2,?0.5)?#?pow是函數?1.4142135623730951?>>>?math.pi?#?pi是變量?3.141592653589793
如果我們只希望導入用到的math模塊的某幾個函數,而不是所有函數,可以用下面的語句:
from?math?import?pow,?sin,?log
這樣,可以直接引用?pow, sin, log?這3個函數,但math的其他函數沒有導入進來:
>>>?pow(2,?10)?1024.0?>>>?sin(3.14)?0.0015926529164868282
如果遇到名字沖突怎么辦?比如math模塊有一個log函數,logging模塊也有一個log函數,如果同時使用,如何解決名字沖突?
如果使用import導入模塊名,由于必須通過模塊名引用函數名,因此不存在沖突:
import?math,?logging?print?math.log(10)???#?調用的是math的log函數?logging.log(10,?'something')???#?調用的是logging的log函數
如果使用?from...import?導入?log?函數,勢必引起沖突。這時,可以給函數起個“別名”來避免沖突:
from?math?import?log?from?logging?import?log?as?logger???#?logging的log現在變成了logger?print?log(10)???#?調用的是math的log?logger(10,?'import?from?logging')???#?調用的是logging的log
查看全部 -
請注意區分返回函數和返回值:
def?myabs(): ????return?abs???#?返回函數def?myabs2(x): ????return?abs(x)???#?返回函數調用的結果,返回值是一個數值
返回函數可以把一些計算延遲執行。例如,如果定義一個普通的求和函數:
def?calc_sum(lst): ????return?sum(lst)
調用calc_sum()函數時,將立刻計算并得到結果:
>>>?calc_sum([1,?2,?3,?4]) 10
但是,如果返回一個函數,就可以“延遲計算”:
def?calc_sum(lst): ????def?lazy_sum(): ????????return?sum(lst) ????return?lazy_sum
# 調用calc_sum()并沒有計算出結果,而是返回函數:
>>>?f?=?calc_sum([1,?2,?3,?4]) >>>?f <function?lazy_sum?at?0x1037bfaa0>
# 對返回的函數進行調用時,才計算出結果:
>>>?f() 10
由于可以返回函數,我們在后續代碼里就可以決定到底要不要調用該函數。
查看全部 -
?sorted()也是一個高階函數,它可以接收一個比較函數來實現自定義排序,比較函數的定義是,傳入兩個待比較的元素 x, y,如果 x 應該排在 y 的前面,返回 -1,如果 x 應該排在 y 的后面,返回 1。如果 x 和 y 相等,返回 0。
因此,如果我們要實現倒序排序,只需要編寫一個reversed_cmp函數:
def?reversed_cmp(x,?y): ????if?x?>?y: ????????return?-1 ????if?x?<?y: ????????return?1 ????return?0
這樣,調用 sorted() 并傳入 reversed_cmp 就可以實現倒序排序:
>>>?sorted([36,?5,?12,?9,?21],?reversed_cmp) [36,?21,?12,?9,?5]
sorted()也可以對字符串進行排序,字符串默認按照ASCII大小來比較:
>>>?sorted(['bob',?'about',?'Zoo',?'Credit']) ['Credit',?'Zoo',?'about',?'bob']
'Zoo'排在'about'之前是因為'Z'的ASCII碼比'a'小。
查看全部 -
1.__init__初始化示例? 即對象創建時必須傳入適當參數,當創建實例(對象)時,__init__()方法被自動調用,我們就能在此為每個實例都統一加上以下屬性: class Person(object): def __init__(self, name, gender, birth): # 這里的self就是(該類的)具體對象 self.name = name self.gender = gender self.birth = birth xiaoming = Person('Xiao Ming', 'Male', '1991-1-1') xiaohong = Person('Xiao Hong', 'Female', '1992-2-2') print xiaoming.name # 輸出 'Xiao Ming' print xiaohong.birth # 輸出 '1992-2-2’ 任務:請定義Person類的__init__方法,除了接受 name、gender 和 birth 外,還可接受任意關鍵字參數,并把他們都作為屬性賦值給實例。? 定義關鍵字參數,使用 **kw;(**kw是關鍵字參數,用于字典 )? 除了可以直接使用self.name = ‘xxx’設置一個屬性外,還可以通過 setattr(self, ‘name’, ‘xxx’) 設置屬性,解答見下: class Person(object): def __init__(self, name, gender, birth, **kw): self.name = name self.gender = gender self.birth = birth for k, v in kw.iteritems(): setattr(self, k, v) xiaoming = Person('Xiao Ming', 'Male', '1990-1-1', job='Student') print xiaoming.name print xiaoming.job 解釋器內部會將**kw拆分成對應的dict.? setattr()方法接受3個參數查看全部
-
python中偏函數
當一個函數有很多參數時,調用者就需要提供多個參數。如果減少參數個數,就可以簡化調用者的負擔。
比如,int()函數可以把字符串轉換為整數,當僅傳入字符串時,int()函數默認按十進制轉換:
>>>?int('12345')?12345
但int()函數還提供額外的base參數,默認值為10。如果傳入base參數,就可以做?N?進制的轉換:
>>>?int('12345',?base=8)?5349?>>>?int('12345',?16)?74565
假設要轉換大量的二進制字符串,每次都傳入int(x, base=2)非常麻煩,于是,我們想到,可以定義一個int2()的函數,默認把base=2傳進去:
def?int2(x,?base=2):?????return?int(x,?base)
這樣,我們轉換二進制就非常方便了:
>>>?int2('1000000')?64?>>>?int2('1010101')?85
functools.partial就是幫助我們創建一個偏函數的,不需要我們自己定義int2(),可以直接使用下面的代碼創建一個新的函數int2:
>>>?import?functools?>>>?int2?=?functools.partial(int,?base=2)?>>>?int2('1000000')?64?>>>?int2('1010101')?85
所以,functools.partial可以把一個參數多的函數變成一個參數少的新函數,少的參數需要在創建時指定默認值,這樣,新函數調用的難度就降低了。
查看全部 -
python中編寫帶參數decorator
考察上一節的?@log?裝飾器:
def?log(f):?????def?fn(x):?????????print?'call?'?+?f.__name__?+?'()...'?????????return?f(x)?????return?fn
發現對于被裝飾的函數,log打印的語句是不能變的(除了函數名)。
如果有的函數非常重要,希望打印出'[INFO] call xxx()...',有的函數不太重要,希望打印出'[DEBUG] call xxx()...',這時,log函數本身就需要傳入'INFO'或'DEBUG'這樣的參數,類似這樣:
@log('DEBUG')?def?my_func():?????pass
把上面的定義翻譯成高階函數的調用,就是:
my_func?=?log('DEBUG')(my_func)
上面的語句看上去還是比較繞,再展開一下:
log_decorator?=?log('DEBUG')?my_func?=?log_decorator(my_func)
上面的語句又相當于:
log_decorator?=?log('DEBUG')?@log_decorator?def?my_func():?????pass
所以,帶參數的log函數首先返回一個decorator函數,再讓這個decorator函數接收my_func并返回新函數:
def?log(prefix):?????def?log_decorator(f):?????????def?wrapper(*args,?**kw):?????????????print?'[%s]?%s()...'?%?(prefix,?f.__name__)?????????????return?f(*args,?**kw)?????????return?wrapper?????return?log_decorator?@log('DEBUG')?def?test():?????pass?print?test()
執行結果:
[DEBUG]?test()...?None
對于這種3層嵌套的decorator定義,你可以先把它拆開:
#?標準decorator:?def?log_decorator(f):?????def?wrapper(*args,?**kw):?????????print?'[%s]?%s()...'?%?(prefix,?f.__name__)?????????return?f(*args,?**kw)?????return?wrapper?return?log_decorator?#?返回decorator:?def?log(prefix):?????return?log_decorator(f)
拆開以后會發現,調用會失敗,因為在3層嵌套的decorator定義中,最內層的wrapper引用了最外層的參數prefix,所以,把一個閉包拆成普通的函數調用會比較困難。不支持閉包的編程語言要實現同樣的功能就需要更多的代碼
查看全部 -
python中編寫無參數decorator
Python的?decorator?本質上就是一個高階函數,它接收一個函數作為參數,然后,返回一個新函數。
使用 decorator 用Python提供的?@?語法,這樣可以避免手動編寫?f = decorate(f)?這樣的代碼。
考察一個@log的定義:
def?log(f):?????def?fn(x):?????????print?'call?'?+?f.__name__?+?'()...'?????????return?f(x)?????return?fn
對于階乘函數,@log工作得很好:
@log?def?factorial(n):?????return?reduce(lambda?x,y:?x*y,?range(1,?n+1))?print?factorial(10)
結果:
call?factorial()...?3628800
但是,對于參數不是一個的函數,調用將報錯:
@log?def?add(x,?y):?????return?x?+?y?print?add(1,?2)
結果:
Traceback?(most?recent?call?last):???File?"test.py",?line?15,?in?<module>?????print?add(1,2)?TypeError:?fn()?takes?exactly?1?argument?(2?given)
因為?add()?函數需要傳入兩個參數,但是?@log?寫死了只含一個參數的返回函數。
要讓?@log?自適應任何參數定義的函數,可以利用Python的?*args?和?**kw,保證任意個數的參數總是能正常調用:
def?log(f):?????def?fn(*args,?**kw):?????????print?'call?'?+?f.__name__?+?'()...'?????????return?f(*args,?**kw)?????return?fn
現在,對于任意函數,@log?都能正常工作。
查看全部 -
decorrator裝飾器
查看全部 -
python中匿名函數
高階函數可以接收函數做參數,有些時候,我們不需要顯式地定義函數,直接傳入匿名函數更方便。
在Python中,對匿名函數提供了有限支持。還是以map()函數為例,計算 f(x)=x2?時,除了定義一個f(x)的函數外,還可以直接傳入匿名函數:
>>>?map(lambda?x:?x?*?x,?[1,?2,?3,?4,?5,?6,?7,?8,?9])?[1,?4,?9,?16,?25,?36,?49,?64,?81]
通過對比可以看出,匿名函數?lambda x: x * x?實際上就是:
def?f(x):?????return?x?*?x
關鍵字lambda?表示匿名函數,冒號前面的?x 表示函數參數。
匿名函數有個限制,就是只能有一個表達式,不寫return,返回值就是該表達式的結果。
使用匿名函數,可以不必定義函數名,直接創建一個函數對象,很多時候可以簡化代碼:
>>>?sorted([1,?3,?9,?5,?0],?lambda?x,y:?-cmp(x,y))?[9,?5,?3,?1,?0]
返回函數的時候,也可以返回匿名函數:
>>>?myabs?=?lambda?x:?-x?if?x?<?0?else?x??>>>?myabs(-1)?1?>>>?myabs(1)?1
查看全部 -
python中閉包
在函數內部定義的函數和外部定義的函數是一樣的,只是他們無法被外部訪問:
def?g():?????print?'g()...'?def?f():?????print?'f()...'?????return?g
將?g?的定義移入函數?f?內部,防止其他代碼調用?g:
def?f():?????print?'f()...'?????def?g():?????????print?'g()...'?????return?g
但是,考察上一小節定義的?calc_sum?函數:
def?calc_sum(lst):?????def?lazy_sum():?????????return?sum(lst)?????return?lazy_sum
注意:?發現沒法把?lazy_sum?移到?calc_sum?的外部,因為它引用了?calc_sum?的參數?lst。
像這種內層函數引用了外層函數的變量(參數也算變量),然后返回內層函數的情況,稱為閉包(Closure)。
閉包的特點是返回的函數還引用了外層函數的局部變量,所以,要正確使用閉包,就要確保引用的局部變量在函數返回后不能變。舉例如下:
#?希望一次返回3個函數,分別計算1x1,2x2,3x3:?def?count():?????fs?=?[]?????for?i?in?range(1,?4):?????????def?f():??????????????return?i*i?????????fs.append(f)?????return?fs?f1,?f2,?f3?=?count()
你可能認為調用f1(),f2()和f3()結果應該是1,4,9,但實際結果全部都是?9(請自己動手驗證)。
原因就是當count()函數返回了3個函數時,這3個函數所引用的變量 i?的值已經變成了3。由于f1、f2、f3并沒有被調用,所以,此時他們并未計算 i*i,當 f1 被調用時:
>>>?f1()?9?????#?因為f1現在才計算i*i,但現在i的值已經變為3
因此,返回函數不要引用任何循環變量,或者后續會發生變化的變量。
查看全部 -
python中返回函數
Python的函數不但可以返回int、str、list、dict等數據類型,還可以返回函數!
例如,定義一個函數 f(),我們讓它返回一個函數 g,可以這樣寫:
def?f():?????print?'call?f()...'?????#?定義函數g:?????def?g():?????????print?'call?g()...'?????#?返回函數g:?????return?g
仔細觀察上面的函數定義,我們在函數 f 內部又定義了一個函數 g。由于函數 g 也是一個對象,函數名 g 就是指向函數 g 的變量,所以,最外層函數 f 可以返回變量 g,也就是函數 g 本身。
調用函數 f,我們會得到 f 返回的一個函數:
>>>?x?=?f()???#?調用f()?call?f()...?>>>?x???#?變量x是f()返回的函數:?<function?g?at?0x1037bf320>?>>>?x()???#?x指向函數,因此可以調用?call?g()...???#?調用x()就是執行g()函數定義的代碼
請注意區分返回函數和返回值:
def?myabs():?????return?abs???#?返回函數?def?myabs2(x):?????return?abs(x)???#?返回函數調用的結果,返回值是一個數值
返回函數可以把一些計算延遲執行。例如,如果定義一個普通的求和函數:
def?calc_sum(lst):?????return?sum(lst)
調用calc_sum()函數時,將立刻計算并得到結果:
>>>?calc_sum([1,?2,?3,?4])?10
但是,如果返回一個函數,就可以“延遲計算”:
def?calc_sum(lst):?????def?lazy_sum():?????????return?sum(lst)?????return?lazy_sum
# 調用calc_sum()并沒有計算出結果,而是返回函數:
>>>?f?=?calc_sum([1,?2,?3,?4])?>>>?f?<function?lazy_sum?at?0x1037bfaa0>
# 對返回的函數進行調用時,才計算出結果:
>>>?f()?10
由于可以返回函數,我們在后續代碼里就可以決定到底要不要調用該函數。
查看全部 -
python中自定義排序函數
Python內置的?sorted()函數可對list進行排序:
>>>sorted([36, 5, 12, 9, 21])
[5, 9, 12, 21, 36]但?sorted()也是一個高階函數,它可以接收一個比較函數來實現自定義排序,比較函數的定義是,傳入兩個待比較的元素 x, y,如果 x 應該排在 y 的前面,返回 -1,如果 x 應該排在 y 的后面,返回 1。如果 x 和 y 相等,返回 0。
因此,如果我們要實現倒序排序,只需要編寫一個reversed_cmp函數:
def?reversed_cmp(x,?y):?????if?x?>?y:?????????return?-1?????if?x?<?y:?????????return?1?????return?0
這樣,調用 sorted() 并傳入 reversed_cmp 就可以實現倒序排序:
>>>?sorted([36,?5,?12,?9,?21],?reversed_cmp)?[36,?21,?12,?9,?5]
sorted()也可以對字符串進行排序,字符串默認按照ASCII大小來比較:
>>>?sorted(['bob',?'about',?'Zoo',?'Credit'])?['Credit',?'Zoo',?'about',?'bob']
'Zoo'排在'about'之前是因為'Z'的ASCII碼比'a'小。
查看全部 -
python中filter()函數
filter()函數是?Python?內置的另一個有用的高階函數,filter()函數接收一個函數 f?和一個list,這個函數?f?的作用是對每個元素進行判斷,返回 True或 False,filter()根據判斷結果自動過濾掉不符合條件的元素,返回由符合條件元素組成的新list。
例如,要從一個list [1, 4, 6, 7, 9, 12, 17]中刪除偶數,保留奇數,首先,要編寫一個判斷奇數的函數:
def?is_odd(x):?????return?x?%?2?==?1
然后,利用filter()過濾掉偶數:
filter(is_odd,?[1,?4,?6,?7,?9,?12,?17])
結果:[1, 7, 9, 17]
利用filter(),可以完成很多有用的功能,例如,刪除 None 或者空字符串:
def?is_not_empty(s):?????return?s?and?len(s.strip())?>?0?filter(is_not_empty,?['test',?None,?'',?'str',?'??',?'END'])
結果:['test', 'str', 'END']
注意:?s.strip(rm) 刪除 s 字符串中開頭、結尾處的 rm 序列的字符。
當rm為空時,默認刪除空白符(包括'\n', '\r', '\t', ' '),如下:
a?=?'?????123'?a.strip()
結果:?'123'
a='\t\t123\r\n'?a.strip()
結果:'123'
查看全部 -
python中reduce()函數
reduce()函數也是Python內置的一個高階函數。reduce()函數接收的參數和 map()類似,一個函數 f,一個list,但行為和 map()不同,reduce()傳入的函數 f 必須接收兩個參數,reduce()對list的每個元素反復調用函數f,并返回最終結果值。
例如,編寫一個f函數,接收x和y,返回x和y的和:
def?f(x,?y):?????return?x?+?y
調用?reduce(f, [1, 3, 5, 7, 9])時,reduce函數將做如下計算:
先計算頭兩個元素:f(1,?3),結果為4;?再把結果和第3個元素計算:f(4,?5),結果為9;?再把結果和第4個元素計算:f(9,?7),結果為16;?再把結果和第5個元素計算:f(16,?9),結果為25;?由于沒有更多的元素了,計算結束,返回結果25。
上述計算實際上是對 list 的所有元素求和。雖然Python內置了求和函數sum(),但是,利用reduce()求和也很簡單。
reduce()還可以接收第3個可選參數,作為計算的初始值。如果把初始值設為100,計算:
reduce(f,?[1,?3,?5,?7,?9],?100)
結果將變為125,因為第一輪計算是:
計算初始值和第一個元素:f(100, 1),結果為101。
查看全部 -
python中map()函數
map()是 Python 內置的高階函數,它接收一個函數 f?和一個?list,并通過把函數 f 依次作用在 list 的每個元素上,得到一個新的 list 并返回。
例如,對于list [1, 2, 3, 4, 5, 6, 7, 8, 9]
如果希望把list的每個元素都作平方,就可以用map()函數。
因此,我們只需要傳入函數f(x)=x*x,就可以利用map()函數完成這個計算:
def?f(x): ????return?x*x print?map(f,?[1,?2,?3,?4,?5,?6,?7,?8,?9])
輸出結果:
[1,?4,?9,?10,?25,?36,?49,?64,?81]
注意:map()函數不改變原有的 list,而是返回一個新的 list。
利用map()函數,可以把一個 list 轉換為另一個 list,只需要傳入轉換函數。
由于list包含的元素可以是任何類型,因此,map() 不僅僅可以處理只包含數值的 list,事實上它可以處理包含任意類型的 list,只要傳入的函數f可以處理這種數據類型。
查看全部
舉報