Python函数

Python使用def关键字定义函数:

def area(width, height):
	return width * height

Python提供了返回多个值的语法,实际上是将它们作为一个元组返回:

def multi_return():
  return 1,2

>>>multi_return()
(1,2)

参数和返回值传递采用浅拷贝方式,即只拷贝对象本身,其成员指向的其它对象不进行拷贝.

对象本身被拷贝,函数无法影响实参 :

>>> def swap(a,b):
...   b,a=a,b
...
>>> a = 1
>>> b = 2
>>> swap(1,2)
>>> a
1
>>> b
2

对象引用的其它对象没有拷贝, 函数可以影响实参的元素:

>>> def fun(a):
...   a[0] = 2
...
>>> a = [1]
>>> fun(a)
>>> a
[2]

Python提供了lambda关键字定义匿名函数:

>>> lam = lambda x,y: x + y
>>> print(lam(1,2))
3

Python的函数也是对象, 因此可以方便的进行回调:

def func(callback, args):
	callback(args)

函数也是对象的特性, 为许多函数功能提供了支持.

Python允许函数嵌套定义,并采用链式作用域,内部函数可以访问外部函数的作用域.

因为Python中可以不声明直接使用对象, 在内部函数访问外部作用域时建议使用global关键字声明.

Python不检查参数的类型,建议必要时使用isinstance进行检查.

locals()方法返回保存函数当前作用域内所有变量的字典:

>>> def func():
...   a = 1
...   b = 2
...   return locals()
...
>>> func()
{'a': 1, 'b': 2}

因为采用浅拷贝的方式传递,我们可以进行一些修改:

>>> def func():
...   a = [1]
...   locals()['a'][0] = 233
...   return a
...
>>> func()
[233]

参数

Python函数除了上文提到的参数形式(称作位置参数)外, 还提供了更多参数机制:

默认参数:

>>> def volume(radius=1, height=1):
 	...	  return math.pi * (radius ** 2)* height

>>> volume(2)
12.566370614359172

在有默认参数的情况下可以指定只对特殊的默认参数赋值:

>>> volume(height=2)
6.283185307179586

可变参数用*修饰,所有可变参数作为一个元组传入:

>>> def func(*args):
...   print(args)
>>> func(1,2)
(1, 2)

关键字参数用**修饰, 所有关键字参数作为一个字典传入:

>>>def func(**kwargs):
    print(kwargs)

>>> func(key='val')
{'key': 'val'}

>>> func(**{'key':'val'})
{'key': 'val'}

默认参数可以用命名关键字的方式传入:

>>> def volume(radius=1, height=1):
...	  return math.pi * (radius ** 2)* height
 	
>>> volume(height=2)
6.283185307179586

Python3开始支持命名关键字参数,只允许给定的关键字:

>>>def func(*, kwarg):
	print(kwarg)

>>>func(kwarg='val')
'val'

命名关键字参数中*仅作为作为分隔符.

为了避免二义性,5种参数的顺序为:位置参数, 默认参数, 可变参数/命名关键字参数,关键字参数

decorator

装饰器可以方便的为函数动态添加功能:

import time

def decorator(func):
  def wrapper(arg):
  	print('logging',time.localtime())
  	return func(arg)
  return wrapper

@decorator
def func(arg):
  print(arg)

>>> func('hello')
logging time.struct_time(tm_year=2016, tm_mon=2,...
'hello'

从上述示例中>>> func(arg)实际上调用了decorator(func)(arg).

装饰器是一个函数, 无参数的装饰器decorator接受被修饰的函数func做参数,返回函数wrapper.

调用func的实参被传给wrapper, 即wrapper函数代替func被调用.

为了防止wrapper和func的环境变量不同导致调用出错, 建议使用functools.wraps装饰器保证正确:

import time
from functools import wraps

def decorator(func):
    @wraps(func)
    def wrapper(arg):
        print('logging',time.localtime())
        return func(arg)
    return wrapper

@decorator
def func(arg):
    print(arg)

func('hello')

含有参数的装饰器需要再加一层嵌套:

import time

def log(text):
	def decorator(func):
		def wrapper(arg):
			print(text)
			return func(arg)
		return wrapper
	return decorator

@log('invoke')
def func(arg):
	print(arg)

调用>>>func(arg)等价于>>>log('invoke')(func)(arg)

generator

生成器是一类特殊的函数对象, 它使用yield关键字代替return.

当调用其next()方法或使用for-in遍历generator时, 每次执行到yield语句就记录断点并返回.

下次调用next()或下次迭代时, 从断点处继续执行.

虽然generator的语法类似函数,但是:

>>> obj = fibo
>>> obj
<function fibo at 0x0000000002F19F98>
>>> obj = fibo(max)
>>> obj
<generator object fibo at 0x0000000002F32438>

send(msg)是generator另外一个重要方法,在后面协程部分有如下代码:

def consumer():
r = ''
while True:
    n1 = yield r
    if not n1:
        return
    print('Consuming %s' % n1)
    r = 'OK'

def produce(c):
    c.send(None)
    n = 0
    while n < 5:
        n = n + 1
        print('Producing %s' % n)
        r = c.send(n)
        print('Consumer return: %s' % r)
    c.close()

c = consumer()
produce(c)

第一次启动generator只能使用next()或send(None).

在consumer()第一次遇yield返回时n1没有被定义.

produce()函数调用c.send(n)把实参值赋给yield的左值n1并从下一行开始继续执行consumer.

generator的另一个应用是列表和字典生成式.

posted @ 2017-02-07 16:10  -Finley-  阅读(271)  评论(0编辑  收藏  举报