[PYTHON] 核心编程笔记(11.Python函数和函数式编程)

11.1 什么是函数?


函数式对程序逻辑进行结构化或过程化的一种编程方法,能够整块代码巧妙地隔离成易于管理的小块


以下为创建,使用,或引用函数的方法:

declaration/definition def foo(): print 'bar'

function object/reference foo

function call/invocation foo()


11.1.1 函数 vs 过程


11.1.2 返回值与函数类型


函数会向调用者返回一个值


下面hello() 函数的行为就像一个过程,没有返回值,如果保存了返回值,该值为None


>>> def hello():          

...    print 'hello world'

...

>>> res = hello()        

hello world

>>> hello()

hello world

>>> res

>>> print res

None

>>> type(res)

<type 'NoneType'>

>>> type(hello())

hello world

<type 'NoneType'>


python 里的函数可以返回一个值或者对象


>>> def foo():

...    return ['xyz', 100000, -98.6]

...

>>> def bar():

...    return 'abc', [42,'python'], "Guido"

...

>>> foo()

['xyz', 100000, -98.6]

>>> bar()

('abc', [42, 'python'], 'Guido')


foo函数返回一个列表,bar()函数返回一个元祖,由于元祖语法上不需要一定带上圆括号,所以让人真的以为可以i返回多个对象,如果我们要恰当地给这个元祖加上括号,bar()的定义看起来会是这样:


>>> def bar():

...    return ('abc', [42, 'python'], 'Guido')

...

>>> bar()

('abc', [42, 'python'], 'Guido')


从返回值角度考虑,可以通过很多方式来存储元祖:


>>> aTuple = bar()

>>> x, y, z = bar()

>>> (a, b, c) = bar()

>>>

>>> aTuple

('abc', [42, 'python'], 'Guido')

>>> x, y, z

('abc', [42, 'python'], 'Guido')

>>> (a, b, c)

('abc', [42, 'python'], 'Guido')


11.2  调用函数


11.2.1 函数操作符


11.2.2 关键字参数


通过函数调用中的参数名字来区分参数,这样规范允许参数缺货死或不按顺序,因为解释器能通过给出的关键字来匹配参数的值:

例:


def foo(x):

   foo_suite # presumably does some processing with 'x'


标准调用 foo() foo(42) foo('bar') foo(y)

关键字调用 foo() foo(x=42) foo(x='bar') foo(x=y)


例,假设一个函数叫net_conn(),需要两个参数host和port:


def net_conn(host,port):

   net_conn_suite


只要按照函数声明中参数定义的顺序输入恰当的参数,自然就可以调用这个函数

net_conn('kappa',8080)


host参数得到字符串'kappa',port参数得到整数8080,也可以不按顺序输入,但要输入相应的参数名:

net_conn(port=8080,host='chino')


当参数缺失,可以使用默认参数


11.2.3 默认参数:

默认参数就是声明了默认值的参数


11.2.4 参数组:

Python同样允许执行一个没有显式定义参数的函数,相应的方法是通过一个把元祖(非关键字参数)或字典(关键字参数)作为参数组传递给函数


func(*tuple_grp_nonkw_args,**dict_grp_kw_args)


tuple_grp_nonkw_args是以元祖形式体现的非关键字参数组

dict_grp_kw_args是装有关键字参数的字典


你也可以给出形参! 这些参数包括标准的位置参数和关键字参数


func(positonal_args,keyword_args,*tuple_grp_nonkw_args,**dict_grp_kw_args)


例:随机选择数字及一个算术函数,显示问题,以及验证结果,在3次错误尝试以后给出结果,等到用户输入一个正确的答案后便会继续运行:


# vi easyMath.py

----------------------------

#!/usr/bin/env python


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 'correct'

               break

           if oops == MAXTRIES:

               print 'answer\n%s%d' %(pr,ans)

           else:

               print 'incorrect... try again'

               oops += 1

       except (KeyboardInterrupt,EOFError,ValueError):

           print 'invalid input... try again'


def main():

   while True:

       doprob()

       try:

           opt =raw_input('Again?[y]').lower()

           if opt and opt[0] == 'n':

               break

       except(KeyboadInterrupt,EOFError):

           break


if __name__ == '__main__':

   main()

----------------------------

