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的另一个应用是列表和字典生成式.