《Fluent Python》读书笔记-First-Class Functions

概览

    函数在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)

>>> fact = factorial
>>> fact

>>> fact(5)
120
>>> map(factorial, range(4))

>>> list(map(fact, range(4)))
[1, 1, 2, 6]

    上面的例子展示了函数作为第一类对象的特性。可以把函数赋值给一个对象,并且使用这个对象的名字调用函数。也可以把函数作为参数传递给另一个函数。

Higher-Order Functions

    一个函数把函数作为参数或者把函数作为返回结果就被称为高阶函数(high-order function)
    函数式编程通常提供一些通用的高阶函数如mapreducefilter等。不过在python里由于list comprehensions还有generator expressions的引入,都不太重要了。在python3里mapfilter返回生成器,而在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' %
                   (name, attr_str, c, name) for c in content) 
    else:
        return '<%s%s />' % (name, attr_str)
>>> tag('br')
'
' >>> tag('p', 'hello') '

hello

' >>> print(tag('p', 'hello', 'world'))

hello

world

>>> tag('p', 'hello', id=33) '

hello

' >>> print(tag('p', 'hello', 'world', cls='sidebar')) >>> tag(content='testing', name="img") '' >>> my_tag = {'name': 'img', 'title': 'Sunset Boulevard', ... 'src': 'sunset.jpg', 'cls': 'framed'} >>> tag(**my_tag) ''

    仅限关键字参数(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包里包含了很多算术操作符,另外几个比较有用的函数itemgetterattrgettermethodcaller
    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

你可能感兴趣的:(《Fluent Python》读书笔记-First-Class Functions)