注:

ans = ops[op](*nums)

ops = {'+':add,'-':sub} 是个字典

op则等于+或者-,   假设op是'+'则ops[op] 则取出add这个函数

而后面的(*nums)则相当于将nums中的元素依次作为参数传递给add这个函数比如nums = [3,4]

则ops[op](*nums) 相当于 add(3,4)


至于这样的调用函数的形式你可以去看下python2.x的内置函数apply这里的ops[op]相当于apply的functions函数*nums相当于apply的args函数


11.3 创建函数

11.3.1 def语句

函数是用def语句来创建的,语法如下:

def function_name(arguments):

   "function_documentation_string"

function_body_suite


>>> def helloSomeone(who):

...     'returns a salutory string customized with the input'

...     return "Hello " + str(who)

...

>>> helloSomeone('haha')

'Hello haha'


11.3.2 声明与定义比较


11.3.3 前向引用


Python不允许在函数未声明之前,对其进行引用或者调用

>>> def foo():

...     print 'in foo()'

...     bar()


如果我们调用函数foo(),肯定会失败,因为函数bar()未声明:


>>> foo()

in foo()

Traceback (most recent call last):

 File "<stdin>", line 1, in <module>

 File "<stdin>", line 3, in foo

NameError: global name 'bar' is not defined


现在定义函数bar(),在函数foo()前给出bar()声明:

>>> def bar():

...    print 'in bar()'

...

>>> def foo():

...    print 'in foo()'

...    bar()

...


现在可以安全调用foo()

>>> foo()

in foo()

in bar()


我们可以在函数bar()前定义函数foo()

>>> def foo():

...    print 'in foo()'

...    bar()

...

>>> def bar():

...    print 'in bar()'


仍旧非常好的运行,不会有前向引用问题

因为我们声明foo(),然后再声明bar(),接着调用foo(),但那时,bar()已经存在,所以调用成功

>>> foo()

in foo()

in bar()


11.3.4 函数属性


import foo, bar

print foo.x + bar.x


>>> def foo():

...    'foo() -- properly created doc string'

...

>>> def bar():

...     pass

...

>>> bar.__doc__ = '0ops, forgot the doc str above'

>>> bar.version = 0.1


>>> help(foo)

Help on function foo in module __main__:


foo()

   foo() -- properly created doc string

>>> print bar.version

0.1

>>> print foo.__doc__

foo() -- properly created doc string


>>> print bar.__doc__

0ops, forgot the doc str above


11.3.5 内部/内嵌函数

在函数体内创建另一个函数是完全合法的,这种函数叫做内部/内嵌函数


创建内部函数的方法是在外部函数的定义体内定义函数(用def关键字)


>>> def foo():              

...   def bar():            

...     print 'bar() called'

...     print 'foo() called'

...   bar()  

...

>>> foo()

bar() called

foo() called

>>> bar()

Traceback (most recent call last):

 File "<stdin>", line 1, in <module>

NameError: name 'bar' is not defined


内部函数在于整个函数体都在外部函数的作用于之内,如果没有任何对bar()的外部引用,那么除了函数体内,任何地方都不能对其进行调用,上述代码异常的原因就是如此


11.3.6 函数(与方法)装饰器


装饰器的语法以@开头,接着是装饰器的名字和可选册数

下面是被修饰的函数,和装饰函数的可选参数:


@decorator(dec_opt_args)

def func2Bdecorated(func_opt_args):


例:

class MyClass(object):

   @staticmethod

   def statciFoo():

   ..


@deco2

@deco1


def func(arg1,arg2,...):pass

这和创建一个组合函数是等价的


函数组合用数学来定义就像这样: (g * f)(x) =g(f(x)) 对于在python中的一

致性


@g

@f

def foo():

...


什么时候使用带参数的装饰器:


无参数装饰器:

@deco

def foo(): pass


....非常直接


foo = deco(foo)


有参数装饰器:


@decomaker(deco_args)

def foo(): pass

...


foo =decomaker(deco_args)(foo)


@deco1(deco_arg)

@deco2

def func():pass

This is equivalent to: 这等价于

func = deco1(deco_arg)(deco2(func))


装饰器实际就是函数,我们在运行函数之前可以运行一些预备代码,之后做一些清理工作

