资讯专栏INFORMATION COLUMN

Python一等函数简析

邹立鹏 / 3504人阅读

摘要:本文重点了解函数在中是一等对象了解中的可调用对象掌握正确定义函数参数的方法了解和中支持函数式编程的方法。归约函数定义能够接受一个可迭代对象并返回单个结果的函数是归约函数。

本文章记录了本人在学习Python基础之函数篇的重点知识及个人心得,欢迎打算入门Python的朋友与我一起学习交流。。

本文重点:

1、了解函数在Python中是一等对象;
2、了解Python中的可调用对象;
3、掌握正确定义函数参数的方法;
4、了解operator和functools中支持函数式编程的方法。
一、函数是一等对象 1、一等对象

定义:一等对象是满足如下条件的程序实体:

在运行时创建;

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

能作为参数传给函数;

能作为函数的返回结果。

在Python中,所有函数都是一等对象。

2、高阶函数

定义:接受函数为参数,或者把函数作为结果返回的函数是高阶函数。
在Python中传统的高阶函数有map,filter,reduce;常用的高阶函数有内置函数sorted、min、max和functools.partial。

map(function, iterable, ...):
map返回一个迭代器,迭代器是通过function处理可迭代对象中的每个元素产生的返回值的集合。

filter(function, iterable):
filter相当于一个过滤器,以函数返回值为判定条件,筛选出True的元素并放入迭代器中返回。

functools.reduce(function, iterable[, initializer])
reduce对可迭代对象中从左开始元素选出两个进行函数运算,将返回的运算值作为一个参数继续与第三个元素进行函数运算,直至迭代完成返回运算值。

3、归约函数:

定义:能够接受一个可迭代对象并返回单个结果的函数是归约函数。
reduce就是归约函数的一种,sum也是一种归约函数。本章额外介绍两个内置的归约函数。

all(iterable):
可迭代对象中每一个元素都是真值则返回True,否则False。
any(iterable)
可迭代对象中存在一个元素是真值则返回True,否则False。
归约函数会在第14章中讨论可迭代对象时重点讲解。

4、匿名函数:

匿名函数:使用lambda表达式创建的函数,函数本身没有名字来辨识,因而叫做匿名函数。
句法特点:lambda函数只能使用纯表达式,不能赋值,也不能使用while和try等语句。
语法:lambda [arg1 [,arg2,.....argn]]:expression。
优点:创建方便,简化代码工作量。
缺点:代码可读性降低。

5、函数内省

在计算机编程中,自省是指这种能力:检查某些事物以确定它是什么、它知道什么以及它能做什么。自省向程序员提供了极大的灵活性和控制力。

二、函数参数与注解 1、函数参数

在函数的定义过程可能需要传入参数,对于函数涉及到的参数分为以下四种:

必填参数
调用函数必须填写的参数。在参数中居于靠前位置。

默认参数
当必填参数设置默认值时可选填。注意默认值是不可变对象,否则有逻辑错误。

可变参数
用单星号*args表示,即传入的参数是不定的。*args把参数收到元组中接受。
传入方式既可以是直接传入,如func(1, 2, 3);也可以用列表或元组传入,如func(*(1,2,3))。

强制关键字参数
此类参数只能捕获通过指定关键字传入的参数,无法按照位置顺序读参。定义时前面需放一个*。

关键字参数
此参数可填可不填。传入方式分两种,一是”传递参数名=传递参数值”形式的参数,这种方式传入对位置无要求;二是不写参数名,按照位置顺序传入参数值。
当关键字参数不定时用双星号**kw表示。**kw把关键字参数收到字典中接受。关键字参数既可以直接传入:func(a=1, b=2),又可以先组装dict,再通过**kw传入:func(**{"a": 1, "b": 2})。

参数组合:当函数涉及到使用多种参数时,定义和传入的参数需按照的顺序:
必填参数、默认参数、可变参数、强制关键字参数、关键字参数.

def func(name,country="China",*,age,**rest):
    print("name :",name," country :",country," age :",age," rest :",rest)
func("Jack","US",age=20)
func("Hoya",age=15,male="Boy",height="178",grade="excellent",country="UK")

#output:
name : Jack  country : US  age : 20  rest : {}
name : Hoya  country : UK  age : 15  rest : {"male": "Boy", "height": "178", "grade": "excellent"}
#强制关键字参数错误传参
 func("Hoya",country="UK",20)

SyntaxError: positional argument follows keyword argument
#强制关键字参数只能利用关键字传入参数

注:函数参数知识引自
作者:东皇Amrzs

2、获取参数:inspect模块

可以通过A=inspect.signature(object)提取关于函数参数的信息;
signature支持signature.parameter方法返回关于参数的有序映射。
signature支持signature.bind(args, *kwargs)方法,此方法可将多个实参绑定到签名的形参来接受。

