Python函数式编程术语大全

栏目: Python · 发布时间: 5年前

内容简介:以函数为参数或返回值闭包是一种在变量作用域之外访问变量的方法。是一种将函数存储在环境中的方法。闭包是一个作用域,它捕获函数的局部变量以便访问,即使在执行已经移出定义它的块之后也是如此。
import inspect
add = lambda a, b: a + b
len(inspect.getfullargspec(add).args)
# 2
复制代码

Higher-Order Function - 高阶函数

以函数为参数或返回值

is_type = lambda type_: lambda x: isinstance(x, type_)
li = [0, '1', 2, None]
[l for l in li if is_type(int)(l)]
# [0, 2]
复制代码

Closure - 闭包

闭包是一种在变量作用域之外访问变量的方法。是一种将函数存储在环境中的方法。

闭包是一个作用域,它捕获函数的局部变量以便访问,即使在执行已经移出定义它的块之后也是如此。

add_to = lambda x: lambda y: x + y
add_to_five = add_to(5)
add_to_five(3)
# 8
复制代码

函数addTo()返回一个函数(内部称为add()),将它存储在名为addToFive的变量中,它带有参数为5的柯里化调用。

理想情况下,当函数addTo完成执行时,其作用域与局部变量add,x,y就变得不可访问。 但是,它在调用addToFive()时返回8。 这意味着即使在代码块完成执行后也会保存函数addTo的状态,否则无法知道addTo被调用为addTo(5)并且x的值被设置为5。

词法作用域范围是它能够找到x和add的值的原因 - 已经完成执行的父项的私有变量。该值称为闭包。

堆栈以及函数的词法范围以对父项的引用形式存储。这可以防止关闭和底层变量被垃圾收集(因为至少有一个对它的实时引用)。

闭包是一种通过引用其主体外部的字段来包围其周围状态的函数。封闭状态保持在闭包的调用之间。

Partial Function - 偏函数

通过对原始函数预设参数来创建一个新的函数

from functools import partial
add3 = lambda a, b, c: a + b + c
five_plus = partial(add3, 2, 3)
five_plus(4)
# 9
复制代码

Currying - 柯里化

将一个多元函数转变为一元函数的过程

add = lambda a, b: a + b
curried_add = lambda a: lambda b: a + b
curried_add(3)(4)
# 7
add2 = curried_add(2)
add2(10)
# 12
复制代码

Auto Currying - 自动柯里化

from toolz import curry
add = lambda a, b: a + b
curried_add = curry(add)
curried_add(1, 2)
# 3
curried_add(1)(2)
# 3
curried_add(1)
# <function <lambda> at 0x000002088BBD5E18>
复制代码

Function Composition - 函数组合

接收多个函数作为参数,从右到左,一个函数的输入为另一个函数的输出

import math
from functools import reduce
# 组合2个函数
compose = lambda f, g: lambda a: f(g(a))
# 组合多个函数
compose = lambda *funcs: reduce(lambda f, g: lambda *args: f(g(*args)), funcs)
floor_and_to_string = compose(str, math.floor)
floor_and_to_string(12.12)
# '12'
复制代码

Purity - 纯函数

输出仅由输入决定,且不产生副作用

greet = lambda name: f'hello, {name}'
greet('world')
'hello, world'
复制代码

以下代码不是纯函数

# 情况1:函数依赖全局变量
NAME = 'alphardex'
greet = lambda: f'hi, {NAME}'
greet()
# 'hi, alphardex'

# 情况2:函数修改了全局变量
greeting = None
def greet(name):
    global greeting
    greeting = f'hi, {name}'
greet('alphardex')
greeting
# 'hi, alphardex'
复制代码

Side effects - 副作用

如果函数与外部可变状态进行交互,则它是有副作用的

最典型的例子是创建日期和IO

from datetime import datetime
different_every_time = datetime.now()
different_every_time
# datetime.datetime(2019, 4, 20, 17, 30, 24, 824876)
different_every_time = datetime.now()
different_every_time
# datetime.datetime(2019, 4, 20, 17, 31, 41, 204302)
复制代码

Idempotent - 幂等性

如果一个函数执行多次皆返回相同的结果,则它是幂等性的

abs(abs(abs(10)))
# 10
复制代码

Point-Free Style - Point-Free 风格

定义函数时,不显式地指出函数所带参数,这种风格通常需要柯里化或者高阶函数

Point-Free风格的函数就像平常的赋值,不使用def或者lambda关键词

map_ = lambda func: lambda li: [func(l) for l in li]
add = lambda a: lambda b: a + b
increment_all = map_(add(1))

numbers = [1, 2, 3]
increment_all(numbers)
# [2, 3, 4]
复制代码

Predicate - 谓词

根据输入返回 True 或 False。常用于filter函数中

filter函数亦可以用列表推导式的if判断实现

above_two =  lambda a: a > 2
li = [1, 2, 3, 4]
[l for l in li if above_two(l)]
# [3, 4]
复制代码

Contracts - 契约

契约保证了函数或者表达式在运行时的行为。当违反契约时,将抛出一个错误。

def contract(input):
    if isinstance(input, int):
        return True
    raise Exception('Contract Violated: expected int -> int')

add_one = lambda num: contract(num) and num + 1
add_one(2)
# 3
add_one('hello')
# Exception Traceback
复制代码

Functor - 函子

一个实现了map函数的对象,map会遍历对象中的每个值并生成一个新的对象。

Python中最具代表性的函子就是list, 因为它遵守因子的两个准则

Python 中可以用列表推导式来代表map操作

Preserves identity - 一致性

li = [1, 2, 3]
[l for l in li] == li
# True
复制代码

Composable - 组合性