1.可以引入日志

2.增加计时逻辑来检测性能

3.给函数加入事务能力


例:

-------------------------------

#!/usr/bin/env python


from time import ctime, sleep


def tsfunc(func):

   def wrappedFunc():

       print '[%s] %s() called' %(ctime(),func.__name__)

       return func()

   return wrappedFunc


@tsfunc

def foo():

   pass


foo()

sleep(4)


for i in range(2):

   sleep(1)

   foo()

-------------------------------


# python decp.py

[Wed Oct 23 03:10:58 2013] foo() called

[Wed Oct 23 03:11:03 2013] foo() called

[Wed Oct 23 03:11:04 2013] foo() called


11.4 传递函数:

所有对象都是通过引用来传递的,函数也不例外:

>>> def foo():

...    print 'in foo()'

...

>>> bar = foo

>>> bar()

in foo()


当我们把foo赋值给bar时,bar和foo引用了同一个函数对象,所以能以和调用foo()相同的方式来调用bar().


我们甚至可以把函数作为参数传入其他函数来进行调用


>>> def bar(argfunc):

...    argfunc()

...

>>> bar(foo)

in foo()


例:传递和调用(内建)函数:


# vi numConv.py

--------------------------

#!/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, 9999999999L)


print convert(int, myseq)

print convert(long, myseq)

print convert(float,myseq)

--------------------------


# python numConv.py    

[123, 45, -620000000, 9999999999L]

[123L, 45L, -620000000L, 9999999999L]

[123.0, 45.67, -620000000.0, 9999999999.0]


11.5 形式参数:

python函数的形参集合由在调用时要传入参数的所有参数组成


11.6 位置参数:

这些都是我们熟悉的标准化参数.

>>> 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)


foo()函数有一个位置参数,那意味着任何对foo()的调用必须有唯一的一个参数

否则会报TypeError异常


11.5.2 默认参数

对于默认参数如果在函数调用时没有为参数提供值则使用预先定义的默认值

python中用默认值生命变量的语法是所有的位置参数必须出现在任何一个默认参数之前


def func(posargs, defarg1=dvall, defarg2=dval2,...):

   'function_documentation_string'

   function_body_suite

每个默认参数都紧跟一个用默认值的赋值语句,如果在函数调用时木有给出值,那么这个赋值就会实现.


>>> def taxMe(cost, rate=0.0825):      

...     return cost + (cost * rate)    

...

>>> taxMe(100)                    

108.25

>>> taxMe(100,0.05)

105.0


如果没有按正确的顺序给出参数,就会产生一个语法错误:

>>> def taxMe2(rate=0.0825, cost):

...     return cost * (1.0 + rate)

...

 File "<stdin>", line 1

SyntaxError: non-default argument follows default argument


让我们再看下关键字参数:

def net_conn(host,port):

   net_conn_suite


如果命名了参数,这里可以不按顺序给出参数

net_conn('kappa',8000)

net_conn(port=8080,host='chino')


如果我们将默认参数引入这个模式

def net_conn(host,port=80,stype='tcp'):

   net_conn_suite


未使用默认参数:

net_conn('phaze', 8000,'udp')

使用默认参数:

net_conn('kappa')

net_conn('chino', stype='icmp')

net_conn(stype='udp',host='solo')

net_conn('deli',8080)

net_conn(port=81, host='chino')


例:

--------------------------

#!/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()

--------------------------




11.6 可变长度的参数:


11.6.1 非关键字可变长参数(元组)


def function_name([formal_args] *vargs_tuple):

   'function_documentation_string'

   function_body_suite


例:

>>> def tupleVarArgs(arg1, arg2='default8', *theRest):      

...      'display regular args and non-keyword variable args'

...      print 'formal arg 1:', arg1                        

...      print 'formal arg 2:', arg2

...      for eachXtrArg in theRest:                          

...         print 'another arg:' , eachXtrArg                

...

>>> tupleVarArgs('abc')                                      

formal arg 1: abc

formal arg 2: default8

>>> tupleVarArgs(23,4.56)

formal arg 1: 23

formal arg 2: 4.56

>>> tupleVarArgs('abc',123,'xyz',456.789)

formal arg 1: abc

formal arg 2: 123

another arg: xyz

another arg: 456.789


