repo: github.com/alphardex/p…html
參考repo:github.com/hemanth/fun…python
import inspect
add = lambda a, b: a + b
len(inspect.getfullargspec(add).args)
# 2
複製代碼
以函數爲參數或返回值git
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]
複製代碼
閉包是一種在變量做用域以外訪問變量的方法。是一種將函數存儲在環境中的方法。github
閉包是一個做用域,它捕獲函數的局部變量以便訪問,即便在執行已經移出定義它的塊以後也是如此。數組
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。dom
詞法做用域範圍是它可以找到x和add的值的緣由 - 已經完成執行的父項的私有變量。該值稱爲閉包。ide
堆棧以及函數的詞法範圍以對父項的引用形式存儲。這能夠防止關閉和底層變量被垃圾收集(由於至少有一個對它的實時引用)。函數
閉包是一種經過引用其主體外部的字段來包圍其周圍狀態的函數。封閉狀態保持在閉包的調用之間。lua
經過對原始函數預設參數來建立一個新的函數
from functools import partial
add3 = lambda a, b, c: a + b + c
five_plus = partial(add3, 2, 3)
five_plus(4)
# 9
複製代碼
將一個多元函數轉變爲一元函數的過程
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
複製代碼
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>
複製代碼
接收多個函數做爲參數,從右到左,一個函數的輸入爲另外一個函數的輸出
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'
複製代碼
輸出僅由輸入決定,且不產生反作用
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'
複製代碼
若是函數與外部可變狀態進行交互,則它是有反作用的
最典型的例子是建立日期和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)
複製代碼
若是一個函數執行屢次皆返回相同的結果,則它是冪等性的
abs(abs(abs(10)))
# 10
複製代碼
定義函數時,不顯式地指出函數所帶參數,這種風格一般須要柯里化或者高階函數
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]
複製代碼
根據輸入返回 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]
複製代碼
契約保證了函數或者表達式在運行時的行爲。當違反契約時,將拋出一個錯誤。
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
複製代碼
一個實現了map函數的對象,map會遍歷對象中的每一個值並生成一個新的對象。
Python中最具表明性的函子就是list, 由於它遵照因子的兩個準則
在Python中能夠用列表推導式來表明map操做
li = [1, 2, 3]
[l for l in li] == li
# True
複製代碼
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']
複製代碼
一個表達式可以被它的值替代而不改變程序的行爲成爲引用透明
greet = lambda: 'hello, world.'
複製代碼
按需求值機制,只有當須要計算所得值時纔會計算
Python中可用生成器實現
import random
def rand():
while True:
yield random.random()
rand_iter = rand()
next(rand())
# 0.16066473752585098
複製代碼
一個對象擁有一個函數用來鏈接相同類型的對象
數值加法是一個簡單的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
複製代碼
擁有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']
複製代碼
擁有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
複製代碼
一個變形的函數
輸入輸出是相同類型的函數
uppercase = lambda string: string.upper()
uppercase('hello')
# 'HELLO'
decrement = lambda number: number - 1
decrement(2)
# 1
複製代碼
不一樣類型對象的變形,保持結構而且不丟失數據。
例如,一個二維座標既能夠表示爲列表[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}
複製代碼
擁有equals
函數的對象。equals
能夠用來和其它對象比較。
Python裏的==
就是equals
函數
[1, 2] == [1, 2]
# True
[1, 2] == [3, 4]
# False
複製代碼
擁有concat
函數的對象。concat
能夠鏈接相同類型的兩個對象。
Python裏列表的extend
就是concat
函數
li = [1]
li.extend([2])
li
# [1, 2]
複製代碼
一個擁有reduce
函數的對象。reduce
能夠把一種類型的對象轉化爲另外一種類型。
from functools import reduce
sum_ = lambda li: reduce(lambda acc, val: acc + val, li, 0)
sum_([1, 2, 3])
6
複製代碼
一般能夠在註釋中指出參數與返回值的類型
# 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]
複製代碼