li = [1, 2, 3]
compose = lambda f, g: lambda a: f(g(a))
[compose(str, lambda x: x+1)(l) for l in li]
# ['2', '3', '4']
[str(l+1) for l in li]
# ['2', '3', '4']
复制代码

Referential Transparency - 引用透明性

一个表达式能够被它的值替代而不改变程序的行为成为引用透明

greet = lambda: 'hello, world.'
复制代码

Lazy evaluation - 惰性求值

按需求值机制,只有当需要计算所得值时才会计算

Python中可用生成器实现

import random
def rand():
    while True:
        yield random.random()
rand_iter = rand()
next(rand())
# 0.16066473752585098
复制代码

Monoid - 单位半群

一个对象拥有一个函数用来连接相同类型的对象

数值加法是一个简单的Monoid

1 + 1
# 2
复制代码

以上例子中,数值是对象,而+是函数

以下能更清晰地说明它

from operator import add
type(1)
# <class 'int'>
add(1, 1)
# 2
复制代码

数值是int类的实例对象,add是实现了加法的函数

与另一个值结合而不会改变它的值必须存在,称为 identity

加法的identity值为 0:

1 + 0
# 1
复制代码

需要满足结合律

1 + (2 + 3) == (1 + 2) + 3
# True
复制代码

list的结合也是Monoid

[1, 2].extend([3, 4])
复制代码

identity值为空数组

[1, 2].extend([])
复制代码

identity与compose函数能够组成monoid

identity = lambda a: a
compose = lambda f, g: lambda a: f(g(a))
foo = lambda bar: bar + 1
compose(foo, identity)(1) == compose(identity, foo)(1) == foo(1)
# True
复制代码

Monad - 单子

拥有 ofchain 函数的对象。 chain 很像 map ,除了用来铺平嵌套数据。

flatten = lambda li: sum(li, [])
of = lambda *args: list(args)
chain = lambda func: lambda li: list(flatten([func(l) for l in li]))

[s.split(',') for s in of('cat,dog', 'fish,bird')]
# [['cat', 'dog'], ['fish', 'bird']]

chain(lambda s: s.split(','))(of('cat,dog', 'fish,bird'))
# ['cat', 'dog', 'fish', 'bird']
复制代码

Comonad - 余单子

拥有 extractextend 函数的对象。

class CoIdentity:
    def __init__(self, v):
        self.val = v
    def extract(self):
        return self.val
    def extend(self, func):
        return CoIdentity(func(self))

CoIdentity(1).extract()
1
from beeprint import pp
pp(CoIdentity(1).extend(lambda x: x.extract() + 1))
# instance(CoIdentity):
#   val: 2
复制代码

Morphism - 态射

一个变形的函数

Endomorphism - 自同态

输入输出是相同类型的函数

uppercase = lambda string: string.upper()
uppercase('hello')
# 'HELLO'

decrement = lambda number: number - 1
decrement(2)
# 1
复制代码

Isomorphism - 同构

不同类型对象的变形,保持结构并且不丢失数据。

例如,一个二维坐标既可以表示为列表 [2, 3] ,也可以表示为字典 {'x': 2, 'y': 3}

pair_to_coords = lambda pair: {'x': pair[0], 'y': pair[1]}
coords_to_pair = lambda coords: [coords['x'], coords['y']]
pair_to_coords(coords_to_pair({'x': 1, 'y': 2}))
#{'x': 1, 'y': 2}
复制代码

Setoid

拥有 equals 函数的对象。 equals 可以用来和其它对象比较。

Python里的 == 就是 equals 函数

[1, 2] == [1, 2]
# True

[1, 2] == [3, 4]
# False
复制代码

Semigroup - 半群

拥有 concat 函数的对象。 concat 可以连接相同类型的两个对象。

Python里列表的 extend 就是 concat 函数

li = [1]
li.extend([2])
li
# [1, 2]
复制代码

Foldable

一个拥有 reduce 函数的对象。 reduce 可以把一种类型的对象转化为另一种类型。

from functools import reduce
sum_ = lambda li: reduce(lambda acc, val: acc + val, li, 0)
sum_([1, 2, 3])
6
复制代码

Type Signatures - 类型签名

通常可以在注释中指出参数与返回值的类型

# add :: int -> int -> int
add = lambda x: lambda y: x + y

# increment :: int -> int
increment = lambda x: x + 1
复制代码

如果函数的参数也是函数,那么这个函数需要用括号括起来

# call :: (a -> b) -> a -> b
call = lambda func: lambda x: func(x)
复制代码

字符a, b, c, d表明参数可以是任意类型。以下版本的 map 的参数func,把一种类型a的数组转化为另一种类型b的数组

# map :: (a -> b) -> [a] -> [b]
map_ = lambda func: lambda li: [func(l) for l in li]
复制代码

常用库


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

增长黑客实战

增长黑客实战

范冰、张溪梦 / 电子工业出版社 / 2017-6 / 59.00

《增长黑客实战》围绕硅谷前沿的增长黑客职业,讲解增长理念的树立、增长团队的组建、流程制度的创立、技术营销的运用等团队运营成功实战经验。作者以自身创业经验为蓝本,结合真实案例,并融入一些伟大创业者的智慧,创建了一套思考、验证和追求卓越增长的理论体系。那些想要验证自己的创意、解决实际增长问题和拥有成功事业的人,可以将《增长黑客实战》当成一套清晰的实践指南、一幅组建增长团队的指导蓝图,或者一套值得反复玩......一起来看看 《增长黑客实战》 这本书的介绍吧!

URL 编码/解码
URL 编码/解码

URL 编码/解码

MD5 加密
MD5 加密

MD5 加密工具