11.6.2 关键字变量参数(Dictionary)

def function([formal_args,][*vargst,] **vargsd):

   function_documentation_string function_body_suite


最后一个的参数是使用了**的关键字变量参数

例:

>>> def dictVarArgs(arg1, arg2='default8', **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: default8

Xtra arg men: ('freud', 'gaudi')

Xtra arg e: zoo

Xtra arg d: 10


关键字和非关键字可变长参数都有可能用在同一个函数中,只要关键字字典是最后一个参数并且非关键字元组先于它之前出现:

>>> 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.keys():

...       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


11.6.3 调用带有可变长参数对象函数:


>>> 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


>>> 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


最终,我们将在另外进行一次调用,但是是在函数调用之外来创建我们的元组和字典.

>>> aTuple = (6,7,8)

>>> aDict = {'z':9}

>>> 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


函数式编程举例:

# vi testit.py

-----------------------------

#!/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, long, float)

   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()

-----------------------------


单元测试函数test()在一个为4个数字的输入集合运行了一个数字转换函数的集合,为了确定这样的功能,在测试中有两个失败的案例,这里是运行脚本的输出:


# python testit.py

--------------------

int(eachVal) = 1234

int(eachVal) = 12

int(eachVal) = 1234

int(eachVal) = FAILED: invalid literal for int() with base 10: '12.34'

--------------------

long(eachVal) = 1234

long(eachVal) = 12

long(eachVal) = 1234

long(eachVal) = FAILED: invalid literal for long() with base 10: '12.34'

--------------------

float(eachVal) = 1234.0

float(eachVal) = 12.34

float(eachVal) = 1234.0

float(eachVal) = 12.34


11.7 函数式编程


11.7.1 匿名函数与lambda


lambda [arg1[,arg2, ...argN]]:expression


def true():

   return True


Python中单行函数可以和标题写在同一行

def true(): return True


利用匿名函数lambda写法实现上面函数的效果:

lambda : True


例:

>>> def true(): return True

...

>>> true()

True

>>> lambda : True

<function <lambda> at 0x8f9c374>

>>> true = lambda :True

>>> true()

True


我们可以把lambda表达式赋值给一个如列表和元组的数据结构

例:我们设计一个带两个数字或字符串参数,返回数字之和或者已拼接的字符串的函数


def add(x,y): return x + y

lambda x,y :x + y


默认以及可变参示例:

def usualllyAdd2(x,y=2): return x+y

lambda x,y=2: x+y

def showAllAsTuple(*z): return z

lambda *z : z


实例:

>>> true = lambda :True

>>> true()

True

>>> a = lambda x,y=2: x + y

>>> a(3)

5

>>> a(3,5)

8

>>> a(0,9)

9

>>> b= lambda *z: z

>>> b(23,'zyz')

(23, 'zyz')

>>> b(42,)

(42,)


11.7.2 内建函数 apply(),filter(),map(),reduce()

apply(func[, nkw][, kw])

用可选的参数来调用func,nkw为非关键字参数,kw为关键字参数,返回值是函数调用的返回值


filter(func,seq)

调用一个布尔函数func来迭代遍历每个seq中的元素,返回一个使func返回值为true的元素的序列

def filter(bool_func, seq):

   filtered_seq = []

   for eachItem in seq:

       if bool_func(eachItem):

   filtered_seq.append(eachItem)

return filtered_seq


例:

# vi oddnogen.py

---------------------

#!/usr/bin/env python

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)

---------------------

odd()用来对一个整数取余,如果返回0为偶数,返回1为奇数

后面阐述10个在1到100的随机数,然后调用filter(),过滤掉返回值0即为假的偶数,剩下的即为奇数.

输出:

# python oddnogen.py

[33, 73, 85, 41]

# python oddnogen.py

[45, 77, 49, 85, 35, 21]

# python oddnogen.py

[21, 93, 99]

# python oddnogen.py

[75, 59, 73, 85, 31, 31, 33, 37, 29]


第一次重构,利用lambda表达式:

--------------------------------

#!/usr/bin/env python

from random import randint


allNums = []

for eachNum in range(9):

   allNums.append(randint(1,99))

print filter(lambda n: n%2,allNums)

--------------------------------

# python oddnogen1.py

