概览
函数在python里是作为第一类对象(First Class Objects)。在编程语言理论里,定义一个“第一类对象”作为编程对象能够做到以下几点:
- 在运行时创建
- 可以赋值给变量或者数据结构里的元素
- 能作为参数传递给函数
- 可以作为函数的返回值
Treating a Function Like an Object
在python里函数就是对象,类型是function。
>>> def factorial(n):
... '''returns n!'''
... return 1 if n < 2 else n * factorial(n-1)
...
>>> factorial(10)
3628800
>>> factorial.__doc__
'returns n!'
>>> type(factorial)
<class 'function'>
>>> fact = factorial
>>> fact
<function factorial at 0x1053fcf28>
>>> fact(5)
120
>>> map(factorial, range(4))
<map object at 0x10566b160>
>>> list(map(fact, range(4)))
[1, 1, 2, 6]
上面的例子展示了函数作为第一类对象的特性。可以把函数赋值给一个对象,并且使用这个对象的名字调用函数。也可以把函数作为参数传递给另一个函数。
Higher-Order Functions
一个函数把函数作为参数或者把函数作为返回结果就被称为高阶函数(high-order function)。
函数式编程通常提供一些通用的高阶函数如map
,reduce
,filter
等。不过在python里由于list comprehensions还有generator expressions的引入,都不太重要了。在python3里map
和filter
返回生成器,而在python2里返回list。在python3里reduce
被从built-in里移除,放在了functools模块里。
Anonymous Functions
在使用高阶函数时,有时候创建一个小的,一次性的函数会很方便,这个就是匿名函数的由来。
匿名函数是由lambda
关键字创建。不过由于匿名函数句法的局限,匿名函数的函数体只能是纯表达式。除了作为高阶函数的参数以为,匿名函数的使用场景非常有限。
The Seven Flavors of Callable Objects
call
操作符(就是())除了用户自定义函数以外,也可以用在其他对象上。要确定一个函数是否是callable的,可以使用内建的callable() 函数。python定义了七种callable类型:
- User-defined functions:使用def语句或者用lambda表达式创建。
- Built-in functions:使用C实现的函数,如len。
- Built-in methods:使用C实现的方法,如dict.get。
- Methods:定义在类里的函数。
- Classes:调用类就是创建一个实例。
- Class instances:类如果定义了
__call__
方法,那么类的实例也可以像函数一样调用。 - Generator functions:使用
yield
关键字的函数或方法。
User-Defined Callable Types
这一节介绍的就是7种callabe类型里的第6种。主要使用的场景就是创建在调用时需要保存内部状态的像函数一样的对象,另一种方式就是闭包(Closures),后面会详细讲。
From Positional to Keyword-Only Parameters
python函数最棒的特性就是极度灵活的参数处理方式,在python进一步增强提供了仅限关键字参数(keyword-only)。与之相关的就是当调用一个函数时,使用和*去展开iterables和mappings到不同的参数。
>>>def tag(name, *content, cls=None, **attrs):
"""Generate one or more HTML tags"""
if cls is not None:
attrs['class'] = cls
if attrs:
attr_str = ''.join(' %s="%s"' % (attr, value)
for attr, value
in sorted(attrs.items()))
else:
attr_str = ''
if content:
return '\n'.join('<%s%s>%s</%s>' %
(name, attr_str, c, name) for c in content)
else:
return '<%s%s />' % (name, attr_str)
>>> tag('br')
'<br />'
>>> tag('p', 'hello')
'<p>hello</p>'
>>> print(tag('p', 'hello', 'world'))
<p>hello</p>
<p>world</p>
>>> tag('p', 'hello', id=33)
'<p id="33">hello</p>'
>>> print(tag('p', 'hello', 'world', cls='sidebar'))
<p class="sidebar">hello</p>
<p class="sidebar">world</p>
>>> tag(content='testing', name="img")
'<img content="testing" />'
>>> my_tag = {'name': 'img', 'title': 'Sunset Boulevard',
... 'src': 'sunset.jpg', 'cls': 'framed'}
>>> tag(**my_tag)
'<img class="framed" src="sunset.jpg" title="Sunset Boulevard" />'
仅限关键字参数(keyword-only)是python3里的新特性。参数只能作为关键字参数,而不能从未命名的位置参数捕获。要定义一个仅限关键字参数,就把他放在前缀的参数后面。如果不需要变化的参数,但是还需要仅限关键字参数,那么就直接放在的后面。
Retrieving Information About Parameters
函数对象有几个内省的属性存储了参数信息:
-
__defaults__
:存储了参数的默认值 -
__kwdefaults__
:存储了keyword-only参数的默认值 -
__code__
:__code__.co_varnames
存储了参数名和局部变量的名字,通过__code__.co_argcount
定位前N个作为参数。
更简单的是使用inspect.signature
来获取参数信息。
Function Annotations
python3提供了语法给函数的参数和返回值附加一些元数据。如类型还有限制条件,不过现在python只是做了些记录,并没有去做检查。
Packages for Functional Programming
operator包里包含了很多算术操作符,另外几个比较有用的函数itemgetter
,attrgetter
,methodcaller
。
functools包里主要介绍了partial,可以用来生成一个新的callable其中的一些参数值固定。
>>> a = range(10)
>>> from operator import itemgetter
>>> a_itemgetter = itemgetter(5, 1)
>>> a_itemgetter(a)
(5, 1)
>>> from collections import namedtuple
>>> LatLong = namedtuple('LatLong', 'lat long')
>>> latlon = LatLong(30, 140)
>>> from operator import attrgetter
>>> attr_lat = attrgetter('lat')
>>> attr_lat(latlon)
30
>>> from operator import methodcaller
>>> s = 'The time has come'
>>> upcase = methodcaller('upper')
>>> upcase(s)
'THE TIME HAS COME'
>>> from operator import mul
>>> from functools import partial
>>> triple = partial(mul, 3)
>>> triple(7)
21
网友评论