3、函数注解:

注解(annotation)从Python3开始存在,用于为函数声明中的参数和返回值附加元数据。只有inspect.signature()可以提取注解。
本人目前把注解简单理解为一种标签。

三、可调用对象

定义:支持调用运算符()的对象叫做可调用对象。
判断方法:利用内置的callable()函数判断。

Python数据模型包含7种可调用对象:

用户定义的函数
使用def语句或lambda表达式创建。

内置函数
使用CPython实现的函数,如len。

内置方法
使用CPython实现的方法,如list.pop。

方法
在类的定义体中定义的函数。

类的实例
如果类定义了__call__方法,这个类的实例可以作为函数调用。

生成器函数
使用yield关键字的函数或方法。调用生成器函数返回的对象是生成器。

下面针对类的实例为示范进行调用操作:

class Text:
    def __init__(self,text):
        self.text=str(text)
    def number_search(self):
        import re
        num_search=re.compile(r"d+")
        return print("number search :",num_search.findall(self.text))
    def __call__(self, *args, **kwargs):
        return self.number_search()
a=Text("asdljlj55fsa56af6af66f598as5asf6af59nf3asf830fa3s")
a.number_search()

#输出:
number search : ["55", "56", "6", "66", "598", "5", "6", "59", "3", "830", "3"]

从中可以看出,创建函数类对象的简便方式是实现__call__方法。

四、支持函数式编程的包 1. 函数式编程:

相比较命令式编程,函数式编程是通过函数来保存程序的状态的。或者更准确一点,它是通过函数创建新的参数或返回值来保存程序的状态的。

认识函数式编程应掌握的两个本质:

高阶函数(higher-order functions)
函数式编程是通过高阶函数(higher-order functions)的特性来使其具有更丰富多变的表达能力。如map,filter。
高阶函数和一等函数让基于函数演变的函数式语言表达能力大增,使其能够用函数构建起更高层更抽象的模块来解决复杂的问题。

没有副作用(no side effect)
函数所有功能就是返回一个新的值,没有其他行为,尤其是不得修改外部变量的值。
使得函数式编程各个独立的部分的执行顺序可以随意打乱。 而这在命令式编程风格的代码中是不可能的。
执行顺序的自由使其得以衍生出一大堆非常有用的特性,比如无锁(lock-free)的并发操作、惰性求值(lazy evaluation),还有在编译器级别上的各种性能优化技术。 特别在并行技术上,Clojure, Haskell, F#, Scala, Erlang这些函数式语言都无一例外地支持强大的并发功能。
当然函数式语言不可能真的就不执行I/O,但它通过一些手段来把I/O的影响限制到最小,比如通过Continuations, Monad等技术。

注:函数式编程知识引自
作者:Jan Fan

Python的目标不是变成函数式编程语言,但通过operator和functools等包也可以进行函数式编程,下面开始介绍这两个模块。

2. operator

本节介绍operator中的mul、itemgetter、attrgetter、methodcaller四种方法。

operator.mul(a,b)
返回数字a和b的乘积。

import operator
from _functools import reduce
#计算阶乘
def fact1():
    list1=filter(lambda x: x%2,range(8))
    return reduce(operator.mul,list1)
print(fact1())#输出:105

operator.itemgetter(item or *items)
创建一个接受集合的函数,返回指定索引对应的元素。如果指定索引至少为2个,以元组形式返回查询结果。
After f = itemgetter(2), the call f(r) returns r[2].
After g = itemgetter(2, 5, 3), the call g(r) returns (r[2], r[5], r[3]).

metro_data =[("Tokyo", "JP", 36.933, (35.689722, 139.691667)),
("Delhi NCR", "IN", 21.935, (28.613889, 77.208889)),
("Mexico City", "MX", 20.142, (19.433333, -99.133333)),
("New York-Newark", "US", 20.104, (40.808611, -74.020386)),
("Sao Paulo", "BR", 19.649, (-23.547778, -46.635833))]
a=itemgetter(1,0)
for i in metro_data:
    print(a(i))#注意分清楚a和i谁是参数,被处理的可迭代对象是参数。

#输出:
("JP", "Tokyo")
("IN", "Delhi NCR")
("MX", "Mexico City")
("US", "New York-Newark")
("BR", "Sao Paulo")

operator.attrgetter(attr or *attrs)
创建一个函数,根据名称访问对象的属性,以元组的形式返回。
After f = attrgetter("name"), the call f(b) returns b.name.
After f = attrgetter("name", "date"), the call f(b) returns (b.name, b.date).
After f = attrgetter("name.first", "name.last"), the call f(b) returns (b.name.first, b.name.last).

eg:按照城市经度顺序输出城市名和城市经度

from collections import namedtuple
from _operator import attrgetter

