Python函数式编程术语大全!

import inspect
add = lambda a, b: a + b
len(inspect.getfullargspec(add).args)
# 2
复制代码

Higher-Order Function - 高阶函数

以函数为参数或返回值

Python学习交流群:1004391443,这里是python学习者聚集地,有大牛答疑,有资源共享!有想学习python编程的,或是转行,或是大学生,还有工作中想提升自己能力的,正在学习的小伙伴欢迎加入学习。

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 - 单子

拥有 of 和 chain 函数的对象。 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 - 余单子

拥有 extract 与 extend 函数的对象。

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]
复制代码

猜你喜欢

转载自blog.csdn.net/qq_42156420/article/details/89761799