python核心編程-第十一章-我的筆記(一)

1.  調用函數python

    1.1  關鍵字參數和默認參數web

        關鍵字參數調用函數容許用戶缺失參數或者不按順序給定參數。默認參數則是聲明瞭默認值的參數。以下例:shell

def power(a, b=2):
    print a ** b

power(b=3,a=4)

    1.2  實例  easyMath.py編程

#!/usr/bin/env python
# -*- coding:utf-8 -*-
from operator import add, sub
from random import randint, choice

ops = {'+': add, '-': sub}
MAXTRIES = 2

def doprob():
    op = choice('+-')
    nums = [randint(1, 10) for i in range(2)]
    nums.sort(reverse=True)
    ans = ops[op](*nums)
    pr = '%d %s %d=' %(nums[0], op, nums[1])
    oops = 0
    while True:
        try:
            if int(raw_input(pr)) == ans:
                print u'解對了'
                break
            if oops == MAXTRIES:
                print u'應該是:\n%s%d' % (pr, ans)
            else:
                print u'解錯了。。。再拭一次'
                oops += 1
        except (KeyboardInterrupt, EOFError, ValueError):
            print u'無效輸入。。。再試一次'
            

def main():
    while True:
        doprob()
        try:
            opt = raw_input(u'繼續? [Y]'.encode('gbk')).lower()
            if opt and opt[0] == 'n':
                break
        except (KeyboardInterrupt, EOFError):
            break
            
if __name__ == '__main__':
    main()

2. 建立函數app

    2.1  函數能夠具備屬性,用句點表示 dom

def foo():
    pass
foo.__doc__ = "This is foo's doc string"
foo.version = 0.1

   2.2  內嵌函數
函數式編程

Python支持在函數體內建立另一個函數,這種函數叫內嵌函數。但要注意內嵌函數的做用域。函數

以下代碼:oop

def foo():
    def bar():
        print "bar() called"
    print "foo() called"
    bar()
    
foo()
bar()

其執行結果以下:ui

    2.3  裝飾器

        2.3.1  裝飾器相關介紹見https://www.zhihu.com/question/26930016

        裝飾器以@開頭,這裏有個語法糖,即

@deco2
@deco1
def func(arg1, arg2, ...):pass

        和如下代碼是等價的:

def func(arg1, arg2, ...):pass
func = deco2(deco1(func))

        2.3.2  裝飾器實際上就是接受函數對象做爲參數的函數,返回一個修改後的函數對象,並將其從新賦值給原函數標識符,永久失去對原函數對象的訪問。

        2.3.3  使用裝飾器的例子

#!/usr/bin/env python

from time import ctime, sleep

def tsfunc(func):
    def wrappenFunc():
        print '[%s] %s() called' %(
            ctime(), func.__name__)
        return func
    return wrappenFunc
    
@tsfunc
def foo():
    pass 
    
foo()
sleep(4)

for i in range(2):
    sleep(1)
    foo()


3.  傳遞函數

    3.0  python中,函數也是對象,也是能夠被其餘變量引用的:

>>> def foo():
...     print "in foo()"
...
>>> bar = foo
>>> bar()
in foo()
>>> bar
<function foo at 0x00000000024FD978>
>>> ber = foo()
in foo()
>>> type(bar)
<type 'function'>
>>> type(ber)
<type 'NoneType'>

    函數也能夠做爲參數傳遞給其餘函數調用:

>>> def bar(argfunc):
...     argfunc()
...
>>> bar(foo)
in foo()

    3.1  關於函數傳遞的實例

#!usr/bin/env python

def convert(func, seq):
    'conv. sequence of numbers to same type'    # 將序列中的數字轉換爲同一類型,類型由轉換函數給出
    return [func(eachNum) for eachNum in seq]
    
myseq = (123, 45.67, -6.2e8, 999999999L)
print convert(int, myseq)
print convert(long, myseq)
print convert(float, myseq)

   輸出:

4.  形式參數(形參)

    4.1  Python函數的形參集合包括全部必要參數(以正確的定位順序傳入函數)、關鍵字參數(以順序傳入,或不以順序傳入,但指定了參數列表中曾定義的關鍵字)和全部在函數定義時指明瞭默認值的函數。下面將分別敘述。

    4.2  位置參數

        位置參數必須以在函數中定義的順序來準確傳遞。另外,若沒有設定默認參數值,則傳入參數的數目必須和函數定義的數目精確一致。    

>>> def foo(who):
...     print 'Hello', who
...
>>> foo()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError:foo() takes exactly 1 argument (0 given)
>>>
>>> foo('World')
Hello World
>>> foo('Mr.', 'World')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError:foo() takes exactly 1 argument (2 given)

    4.3  例子

#!/usr/bin/env python

from urllib import urlretrieve

def firstNonBlank(lines):
    for eachline in lines:
        if not eachline.strip():
            continue
        else:
            return eachline
    
def firstLast(webpage):
    f = open(webpage)
    lines=f.readlines()
    f.close()
    print firstNonBlank(lines)
    lines.reverse()
    print firstNonBlank(lines)
    
def download(url='http://www.baidu.com', 
        process=firstLast):
    try:
        retval = urlretrieve(url)[0]
    except IOError:
        retval = None
    if retval:
        process(retval)
        
if __name__ == '__main__':
    download()

5.可變參數

    5.1  可變長度的參數包括非關鍵字可變長參數即元組和關鍵字變量參數即字典,其中關鍵字變量參數必須在最後。

    A.  非關鍵字可變長參數

def tupleVarArgs(arg1, arg2='defaultB', *theRest):
    'display regular args and non-keyword variable args'
    print 'formal arg1:', arg1
    print 'formal arg2:', arg2
    for eachXtrArg in theRest:
        print 'another arg:', eachXtrArg

    執行結果:

>>> tupleVarArgs('abc')
formal arg1: abc
formal arg2: defaultB
>>> 
>>> tupleVarArgs(23, 4.56)
formal arg1: 23
formal arg2: 4.56
>>>
>>> tupleVarArgs('abc', 123, 'xyz', 456.789)
formal arg1: abc
formal arg2: 123
another arg: xyz
another arg: 456.789

    B.關鍵字變量參數

def dictVarArgs(arg1, arg2='defaultB', **theRest):
    'display 2 regular args and keyword variable args'
    print 'formal arg1:', arg1
    print 'formal arg2:', arg2
    for eachXtrArg in theRest.keys():
        print "Xtra arg %s: %s" % \
          (eachXtrArg, str(theRest[eachXtrArg]))

    執行結果:

>>> dictVarArgs(1220, 740.0, c='grail')
formal arg1: 1220
formal arg2: 740.0
Xtra arg c: grail
>>>
>>> dictVarArgs(arg2='tales', c=123, d='poe', arg1='mystery')
formal arg1: mystery
formal arg2: tales
Xtra arg c: 123
Xtra arg d: poe
>>>
>>> dictVarArgs('one', d=10, e='zoo', men=('freud', 'gaudi'))
formal arg1: one
formal arg2: defaultB
Xtra arg men: ('freud', 'gaudi')
Xtra arg e: zoo
Xtra arg d: 10
>>>

    C. 混合型

def newfoo(arg1, arg2, *nkw, **kw):
    'display regular args and all variable args'
    print 'arg1 is:', arg1
    print 'arg2 is:', arg2
    for eachNKW in nkw:
        print 'additional non-keyword arg:', eachNKW
    for eachKW in kw:
        print "additional keyword arg '%s': %s" % \
            (eachKW, kw[eachKW])

    執行結果:

>>> newfoo('wolf', 3, 'projects', freud=90, gamble=96)
arg1 is: wolf
arg2 is: 3
additional non-keyword arg: projects
additional keyword arg 'gamble': 96
additional keyword arg 'freud': 90
>>>

   5.2  更多的調用可變參數的例子

    A.經典風格

>>> newfoo(10, 20, 30, 40, foo=50, bar=60)
arg1 is: 10
arg2 is: 20
additional non-keyword arg: 30
additional non-keyword arg: 40
additional keyword arg 'foo': 50
additional keyword arg 'bar': 60

    B.能夠非關鍵字參數放在元組中、關鍵字參數放在詞典中調用,而不是逐個列出