latlong=namedtuple("latlong","lat long")
citydata=namedtuple("citydata", "city ID pop coord")
city=[citydata(city,ID,pop,latlong(lat,long)) for city, ID,pop,(lat,long) in metro_data]
#拆包+列表推导。拆包注意city,ID,pop,latlong(lat,long)和citydata具名元组的结构对应关系,至于拆包用的变量名字是什么并不重要,保证可读性即可。
b=attrgetter("city","coord.lat")

#方法1
for i in sorted(city,key=attrgetter("coord.lat")):
    print(b(i))

#方法2
for i in sorted(city,key=lambda x: x[3][0]):
    print(b(i))

#输出
("Sao Paulo", -23.547778)
("Mexico City", 19.433333)
("Delhi NCR", 28.613889)
("Tokyo", 35.689722)
("New York-Newark", 40.808611)

operator.methodcaller(name[, args...])
自行创建函数,使用对象中支持的方法。args代表函数所需传入的参数。
After f = methodcaller("name"), the call f(b) returns b.name().
After f = methodcaller("name", "foo", bar=1), the call f(b) returns b.name("foo", bar=1).

from operator import methodcaller
c=methodcaller("upper")
d=methodcaller("islower")
print(c("apple"),d("apple"))
#输出
APPLE True.
3. functools.partial

语法:functools.partial(func, *args, **keywords)
functools.partial适用于函数冻结参数的情况。冻结参数是指我们欲调用的函数中的部分或全部参数已经固定,只需补齐剩下的参数调用即可。可以按照word编辑中的格式刷来理解。

from functools import partial
from unicodedata import normalize
clean=partial(normalize,"NFC")#字符串格式化,我觉得很像格式刷啊。
e="café"
f="cafeu0301"
print(e==f) #False
print(clean(e)==clean(f))#True

使用技巧总结:operator中的itemgetter、attrgetter和functools.partial在使用上都需要先构建类似正则表达式的compile partern,即构建对应的itemgetter,attrgetter和partial,然后在partern基础上传入待处理对象。以刚才的partial举例就是clean(e),而不是e(clean)。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/41255.html

相关文章

  • Python一等函数简析

    摘要:本文重点了解函数在中是一等对象了解中的可调用对象掌握正确定义函数参数的方法了解和中支持函数式编程的方法。归约函数定义能够接受一个可迭代对象并返回单个结果的函数是归约函数。 导语:本文章记录了本人在学习Python基础之函数篇的重点知识及个人心得,打算入门Python的朋友们可以来一起学习并交流。 本文重点: 1、了解函数在Python中是一等对象;2、了解Python中的可调用对象;3...

    shusen 评论0 收藏0
  • 简析前端学习python3的基础

    摘要:元组是静态数组,它们不可变,且其内部数据一旦创建便无法改变。元组缓存于运行时环境,这意味着我们每次使用元组时无须访问内核去分配内存。 以下是整理的JavaScript和python的基础区别的整理: 字符串、列表、元组、字典、集合、函数 字符串 声明一个字符串 python str = 123 str = 123 Tips: 如果是三个引号的话,那么在py中就是注释的意思 ...

    summerpxy 评论0 收藏0
  • 简析前端学习python3的基础

    摘要:元组是静态数组,它们不可变,且其内部数据一旦创建便无法改变。元组缓存于运行时环境,这意味着我们每次使用元组时无须访问内核去分配内存。 以下是整理的JavaScript和python的基础区别的整理: 字符串、列表、元组、字典、集合、函数 字符串 声明一个字符串 python str = 123 str = 123 Tips: 如果是三个引号的话,那么在py中就是注释的意思 ...

    LiveVideoStack 评论0 收藏0
  • python学习笔记 函数

    摘要:一等函数在中,函数是一等对象。匿名函数关键字在表达式内创建匿名函数然而,简单的句法限制了函数的定义体只能使用纯表达式,即函数的定义体中不能赋值,不能使用等语句。匿名函数适合用于作为函数的参数 一等函数 在python中,函数是一等对象。编程语言理论家把一等对象定义为满足以下条件的程序实体: 在运行时创建 能赋值给变量或数据结构中的元素 能作为参数传给函数 能作为函数的返回结果 在p...

    Scorpion 评论0 收藏0
  • Python学习之路24-一等函数

    摘要:函数内省的内容到此结束。函数式编程并不是一个函数式编程语言,但通过和等包的支持,也可以写出函数式风格的代码。 《流畅的Python》笔记。本篇主要讲述Python中函数的进阶内容。包括函数和对象的关系,函数内省,Python中的函数式编程。 1. 前言 本片首先介绍函数和对象的关系;随后介绍函数和可调用对象的关系,以及函数内省。函数内省这部分会涉及很多与IDE和框架相关的东西,如果平时...

    wind3110991 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<