流程的python第五章

第三部分 把函数视作对象

第5章 一等函数

在Python中,函数是一等对象
一等对象特点:

在运行时创建

能赋值给变量或数据结构中的元素

能作为参数传给函数

能作为函数的返回结果

5.1 把函数视作对象

5.1
def factorial(n):
    """n!"""
    return 1 if n<2 else n*factorial(n-1)

print(42)


print(factorial.__doc__)
#__doc__是函数对象众多属性中的一个


print(type(factorial))
#factorial是function类的实例

print(help(factorial))

展示函数对象的一等本性:

展示函数对象的一等本性:5.2 
#函数对象的一等本性
'''
通过别名使用函数,将函数当参数传递
'''

fact=factorial
#函数传给一个变量
fact(5)
map(fact,range(11))
#函数作为参数传递给令一个函数

下面介绍函数式编程:

函数式编程的特点之一是使用高阶函数

5.2 高阶函数

受函数为参数,或者把函数作为结果返回的函数是高阶函数

eg:
map函数
sorted()函数的key参数用于接收一个函数参数

5.3
fruits=["strawberry","fig","apple","cherry","raspberry","banana"]

new_fruits=sorted(fruits,key=len)
#任何单参数函数都可以作为key的参数

print(new_fruits)

5.4创建押韵排序

#逆序单词
def reverse(word):
    return word[::-1]

#按照逆序的单词排序
new_reverse_fruits=sorted(fruits,key=reverse)

print(new_reverse_fruits)

在函数式编程范式中,最为人熟知的高阶函数有map、filter、reduce
map、filter和reduce的现代替代品
Python 3中,map和filter返回生成器(一种迭代器),因此现在它们的

直接替代品是生成器表达式
(在python2最中的替代是列表推导式)

5.5计算阶乘列表:mapfilter与列表推导比较
list(map(fact,range(6)))

print([fact(n) for n in range(6)])


list(map(fact,filter(lambda n:n%2,range(6))))

[fact(n) for n in range(6) if n%2]

reduce()

把某个操作连续应用到序列的元素上,
累计之前的结果,把一系列值归约成一个值

5.6
from functools import reduce
from operator import add

reduce(add,range(100))
sum(range(100))

all和any也是内置的归约函数。

all(iterable)

如果iterable的每个元素都是真值,返回True;all([])返回True。

any(iterable)
如果iterable的任何一个元素是真值返回True

a=[1,0,1,1,1,0]
print(all(a))
print(any(a))

为了使用高阶函数,有时创建一次性的小型函数更便利。这便是匿名函数存在的原因
5.3 匿名函数

#lambda

lambda函数的定义体只能使用纯表达式

即lambda函数中不能赋值,也不能使用while、try等python语句

在参数列表中最适合使用匿名函数

5.3
fruits=["strawberry","fig","apple","cherry","raspberry","banana"]

new_reverse_fruits=sorted(fruits,key=lambda word:word[::-1])

print(new_reverse_fruits)

5.4 可调用对象

可以使用()调用运算符的对象称为可调用对象:

用户定义的函数
内置函数
内置方法
方法

类的实例
如果类定义了__call__方法,那么它的实例可以作为函数调用。参见5.5节。
生成器函数

判断对象能否调用,可以使用内置的callable( )函数:

[callable(obj) for obj in (abs,str,13)]

5.5 用户定义的可调用类型

任何Python对象都可以表现得像函数

只需实现实例方法__call__


import random

class BingoCage:
    def __init__(self,items):
        self._items=list(items)
        random.shuffle(self._items)

    def pick(self):
        try:
            return self._items.pop()
        except IdexError:
            raise LookupError("pick from empty BingoCage")

    def __call__(self):
        return self.pick()
    #通过重写__call__方法,类对象成为可调用对象,和函数具有相同功能

bingo=BingoCage(range(3))
a=bingo()
print(a)
print(callable(bingo))

注意,使用__call__是穿件类函数对象的快速方法,
此时必须在内部维护一个状态,在多次调用时记住一些数据。
比如这里的self._items