>>> newfoo(2, 4, *(6, 8), **{'foo': 10, 'bar': 12})
arg1 is: 2
arg2 is: 4 
additional non-keyword arg: 6
additional non-keyword arg: 8
additional keyword arg 'foo': 10
additional keyword arg 'bar': 12

    C.先建立元組和字典,再給函數調用

>>> newfoo(1, 2, 3, x=4, y=5, *aTuple, **aDict)
arg1 is: 1
arg2 is: 2
additional non-keyword arg: 3
additional non-keyword arg: 6
additional non-keyword arg: 7
additional non-keyword arg: 8
additional keyword arg 'y': 5
additional keyword arg 'x': 4
additional keyword arg 'z': 9

     上例說明,在已定義的元組和列表以外的參數,也能夠被函數調用

    5.3 函數式編程例子

#!/usr/bin/env python

def testit(func, *nkwargs, **kwargs):

    try:
        retval = func(*nkwargs, **kwargs)
        result = (True, retval)
    except Exception, diag:
        result = (False, str(diag))
    return result
  
def test():
    funcs = (int, float, long)
    vals = (1234, 12.34, '1234', '12.34')
    
    for eachFunc in funcs:
        print '_' * 20
        for eachVal in vals:
            retval = testit(eachFunc,eachVal)
            if retval[0]:
                print '%s(%s) = ' %(eachFunc.__name__, eachVal), retval[1]
            else:
     		    print '%s(%s) = FAILED' %(eachFunc.__name__, eachVal), retval[1]

if __name__ == '__main__':
    test()

6.  函數式編程

    6.1  匿名函數與lambda

        經過 lambda 與標準函數對比來理解

>>> def true(): return True
>>> lambda : True    # 與前者等價
>>> def add(x, y): return x + y
>>> lambda x, y: x + y 
>>> def usuallyAdd2(x, y=2): return x+y 
>>> lambda x, y=2: x+y 
>>> def showAllAsTuple(*z): return z
>>> lambda *z: z    # 以上每行 lambda 語句均等價於其上一行標準函數語句

        運行時的演示:

>>> a = lambda x, y=2: x + y
>>> a(3)
5
>>> a(3,5)
8
>>> a(0)
2
>>> a(0,9)
9
>>>
>>> b = lambda *z: z
>>> b(23, 'zyx')
(23, 'zyx')
>>> b(42)
(42,)

   6.2  內建函數apply()    filter()    map()    reduce()

        6.2.1  apply()已逐漸被淘汰

        6.2.2  filter()函數爲給定的序列對象每一個元素調用給定的布爾函數,將返回非零值的元素添加到一個列表中。list列表解析能夠代替filter。下面經過一段簡單代碼的重構來講明

    A.原始代碼

from random import randint
def odd(n):
    return n % 2

allNums = []
for eachNum in range(9):
    allNums.append(randint(1,99))
print filter(odd, allNums)

    B.

from random import randint
allNums = []
for eachNum in range(9):
    allNums.append(randint(1,99))
print filter(lambda n: n%2, allNums)    # 將簡單的 odd() 函數替換爲 lambda

    C.

from random import randint
allNums = []
for eachNum in range(9):
    allNums.append(randint(1,99))
print [n for n in allNums if n%2]    # 用列表解析來代替 filter()

    D .

from random import randint
print [n for n in [randint(1,99) for i in range(9)] if n%2]    # 繼續用列表解析來替代中間變量

        6.2.3  map()函數

        A.簡單的map()函數有一個函數和一個序列,將函數做用在序列的每一個元素上,而後建立每一個返回值組成的列表。

>>> map(lambda x: x+2, [0, 1, 2, 3, 4, 5])
[2, 3, 4, 5, 6, 7]
>>> map(lambda x: x**2, range(6))
[0, 1, 4, 9, 16, 25]

        B.通常的 map() 能夠接受多個序列,這種狀況下,map() 並行的迭代每一個序列,即將每一個序列的第一個元素捆綁到一個元組中,對元組調用給定的函數,並將函數返回值合併到一個序列上。