[7, 73, 39, 77, 61, 9, 61]

# python oddnogen1.py

[31, 57, 63, 23, 3, 65]


重构2,利用list迭代解析

----------------------------

#!/usr/bin/env python

from random import randint


allNums = []

for eachNum in range(9):

   allNums.append(randint(1,99))

print [n for n in allNums if n%2]

----------------------------

# python oddnogen2.py

[59, 57, 59, 75, 37]

# python oddnogen2.py

[99, 89, 49, 71, 45, 3]


重构3: 列表解析简化

-------------------------

#!/usr/bin/env python

from random import randint as ri

print [n for n in [ri(1,99) for i in range(9)] if n%2]

-------------------------

# python oddnogen3.py

[11, 7, 35, 71, 87]

# python oddnogen3.py

[83, 61, 17, 13, 21, 55]


map(func,seq1[,seq2...])

将函数func作用于给定序列的每个元素,并用一个列表来提供返回值,如果func为None,func表现为一个身份函数,返回一个含有每个序列中元素集合的N个元组列表

def map(func,seq):

mapped_seq=[]

for eachItem in seq:

   mapped_seq.append(func(eachItem))

return mapped_seq

例:

>>> 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]

>>> [x+2 for x in range(6)]

[2, 3, 4, 5, 6, 7]

>>> [x**2 for x in range(6)]

[0, 1, 4, 9, 16, 25]

多个序列的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])                          

[(1, 2), (3, 4), (5, 6)]

>>> zip([1,3,5],[2,4,6])

[(1, 2), (3, 4), (5, 6)]



reduce(func,seq[, init])

将二元函数作用于seq序列的元素,每次携带一对,连续的将现有的结果和下雨给值作用在获得的随后结果上,最后减少我们的序列为一个单一返回值,如果初始值init给定,第一个比较会是init和第一个序列元素而不是序列的头两个元素

reduce(func,[1,2,3]) = func(func(1,2),3)


if init is None:

   res = lseq.pop(0)

else:

   res = init

for item in lseq:

   res = bin_func(res, item)

   return res


例:

>>> def mySun(x,y): return x+y

...

>>> lambda x,y: x+y

<function <lambda> at 0x89c9374>

---------------------------------

>>> 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

-----------------------------------

简化:

>>> print 'the total is:',reduce((lambda x,y: x+y),range(5))

the total is: 10

给出了上面的输入,reduce()函数运行了如下算数操作:

((((0 + 1) + 2) + 3) + 4) => 10


注:用 list 的头两个元素(0,1),调用mySum()来得到1,然后用现在的结果和下一个元素2来再次调用mySum(),再用这次调用中获得结果,与下面的元素3配对然后调用mySum(),最终拿整个前面的求和和4来调用mySum()得到10,10即为最终返回值


11.7.3 偏函数应用:

简单的函数式例子:


>>> 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(10)

11

>>> add1(1)

2

>>> mul100(10)

1000

>>> mul100(500)

50000


将二进制(作为字符串) 转化为整数:


>>> int('10010',2)

18

>>> baseTwo = partial(int,base=2)

>>> baseTwo.__doc__ = 'Convert base 2 string to an int.'

>>> baseTwo('10010')

18


这个例子使用了int()内建函数并将base固定为2来制定二进制字符串转化


警惕关键字:


如果你创建了不带base关键字的偏函数,会让参数以错误的顺序传入int(),因为固定参数的总是放在运行时参数的左边

比如: baseTwoBAD(x) = int(2,x)

2会作为需要转化的数字,base作为'10010'来传入,从而产生一个异常:


>>> baseTwoBAD = partial(int,2)

>>> baseTwoBAD('10010')

Traceback (most recent call last):

 File "<stdin>", line 1, in <module>

TypeError: an integer is required


# vi ppfaGUI.py

----------------------------

#!/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()

----------------------------


11.8 变量作用域


11.8.1 全局变量与局部变量:


global_str = 'foo'

def foo():

   local_str = 'bar'

   return global_str + local_str


global_str是全局变量,而local_str是局部变量,foo()函数可以对全局和局部变量进行访问,而代码主体部分只能访问全局变量


11.8.2 globa语句:

如果将全局变量的名字声明在一个函数体内,全局变量的名字能被局部变量给覆

