[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



     本文转自 showerlee 51CTO博客,原文链接:http://blog.51cto.com/showerlee/1335949,如需转载请自行联系原作者


相关文章
|
3天前
|
数据库 开发者 Python
实战指南:用Python协程与异步函数优化高性能Web应用
【7月更文挑战第15天】Python的协程与异步函数优化Web性能,通过非阻塞I/O提升并发处理能力。使用aiohttp库构建异步服务器,示例代码展示如何处理GET请求。异步处理减少资源消耗,提高响应速度和吞吐量,适用于高并发场景。掌握这项技术对提升Web应用性能至关重要。
23 10
Python函数:函数的定义和调用
本文详细介绍了Python函数的定义和调用方法,包括基本函数定义、参数传递、返回值、文档字符串、作用域、嵌套函数和闭包。通过一个综合详细的学生成绩管理系统的例子,我们展示了如何在实际编程中应用这些函数概念。希望本文对您理解和应用Python函数有所帮助。
|
3天前
|
数据处理 Python
深入探索:Python中的并发编程新纪元——协程与异步函数解析
【7月更文挑战第15天】Python 3.5+引入的协程和异步函数革新了并发编程。协程,轻量级线程,由程序控制切换,降低开销。异步函数是协程的高级形式,允许等待异步操作。通过`asyncio`库,如示例所示,能并发执行任务,提高I/O密集型任务效率,实现并发而非并行,优化CPU利用率。理解和掌握这些工具对于构建高效网络应用至关重要。
16 6
|
3天前
|
大数据 数据处理 API
性能飞跃:Python协程与异步函数在数据处理中的高效应用
【7月更文挑战第15天】在大数据时代,Python的协程和异步函数解决了同步编程的性能瓶颈问题。同步编程在处理I/O密集型任务时效率低下,而Python的`asyncio`库支持的异步编程利用协程实现并发,通过`async def`和`await`避免了不必要的等待,提升了CPU利用率。例如,从多个API获取数据,异步方式使用`aiohttp`并发请求,显著提高了效率。掌握异步编程对于高效处理大规模数据至关重要。
15 4
|
4天前
|
数据挖掘 开发者 Python
如何自学Python编程?
【7月更文挑战第14天】如何自学Python编程?
17 4
|
3天前
|
调度 Python
揭秘Python并发编程核心:深入理解协程与异步函数的工作原理
【7月更文挑战第15天】Python异步编程借助协程和async/await提升并发性能,减少资源消耗。协程(async def)轻量级、用户态,便于控制。事件循环,如`asyncio.get_event_loop()`,调度任务执行。异步函数内的await关键词用于协程间切换。回调和Future对象简化异步结果处理。理解这些概念能写出高效、易维护的异步代码。
12 2
|
3天前
|
Python
从零到一:构建Python异步编程思维,掌握协程与异步函数
【7月更文挑战第15天】Python异步编程提升效率,通过协程与异步函数实现并发。从async def定义异步函数,如`say_hello()`,使用`await`等待异步操作。`asyncio.run()`驱动事件循环。并发执行任务,如`asyncio.gather()`同时处理`fetch_data()`任务,降低总体耗时。入门异步编程,解锁高效代码。
15 1
|
2天前
|
算法 程序员 计算机视觉
Python并查集:数据结构界的肌肉男,让你在编程路上无所畏惧!
【7月更文挑战第16天】并查集,一种处理不相交集合合并与查询的数据结构,被誉为编程的“肌肉男”。它提供Find(找根节点)和Union(合并集合)操作,常用于好友关系判断、图像处理、集合合并等。Python实现中,路径压缩和按秩合并优化效率。并查集的高效性能使其成为解决问题的强大工具,助力程序员应对复杂挑战。
16 0
|
2天前
|
Python
智慧之光!Python并查集:点亮你的编程思维,让复杂问题迎刃而解!
【7月更文挑战第16天】并查集,一种树型数据结构,用于处理不交集合并与查询。通过路径压缩和按秩合并优化,支持Find(查找元素集合)和Union(合并集合)操作。Python实现简单示例展示如何判断社交网络中用户是否互为好友,高效解决连通性问题,点亮编程思维。
8 0
|
4天前
|
缓存 测试技术 Python
Python中的装饰器:优雅地增强函数功能
在Python编程中,装饰器是一种强大的工具,它能够在不改变函数本身的情况下,动态地增强其功能。本文将深入探讨装饰器的工作原理、常见用法以及如何利用装饰器提高代码的可重用性和可维护性。