穿件保有内部状态的函数还有一种方式:闭包

5.6 函数内省

用dir函数可以探知factorial具有下述属性:

dir(fact)
['__annotations__', '__call__', '__class__', '__closure__', '__code__', '__defaults__', 
'__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__get__', 
'__getattribute__', '__globals__', '__gt__', '__hash__', '__init__', '__init_subclass__', 
'__kwdefaults__', '__le__', '__lt__', '__module__', '__name__', 
'__ne__', '__new__', '__qualname__', '__reduce__', '__reduce_ex__', 
'__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__']
示例5-9 列出常规对象没有而函数有的属性



class C:pass
obj=C()
def fuc():pass

print(sorted(set(dir(fuc))-set(dir(obj))))


['__annotations__', '__call__', '__closure__', 
#参数和返回值的注解,实现()运算符,函数闭包,自由变量的绑定
'__code__', '__defaults__', '__get__', 
             #形式参数的默认值   #实现只读描述协议
'__globals__', '__kwdefaults__', 
#函数所在模块中的全局变量 , 关键字形式的形参默认值
'__name__', '__qualname__']
#函数名字,函数的限定名字


5.7 从定位参数到仅限关键字参数

tag函数:

def tag(name,*content,cls=None,**attrs):
    """生成一个或多个HTML标签"""
    #name定位参数,传入第一个位置的非关键字形参
    #*content,截取其余非关键字形参
    #cls,获取特定关键字传参。
    #**attrs获取其余关键字传参
    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)


print(tag("br"))
print("p","hello")





仅限关键字参数:


def f(a,*c,b):
    return a,c,b
    #*c会获得所有除了第一个位置的位置参数,
    #所以b只能通过关键字传参
print(f(1,2,3,4,5,b=6))



如果不想定义数量不定的定位传参

就写如下:

def f(a,*,b):
    return a,b
print(f(1,b=6))


5.8 获取关于参数的信息

函数对象有个__defaults__属性,它的值是一个元组,里面保存着定位参数和关键字参数的默认值。仅限关键字参数的默认值在__kwdefaults__属性中。然而,参数的名称在__code__属性中,它的值是一个code对象引用,自身也有很多属性。

幸好,我们有更好的方式——使用inspect模块。

示例5-17 提取函数的签名[插图]

就好多了。inspect.signature函数返回一个inspect.Signature对象,它有一个parameters属性,这是一个有序映射,把参数名和inspect.Parameter对象对应起来。各个Parameter属性也有自己的属性,例如name、default和kind。特殊的inspect._empty值表示没有默认值,考虑到None是有效的默认值(也经常这么做),而且这么做是合理的。

inspect.Signature对象有个bind方法,它可以把任意个参数绑定到签名中的形参上,所用的规则与实参到形参的匹配方式一样。框架可以使用这个方法在真正调用函数前验证参数,如示例5-18所示。

这个示例在inspect模块的帮助下,展示了Python数据模型把实参绑定给函数调用中的形参的机制,这与解释器使用的机制相同。框架和IDE等工具可以使用这些信息验证代码。Python 3的另一个特性——函数注解——增进了这些信息的用途,

5.9 函数注解

示例5-19 有注解的clip函数

函数声明中的各个参数可以在:之后增加注解表达式。如果参数有默认值,注解放在参数名和=号之间。如果想注解返回值,在)和函数声明末尾的:之间添加->和一个表达式。

注解不会做任何处理,只是存储在函数的__annotations__属性(一个字典)中

说,注解对Python解释器没有任何意义。注解只是元数据,可以供IDE、框架和装饰器等工具使用。

5.10 支持函数式编程的包

operator和functools

5.10.1 operator模块

示例5-21 使用reduce函数和一个匿名函数计算阶乘

itemgetter和attrgetter其实会自行构建函数。

根据元组的某个字段给元组列表排序

itemgetter使用[]运算符,因此它不仅支持序列,还支持映射和任何实现__getitem__方法的类。

5.10.2 使用functools.partial冻结参数

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值