>>> map(lambda x, y: x + y, [1, 3, 5], [2, 4, 6])
[3, 7, 11]
>>> map(lambda x, y: (x+y, x-y), [1, 3, 5], [2, 4, 6])
[(3, -1), (7, -1), (11, -1)]
>>>
>>> map(None, [1, 3, 5], [2, 4, 6])   # 等價於 zip()
[(1, 2), (3, 4), (5, 6)]

        6.2.4  reduce()函數

        reduce() 函數使用一個二元函數、一個序列和一個可選的初始化器。它取出序列的頭兩個元素(未給定初始化器的狀況下;若給定初始化器,則取出序列的第一個元素和初始化器組合)調用二元函數,得到單一的返回值繼續和序列的下一個元素一塊兒調用二元函數,直到遍歷整個序列得出最後的值,返回這個值

例子:求一個列表全部值的和

def mySum(x, y): return x+y
allNums = range(5)
total = 0

for eachNum in allNums:
    total = mySum(total, eachNum)    # 利用循環求得
    
print 'the total is:', total

輸出

the total is 10

利用 reduce() 結合lambda

print reduce(lambda x, y: x+y, range(5))

輸出

the total is 10

    6.3  偏函數

        6.3.1  簡單例子

        經過如下簡單例子來理解 PFA(偏函數應用)

>>> from operator import add, mul  
>>> from functools import partial
>>> add1 = partial(add, 1)    # add1(x) == add(1, x)
>>> mul100 = partial(mul, 100)     # mul100(x) == mul(100, x)
>>> 
>>> add1(12)
13
>>> mul100(100)
10000
>>> mul100(500)
50000
>>> baseThree = partial(int, base=3)    # baseThree(str) == int(str, 3)
>>> baseThree('121212')
455

        6.3.2  注意關鍵字參數

        由於固定參數老是放在運行參數的左邊,因此若不注意關鍵字參數問題,很容易致使異常

>>> baseTwoBad = partial(int,2)    # baseTwoBad(x) == int(2,x)
>>> baseTwoBad('100100')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: an integer is required

        6.3.3  GUI類例子

#!/usr/bin/env python

from functools import partial
import Tkinter

root = Tkinter.Tk()
MyButton = partial(Tkinter.Button, root,
    fg='white', bg='blue')
b1 = MyButton(text='Button 1')
b2 = MyButton(text='Button 2')
qb = MyButton(text='QUIT', bg='red',
    command=root.quit)
b1.pack()
b2.pack()
qb.pack(fill=Tkinter.X, expand=True)
root.title('PFAs!')
root.mainloop()

7.變量做用域

    7.1  全局變量與局部變量

    定義在函數內的變量有局部做用域,在一個模塊中最高級別的變量有全局做用域

>>> global_str = 'foo'
>>> def foo():
...     local_str = 'bar'
...     return global_str + local_str
...
>>> foo()
'foobar'
>>> global_str
'foo'
>>> local_str
Traceback (most recent call list):
  File "<stdin>", line 1, in <module>
NameError: name 'local_str' is not defined

    上例中,global_str 是全局變量,local_str 是局部變量。foo() 函數能夠訪問全局變量和局部變量,代碼主題部分則只能訪問全局變量

    7.2  global 語句

def foo():
    print "\ncalling foo()..."
    bar = 200
    print "in foo(), bar is", bar
bar = 100
print "in __main__, bar is", bar 
foo()
print "\nin __main__, bar is (still)", bar

代碼輸出:    

in __main__, bar is 100

calling foo()...
in foo(), bar is 200

in __main__, bar is (still) 100

    上例代表,在函數體內的全局變量,會被函數體內定義的局部變量覆蓋掉。爲了明確的引用已命名的全局變量,就須要使用global 語句

>>> is_this_global = 'xyz'
>>> def foo():
...     global is_this_global      # global var1,var2...
...     this_is_local = 'abc'
...     is_this_global = 'def'
...     print this_is_local + is_this_global
...
>>> foo()
abcdef
>>> print is_this_global
def
相關文章
相關標籤/搜索