盖掉


defoo():

   print "\ncallingfoo"

   bar =200

   print "in foo(),bar is",bar

bar =100

print "in_main_,bar is",bar foo()

print "\nin__main__,bar is (still), bar


例子:

>>> is_this_global = 'xyz'  

>>> def foo():                              

...     global is_this_global              

...     this_is_local = 'abc'              

...     is_this_global = 'def'      

...     print this_is_local + is_this_global

...

>>> foo()

abcdef

>>> print is_this_global

def


11.8.3 作用域的数字


>>> def foo():      

...    m = 3        

...    def bar():    

...       n = 4      

...       print m + n

...    print m

...    bar()

...

>>> foo()

3

7


11.8.4 闭包

闭包将内部函数自己的代码和作用于以及外部函数的作用结合起来,闭包的词法变量不属于全局名字空间域或者局部的一而属于其他的名字空间

>>> def counter(start_at=0):

...     count = [start_at]

...     def incr():

...         count[0] += 1

...         return count[0]

...     return incr

...

>>> count = counter(5)

>>> print count()

6

>>> print count()

7

>>> count2 = counter(100)

>>> print count2()

101

>>> print count()

8

>>> print count2()

102


11.8.5 作用域和lambda

python的lambda匿名函数遵循和变准函数一样的作用域规则,一个lambda表达式定义了新的作用域,就像函数定义,所以这个作用域除了局部lambda函数,对于程序其他部分,该作用域都是不能对进行访问的


>>> x = 10

>>> def foo():

...     y = 5

...     bar = lambda : x + y

...     print bar()

...

>>> foo()

15


11.8.6 变量作用域和名字空间


任何时候,总有一个或两个活动的作用域,我们要么只能访问全局作用域的模块的最高级,要么在一个我们能访问局部作用域和全局作用域的函数体内执行


例: 局部变量隐藏了全局变量(有问题)


# vi scope.py

-------------------------------

#!/usr/bin/env python

j, k = 1, 2


def procl():

   j, k = 3, 4

   print "j == %d and k == $d" % (j,k)

   k = 5


   def proc2():

       j = 6

       procl()

       print "j == %d and k == %d" % (j,k)


       j = 7

       procl()

       print "j == %d and k == %d" % (j,k)


       j = 8

       procl2()

       print "j == %d and k == %d" % (j,k)

-------------------------------


11.9 *递归


如果函数包含了对其自身的调用,该函数就是递归的


def factorial(n):

   if n ==0 or n==1:

return 1

   else:

return (n*factorial(n-1))


11.10 生成器


11.10.1 简单的生成器特性:

当到达一个真正的返回或者函数结束没有更多值返回,一个StopIteration异常就会抛出

>>> def simpleGen():

...     yield 1

...     yield '2 --> punch!'

...

>>> myG = simpleGen()

>>> myG.next()

1

>>> myG.next()

'2 --> punch!'

>>> myG.next()

Traceback (most recent call last):

 File "<stdin>", line 1, in <module>

StopIteration


使用for循环穿过一个生成器:

>>> for eachItem in simpleGen():

...     print eachItem

...

1

2 --> punch!


创建一个带序列并从那个序列中返回一个随机元素的随机迭代器:(有问题)


>>> from random import randint                        

>>> def randGen(aList):                                

...     while len(aList) > 0:                          

...         yield aList.pop(randint(0,len(aList)))    

...

>>> for item in randGen(['rock', 'paper', 'scissors']):

...     print item

...

rock


11.10.2 加强的生成器特性:


>>> def counter(start_at=0):

...     count = start_at

...     while True:

...         val = (yield count)

...         if val is not None:

...             count = val

...         else:

...             count +=1

...


生成器带有一个初始化的值,对每次对生成器[next()]调用以1累加计数,用户已可以选择重置这个值,如果他们非常想要用新的值来调用send()不是调用next(),这个生成器是永远运行的,所以终结他,调用close()方法


>>> count = counter(5)

>>> count.next()

5

>>> count.next()

6

>>> count.send(9)

9

>>> count.next()

10

>>> count.close()

>>> count.next()

Traceback (most recent call last):

 File "<stdin>", line 1, in <module>

StopIteration


你可能感兴趣的:(python,函数式编程,核心编程笔记)