国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

Python高階函數(shù)

這篇具有很好參考價值的文章主要介紹了Python高階函數(shù)。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點(diǎn)擊"舉報違法"按鈕提交疑問。

Python實用教程_spiritx的博客-CSDN博客

高階函數(shù)是在Python中一個非常有用的功能函數(shù),所謂高階函數(shù)就是一個函數(shù)可以用來接收另一個函數(shù)作為參數(shù),這樣的函數(shù)叫做高階函數(shù)。高階函數(shù)是函數(shù)式編程的基本前提。

函數(shù)在 Python 是一等公民(First-Class Object),函數(shù)也是對象,是可調(diào)用對象,函數(shù)可以作為普通變量,也可以作為函數(shù)的參數(shù)、返回值,這也是python高階函數(shù)的語法基礎(chǔ)。

通常我們說的Python高階函數(shù)指的是函數(shù)的參數(shù)類型為函數(shù),或者函數(shù)的返回值類型為函數(shù),Python中常用的高階函數(shù)有map、filter、reduce、partial。

高階函數(shù)

概念

在數(shù)學(xué)和計算機(jī)科學(xué)中,高階函數(shù)應(yīng)當(dāng)是至少滿足下面一個條件的函數(shù):

  • 接受一個或多個函數(shù)作為參數(shù)
  • 輸出一個函數(shù)

數(shù)學(xué)概念 y=f(g(x))

# 高階函數(shù),例1:
def counter(base):
    def inc(step=1):             # 局部變量
        nonlocal base
        base += step
        return base
    return inc                   # 局部變量 inc函數(shù)對象,每次賦值即重新定義

c1 = counter(5)
c2 = counter(5)
print(c1, c2)     #c1、c2引用的是不同的函數(shù)對象
print(c1(), c2())                # 6 6
print(c1() == c2())              # True,函數(shù)對象的返回值相等
print(c1== c2)  # False,函數(shù)每次調(diào)用都不一樣

‘’'
<function counter.<locals>.inc at 0x106ed0540> <function counter.<locals>.inc at 0x106ed0b80>
6 6
True
False
‘''
def inc(step=1):
    return step

def counter():
    return inc     # 返回全局變量 inc

c1 = counter()
c2 = counter()
print(c1, c2) #c1和c2引用的是同一個函數(shù)對象
print(c1 == c2)    # True,因為全局變量 inc 不消亡

‘’'
<function inc at 0x10eb68540> <function inc at 0x10eb68540>
True
‘''

?高階函數(shù)特點(diǎn)

Python 高階函數(shù)的特點(diǎn):

  • 函數(shù)是對象類型(Object type)的實例
  • 可以將函數(shù)存儲在變量中
  • 可以將函數(shù)作為參數(shù)傳遞給另一個函數(shù)
  • 您可以從函數(shù)返回函數(shù)
  • 您可以將它們存儲在數(shù)據(jù)結(jié)構(gòu)中,如哈希表、列表等…

函數(shù)作為對象

在 Python中,可以將函數(shù)分配給變量,此賦值不調(diào)用函數(shù),而是創(chuàng)建對該函數(shù)的引用??紤]下面的例子,以便更好地理解。

def shout(text):
    return text.upper()

print(shout('Hello'))
# HELLO

# 將函數(shù)賦值給變量
yell = shout

print(yell('Hello'))
# HELLO

在上面的示例中,一個函數(shù)對象被 shout 引用,并創(chuàng)建指向它的第二個名稱 yell。

將函數(shù)作為參數(shù)傳遞給其他函數(shù)類似于 Python 中的對象,因此,它們可以作為參數(shù)傳遞給其他函數(shù)。請考慮下面的示例,在這里我們創(chuàng)建了一個函數(shù) greet,它將函數(shù)作為參數(shù)。

def shout(text):
    return text.upper()

def whisper(text):
    return text.lower()

def greet(func):
    # 將函數(shù)存儲在變量中
    greeting = func("Hi, I am created by a function \
    passed as an argument.")
    print(greeting)

greet(shout)
# HI, I AM CREATED BY A FUNCTION PASSED AS AN ARGUMENT.
greet(whisper)
# hi, i am created by a function passed as an argument.

返回函數(shù)

由于函數(shù)是對象,我們也可以從另一個函數(shù)返回一個函數(shù)。在下面的示例中,create_adder 函數(shù)返回 adder 函數(shù)。

# 來說明函數(shù)可以返回另一個函數(shù)
def create_adder(x):
    def adder(y):
        return x + y

    return adder

add_15 = create_adder(15)

print(add_15(10))
# 25

這個特性正好可以運(yùn)用到下邊的裝飾器的思想中。

裝飾器

裝飾器是 Python 中最常用的高階函數(shù)。它允許程序員修改函數(shù)或類的行為。裝飾器允許我們包裝另一個函數(shù),以擴(kuò)展包裝函數(shù)的行為,而無需永久修改它。在 Decorators 中,函數(shù)作為參數(shù)被放入另一個函數(shù)中,然后在包裝器函數(shù)中調(diào)用。

裝飾器的編寫方法為:

@gfg_decorator
def hello_decorator():
    ...

# 上述代碼相當(dāng)于:

def hello_decorator():
    ...

hello_decorator = gfg_decorator(hello_decorator)

在上面的代碼中,gfg_decorator 是一個可調(diào)用函數(shù),將在另一個可調(diào)用函數(shù) hello_decorator 函數(shù)的頂部添加一些代碼,并返回包裝器函數(shù)(wrapper function)。

# 定義一個裝飾器
def hello_decorator(func): 

    # inner1 is a Wrapper function in  
    # which the argument is called 

    # inner function can access the outer local 
    # functions like in this case "func" 
    def inner1(): 
        print("Hello, this is before function execution") 

        # calling the actual function now 
        # inside the wrapper function. 
        func() 

        print("This is after function execution") 

    return inner1 


# defining a function, to be called inside wrapper 
def function_to_be_used(): 
    print("This is inside the function !!") 


# passing 'function_to_be_used' inside the 
# decorator to control its behavior 
function_to_be_used = hello_decorator(function_to_be_used) 


# calling the function 
function_to_be_used() 

# 輸出
'''
Hello, this is before function execution
This is inside the function !!
This is after function execution
'''

閉包

說到高階函數(shù),就不得不提閉包,先來看一下Python中閉包的定義:

如果在一個內(nèi)部函數(shù)里,對在外部作用域(但不是在全局作用域)的變量進(jìn)行引用,那么內(nèi)部函數(shù)就被認(rèn)為是閉包(closure)。

def closure():
    x = 5

    def sub():
        return x * x

    return sub

如上,在內(nèi)部函數(shù)sub中包含了對函數(shù)closure中局部變量x的引用,這就是閉包。

filter()

基本定義

filter(function or None, iterable) --> filter object
  • function or None
    # 過濾操作執(zhí)行的函數(shù)
  • iterable
    # 需要過濾的序列

作用:過渡序列中不符合條件的元素。

filter有兩個參數(shù),第1參數(shù)可以是函數(shù),也可以是None.

當(dāng)?shù)?個參數(shù)是函數(shù)的時候,將第2個參數(shù)中每個元素進(jìn)行計算。

當(dāng)?shù)?個參數(shù)是None時,直接將第二個參數(shù)中為True的值篩選出來。

filter() 方法返回一個迭代器(filter 對象),該迭代器通過了 iterable 中每個元素的函數(shù)檢查,返回的是原序列中的值,非布爾值。

函數(shù)使用

lst = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
# 得到列表中的偶數(shù)
def func(x):
    return x % 2 == 0


result = filter(func, lst)
print(list(result))

# 輸出:
[2, 4, 6, 8, 10]

使用匿名函數(shù)

lst = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
print(list(filter(lambda x: x % 2 == 0, lst)))

如果未定義函數(shù)時,相當(dāng)于操作if <元素>,即:

filter(function, iterable) 相當(dāng)于一個生成器表達(dá)式,當(dāng) function 不是 None 的時候為 (item for item in iterable if function(item));function 是 None 的時候為 (item for item in iterable if item) 。

[*filter(None,[1,False,3])]
# [1, 3]

filter 對象

以值為偶數(shù)(除以2時余數(shù)為0)時返回 True 的 lambda(匿名函數(shù))為例:

l = [-2, -1, 0, 1, 2]
print(filter(lambda x: x % 2 == 0, l))
# <filter object at 0x10bb38580>

print(type(filter(lambda x: x % 2 == 0, l)))
# <class 'filter'>

?返回 filter 型的對象,即使直接 print(),也不輸出內(nèi)容的值,可以用 for 循環(huán)等方式取出來。

for i in filter(lambda x: x % 2 == 0, l):
    print(i)
# -2
# 0
# 2
# 篩選大于 5 的值
f = filter(lambda x: x>5, [2,3,5,7,9])
f # <filter at 0x7fe33ea36730>
list(f)
# [7, 9]

# 函數(shù)為 None
f = filter(None, [2,False,5,None,9])
list(f)
# [2, 5, 9]
# list of letters
letters = ['a', 'b', 'd', 'e', 'i', 'j', 'o']

# function that filters vowels
def filter_vowels(letter):
    vowels = ['a', 'e', 'i', 'o', 'u']

    if(letter in vowels):
        return True
    else:
        return False

filtered_vowels = filter(filter_vowels, letters)

print('The filtered vowels are:')
for vowel in filtered_vowels:
    print(vowel)
'''
The filtered vowels are:
a
e
i
o
'''

列表推導(dǎo)式替代

?可以用列表表達(dá)式實現(xiàn)它的功能:

l = [-2, -1, 0, 1, 2]
[x for x in l if x % 2 == 0]
# [-2, 0, 2]

[x for x in l if x % 2 != 0]
# [-1, 1]

l_s = ['apple', 'orange', 'strawberry']
[x for x in l_s if x.endswith('e')]
# ['apple', 'orange']

[x for x in l_s if not x.endswith('e')]
# ['strawberry']

l = [-2, -1, 0, 1, 2]
[x for x in l if x]
# [-2, -1, 1, 2]

l_2d = [[0, 1, 2], [], [3, 4, 5]]
[x for x in l_2d if x]
# [[0, 1, 2], [3, 4, 5]]

filterfalse()

itertools.filterfalse()?,只有 function 返回 false 時才選取 iterable 中元素的補(bǔ)充函數(shù)。和filter()函數(shù)的篩選機(jī)制相反。

import itertools

foo = itertools.filterfalse(lambda x: x%2==0, [1,3,1,5,6,8,1])
[*foo]
# [1, 3, 1, 5, 1]

map()

基本定義

map(func, *iterables) --> map object
  • function
    # 序列中的每個元素需要執(zhí)行的操作, 可以是匿名函數(shù)
  • *iterables
    # 一個或多個序列

作用:對可迭代對象的每一個元素作為函數(shù)的參數(shù)進(jìn)行運(yùn)算,然后將其添加到一個新的對象中返回。

返回一個將 function 應(yīng)用于 iterable 中每一項并輸出其結(jié)果的迭代器。 如果傳入了額外的 iterable 參數(shù),function 必須接受相同個數(shù)的實參并被應(yīng)用于從所有可迭代對象中并行獲取的項。 當(dāng)有多個可迭代對象時,最短的可迭代對象耗盡則整個迭代就將結(jié)束。

將給定的函數(shù)應(yīng)用于可迭代對象的每一項,并返回結(jié)果列表,返回的結(jié)果是一個 map object(map 對象),可以將 map object 傳遞給 list()(創(chuàng)建列表)、set()(創(chuàng)建集合)等函數(shù)以顯示和應(yīng)用結(jié)果。

單個迭代對象

# 對可迭代對象進(jìn)行2次方運(yùn)算
lst = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

result = map(lambda i: i ** 2, lst)
print(list(result))
#輸出
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

多個迭代對象

map支持多個迭代對象,也需要前面的函數(shù)支持多個輸入變量,如果 iterable 的數(shù)量不一樣,則取短板,其余的放棄,如把兩個列表對應(yīng)的元素求和:

r = map(lambda x, y: x + y, [1, 2, 3, 4], [5, 6, 7, 8])
print(list(r)) # 打印結(jié)果:[6, 8, 10, 12]
# 對象不同長度
def add_num(x, y):
    return x + y

m = map(add_num, [1,2,3,4], [1, 2])
list(m)
# [2, 4]

startmap()?

對于函數(shù)的輸入已經(jīng)是參數(shù)元組的情況,可以 使用 itertools.starmap() 操作。它創(chuàng)建一個迭代器,使用從可迭代對象中獲取的參數(shù)來計算該函數(shù)。當(dāng)參數(shù)對應(yīng)的形參已從一個單獨(dú)可迭代對象組合為元組時(數(shù)據(jù)已被“預(yù)組對”)可用此函數(shù)代替 map()。map() 與 starmap() 之間的區(qū)別可以類比 function(a,b) 與 function(*c) 的區(qū)別。

import itertools

t = [(2,5), (3,4)]
# 元組內(nèi)操作(相乘)
sm = itertools.starmap(lambda x,y: x*y, t)
list(sm)
# [10, 12]

? 列表推導(dǎo)式替代

map 的功能可以用列表表達(dá)式來代替:

l = [-2, -1, 0]
[abs(x) for x in l]
# [2, 1, 0]

[x**2 for x in l]
# [4, 1, 0]

l_1 = [1, 2, 3]
l_2 = [10, 20, 30]
[x * y for x, y in zip(l_1, l_2)]
# [10, 40, 90]

在大多數(shù)情況下,與 map 相比,使用列表生成器式更簡潔明了,但也有人認(rèn)為 map 作為高階函數(shù),能更加突出函數(shù),弱化了循環(huán)的表達(dá),讓處理邏輯看起來更加明顯。?

NumPy 代替

在數(shù)據(jù)科學(xué)中,不需要按 map 模式的計算,兩個序列之間的操作被認(rèn)為是一個矩陣計算,NumPy 可以非常好地完成這些,比 map() 和列表表示更為明確。

import numpy as np

a = np.array([-2, -1, 0])
print(np.abs(a))
# [2 1 0]

print(a**2)
# [4 1 0]

a_1 = np.array([1, 2, 3])
a_2 = np.array([10, 20, 30])
print(a_1 * a_2)
# [10 40 90]

對于大規(guī)模的列表的處理和復(fù)雜的處理NumPy更快。NumPy還提供各種函數(shù),所以在進(jìn)行以數(shù)值排列為對象的處理的情況下可以嘗試一下。

reduce()

基本定義

reduce(function, sequence[, initial]) -> value
  • function
    # 函數(shù), 序列中的每個元素需要執(zhí)行的操作, 可以是匿名函數(shù)
  • sequence
    # 需要執(zhí)行操作的序列
  • initial
    # 可選,初始參數(shù)

作用:reduce把一個函數(shù)作用在一個序列[x1, x2, x3…]上,這個函數(shù)必須接收兩個參數(shù),reduce把結(jié)果繼續(xù)和序列的下一個元素做累積計算,其效果就是:

reduce(f, [x1, x2, x3, x4]) = f(f(f(x1, x2), x3), x4)

每次函數(shù)計算的結(jié)果繼續(xù)和序列的下一個元素做累積計算。

可以理解為 reduce 中的第一個參數(shù) function 是一個函數(shù),它有兩個變量(function 的變量),iterable 是一個序列,function 第一次執(zhí)行時,按順序先取兩個傳入執(zhí)行,得到一個結(jié)果,然后再將這個結(jié)果與 iterable 中的下一個值(還是兩個變量)傳入 function 執(zhí)行,如此反復(fù)直到 iterable 里的值取完為止,最終就能得到一個終極的返回值。

例如,reduce(lambda x, y: x+y, [1, 2, 3, 4, 5]) 是計算 ((((1+2)+3)+4)+5) 的值。 左邊的參數(shù) x 是積累值而右邊的參數(shù) y 則是來自 iterable 的更新值。

簡單使用

要想使用,必需導(dǎo)入functools模塊。

# 求列表元素之和
import functools

lst = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]


def func(a, b):
    return a + b


result = functools.reduce(func, lst)
print(result)
輸出:
55

?使用匿名函數(shù):

import functools

lst = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
print(functools.reduce(lambda x, y: x + y, lst))

如果存在可選項 initializer,它會被放在參與計算的可迭代對象的條目之前,并在可迭代對象為空時作為默認(rèn)值。 如果沒有給出 initializer 并且 iterable 僅包含一個條目,則將返回第一項。

累積相除:

from functools import reduce
from operator import truediv

reduce(truediv, [4, 3, 2, 1])
reduce(lambda x,y: x/y, [4, 3, 2, 1])
# 0.6666666666666666

設(shè)定初始值

指定 initializer 參數(shù)時,第一次執(zhí)行時,函數(shù)的第一個參數(shù)傳入此值,第二個參數(shù)為序列的第一個值:

from functools import reduce
from operator import truediv

reduce(truediv, [10, 5, 2], 50)
# 0.5

?還可以把初始值當(dāng)做輸出的提示部分:?

# 設(shè)定初始參數(shù):
s = reduce(lambda x, y: x + y, ['1', '2', '3', '4', '5'], "數(shù)字 = ")

print(s)
# print out: 數(shù)字 = 12345

如果 initializer 沒有指定,序列也會空,則會報錯:

#當(dāng)序列為空時,則返回就是 initializer 的值
reduce(truediv, [], 50)
# 50

reduce(truediv, [])
# TypeError: reduce() of empty iterable with no initial value

性能和可讀性

Python的 reduce() 的性能可能非常差,因為它通過多次調(diào)用函數(shù)來工作。這會使您的代碼變得緩慢和低效。當(dāng)您將 reduce() 用于復(fù)雜的用戶定義函數(shù)或 lambda 函數(shù)時,使用 reduce() 還會影響代碼的可讀性。

Python 提供了一系列工具,可以優(yōu)雅地替換 reduce(),至少在其主要用例中是如此。主要有:

  • 盡可能使用專用函數(shù)解決 Python 的 reduce() 的用例。函數(shù)(如 sum、all、any、max、min、len、math.prod等)將使您的代碼更快、更可讀、更易于維護(hù),并且更具 Python 風(fēng)格。
  • 使用 reduce() 時避免使用復(fù)雜的用戶定義函數(shù)。這些類型的函數(shù)會使代碼難以閱讀和理解。您可以改為使用顯式且可讀的 for 循環(huán)。
  • 使用reduce() 時避免使用復(fù)雜的 lambda 函數(shù),它們還可能使您的代碼無法閱讀和混淆。

第二點(diǎn)和第三點(diǎn)是 Guido (Python 之父,專門撰文討論過 reduce 在 Python 3 的去留問題)自己的擔(dān)憂,他說:

所以現(xiàn)在 reduce() 這實際上是我最討厭的一個,因為除了一些涉及?+?或?*?的示例外,幾乎每次我看到帶有非平凡函數(shù)參數(shù)的 reduce() 調(diào)用時,我都需要抓起紙筆來繪制實際輸入到該函數(shù)中的內(nèi)容,然后才能理解 reduce() 應(yīng)該做什么。所以在我看來,reduce() 的適用性非常局限于關(guān)聯(lián)運(yùn)算符,在所有其他情況下,最好顯式寫出積累循環(huán)。(來源:https://www.artima.com/weblogs/viewpost.jsp?thread=98196)

?以下是用內(nèi)置函數(shù)與reduce() 方法的性能對比:

from timeit import timeit

print('sum()', timeit('sum(range(100))'))
print('reduce()', timeit('reduce(lambda x,y: x+y, range(100))',
                         setup='from functools import reduce'))

‘’'
sum() 1.5165458140254486
reduce() 8.190408975002356
‘''

如果您打算使用 reduce() 來解決問題,那么與使用專用內(nèi)置函數(shù)的代碼相比,您的代碼將慢得多,內(nèi)置函數(shù)比如求和問題(sum)最具可讀性和 python 風(fēng)格的解決方案。

sorted()

?基本定義

sorted(iterable,key,reverse)
  • iterable
    # 序列
  • key
    # 可以用來計算的排序函數(shù)。
  • reverse
    # 排序規(guī)則,reverse = True 降序,reverse = False 升序(默認(rèn))。

其中,iterable是可迭代對象。

key可選參數(shù),可以接收函數(shù)來實現(xiàn)自定義的排序,默認(rèn)為None(直接比較)。

reverse:排序規(guī)則,為一個布爾值,reverse = True 降序 , reverse = False 升序(默認(rèn))。

# 默認(rèn)情況下,對字符串排序,是按照ASCII的大小比較的
lst = ['bb', 'aaaa', 'c', 'ddddddddd', 'fff']
print(sorted(lst))
輸出:
['aaaa', 'bb', 'c', 'ddddddddd', 'fff']

#對列表按照int值排序
lst = [2, 5, '1', 3, '6', '4']
print(sorted(lst, key=int))
輸出:
['1', 2, 3, '4', 5, '6']

key 函數(shù)參數(shù)

對于更復(fù)雜的自定義排序,sorted() 采用可選的 key 參數(shù)指定一個函數(shù),該函數(shù)在比較之前轉(zhuǎn)換每個元素。key 函數(shù)接受 1 個值并返回1個值,返回的函數(shù)計算值(proxy)值用于排序中的比較。

例如,對于字符串列表,指定?key=len(內(nèi)置的?len()?函數(shù))按長度對字符串進(jìn)行排序,從最短到最長。排序?qū)γ總€字符串調(diào)用?len()?,以獲取代理長度值列表,然后使用這些代理值進(jìn)行排序。

strs = ['ccc', 'aaaa', 'd', 'bb']
sorted(strs, key=len)
# ['d', 'bb', 'ccc', 'aaaa']

可以自定義一個函數(shù),該函數(shù)接受一個值(這個值是序列中的每個元素),并返回代理值以指導(dǎo)排序。因此,key 傳入的是一個可調(diào)用對象,這個對接接受序列中的元素。

# 不區(qū)分大小寫的字符串比較
sorted("This is a test string from Andrew".split(), key=str.lower)
# ['a', 'Andrew', 'from', 'is', 'string', 'test', 'This']
# 使用第二個元素進(jìn)行排序
def take_second(elem):
    return elem[1]


# 隨便給一個列表
random = [(2, 2), (3, 4), (4, 1), (1, 3)]

# 帶關(guān)鍵字的排序列表
sorted_list = sorted(random, key=take_second)

# 打印 list
sorted_list
# [(4, 1), (2, 2), (1, 3), (3, 4)]

多健排序

假設(shè)我們有以下列表:

# 科學(xué)奧林匹克競賽中學(xué)生信息的嵌套列表
# 列表元素:(學(xué)生姓名,滿分100分,年齡)

participant_list = [
    ('Alison', 50, 18),
    ('Terence', 75, 12),
    ('David', 75, 20),
    ('Jimmy', 90, 22),
    ('John', 45, 12)
]

我們希望對列表進(jìn)行排序,使得分最高的學(xué)生位于開始位置,如果學(xué)生的分?jǐn)?shù)相等,則必須對他們進(jìn)行排序,以便年輕的參與者排在第一位。

我們可以通過返回元組而不是數(shù)字來實現(xiàn)這種多鍵排序。

兩個元組可以通過從第一個元組開始比較它們的元素來進(jìn)行比較。如果存在聯(lián)系(元素相等),則比較第二個元素,依此類推。

>>> (1,3) > (1, 4)
False
>>> (1, 4) < (2,2)
True
>>> (1, 4, 1) < (2, 1)
True

讓我們使用這個邏輯來構(gòu)建排序邏輯。

# Nested list of student's info in a Science Olympiad
# List elements: (Student's Name, Marks out of 100 , Age)
participant_list = [
    ('Alison', 50, 18),
    ('Terence', 75, 12),
    ('David', 75, 20),
    ('Jimmy', 90, 22),
    ('John', 45, 12)
]


def sorter(item):
    # 因為最高分在先,所以最小錯誤=最高分
    error = 100 - item[1]
    age = item[2]
    return (error, age)


sorted(participant_list, key=sorter)
# [('Jimmy', 90, 22), ('Terence', 75, 12), ('David', 75, 20), ('Alison', 50, 18), ('John', 45, 12)]

?由于排序邏輯函數(shù)很小,可以放在一行中,所以lambda函數(shù)在鍵內(nèi)使用,而不是傳遞單獨(dú)的函數(shù)名。上述程序可通過以下方式使用lambda函數(shù)編寫:

# Nested list of student's info in a Science Olympiad
# List elements: (Student's Name, Marks out of 100 , Age)
participant_list = [
    ('Alison', 50, 18),
    ('Terence', 75, 12),
    ('David', 75, 20),
    ('Jimmy', 90, 22),
    ('John', 45, 12)
]

sorted(participant_list, key=lambda item: (100-item[1], item[2]))
# [('Jimmy', 90, 22), ('Terence', 75, 12), ('David', 75, 20), ('Alison', 50, 18), ('John', 45, 12)]

排序原理

對字符的排序是按照 unicode 的碼位順序進(jìn)行排序的,但有一些細(xì)節(jié)實現(xiàn)比較復(fù)雜。排序算法只使用項目之間的?<?比較。雖然定義一個__lt__()?(小于)方法就足以進(jìn)行排序,但 PEP 8 建議實現(xiàn)所有六個比較功能("<" | ">" | "==" | ">=" | "<=" | "!=")的特殊方法,這將有助于避免將相同的數(shù)據(jù)與依賴于不同底層方法的其他排序工具(如?max()?)一起使用時出現(xiàn)錯誤。實現(xiàn)所有六個比較功能的特殊方法也有助于避免混合類型比較的混淆,混合類型比較可以調(diào)用?__gt__()?方法。

# vowels list
py_list = ['e', 'a', 'u', 'o', 'i']
sorted(py_list)
# ['a', 'e', 'i', 'o', 'u']

# string
py_string = 'Python'
sorted(py_string)
# ['P', 'h', 'n', 'o', 't', 'y']

# vowels tuple
py_tuple = ('e', 'a', 'u', 'o', 'i')
sorted(py_tuple)
# ['a', 'e', 'i', 'o', 'u']

請注意,在所有情況都會返回排序后的列表,不認(rèn)原數(shù)據(jù)是什么結(jié)構(gòu)。

按降序排序

sorted() 函數(shù)接受一個 reverse 參數(shù)作為可選參數(shù),設(shè)置 reverse=True 將按降序?qū)?iterable 進(jìn)行排序。

# set
py_set = {'e', 'a', 'u', 'o', 'i'}
print(sorted(py_set, reverse=True))
# ['u', 'o', 'i', 'e', 'a']

# dictionary
py_dict = {'e': 1, 'a': 2, 'u': 3, 'o': 4, 'i': 5}
sorted(py_dict, reverse=True)
# ['u', 'o', 'i', 'e', 'a']

# frozen set
frozen_set = frozenset(('e', 'a', 'u', 'o', 'i'))
sorted(frozen_set, reverse=True)
# ['u', 'o', 'i', 'e', 'a']

sort()與sorted的區(qū)別

  • sort() 函數(shù)只適用于列表排序,而sorted()函數(shù)適用于任意可以迭代的對象排序。
  • sort() 函數(shù)排序會改變原有的待排序列表,而sorted()函數(shù)則不會改變。所以在使用列表進(jìn)行排序時,需要考慮是否需要保存原列表,如果無需保存原列表,則優(yōu)先使用sort() 節(jié)省內(nèi)存空間,提高效率。

partial()

柯里化基本概念

partial 函數(shù)允許我們復(fù)刻函數(shù)的某些參數(shù)并生成新函數(shù)。函數(shù)在執(zhí)行時,要帶上所有必要的參數(shù)進(jìn)行調(diào)用。但是,有時參數(shù)可以在函數(shù)被調(diào)用之前提前獲知。這種情況下,一個函數(shù)有一個或多個參數(shù)預(yù)先就能用上,以便函數(shù)能用更少的參數(shù)進(jìn)行調(diào)用。簡單說就是局部套用一個函數(shù),讓廣泛功能的函數(shù)簡單化、單一化。這是一個 柯里化 過程。在數(shù)學(xué)和計算機(jī)科學(xué)中,柯里化是一種將使用多個參數(shù)的一個函數(shù)轉(zhuǎn)換成一系列使用一個參數(shù)的函數(shù)的技術(shù)。

簡單說 partial 把某個函數(shù)的某個參數(shù)固定,從而構(gòu)造出一個新的函數(shù)來。返回的這個新函數(shù)對象是 partial 對象,下文有介紹。

在一些情況下, 我們在設(shè)計 Python 函數(shù)的時候, 會給它設(shè)定非常豐富的功能, 這樣我們就可以定義一個非常強(qiáng)大的函數(shù)。 與此同時帶來的問題是使用上的不方便, 因為有可能我們需要傳遞非常多的參數(shù)才能換成我們想要的功能。這時候 partial 函數(shù)就可以讓我們在這個強(qiáng)大的函數(shù)中派生出對應(yīng)的具體功能。

在計算機(jī)科學(xué)中,柯里化(英語:Currying),又譯為科里化、卡瑞化、或加里化,是把接受多個參數(shù)的函數(shù)變換成接受一個單一參數(shù)(最初函數(shù)的第一個參數(shù))的函數(shù),并且返回接受余下的參數(shù)而且返回結(jié)果的新函數(shù)的技術(shù)。這個技術(shù)由克里斯托弗·斯特雷奇以邏輯學(xué)家哈斯凱爾·加里命名的,盡管它是Moses Sch?nfinkel和戈特洛布·弗雷格發(fā)明的。

例如,傳入百、十、個位數(shù)字生成數(shù)字:

from functools import partial

# 常規(guī)函數(shù)
def add(a, b, c):
    return 100 * a + 10 * b + c

# b=1,c=2 的部分函數(shù)
add_part = partial(add, c = 2, b = 1)

# 調(diào)用 partial 函數(shù)
add_part(3)
# 312

例如,我們有加法函數(shù)(實際上我們有 sum,不需要它),我們可以將它派生出不同的加法函數(shù):

from functools import partial

def add(a,b):
    return a + b

def add2number(x,y,z):
    return x + y + z


# a 固定值為 2
add2 = partial(add,2)
add2(1)
# 3

# 將 x 固定為 1,y 值固定為 2
add3 = partial(partial(add2number,1), 2)
add3(1)
# 4

語法定義

完整語法為:functools.partial(func, /, *args, **keywords),返回一個新的 partial 對象(部分對象,見下文),又稱偏函數(shù),主要用途是減少可調(diào)用對象的參數(shù)個數(shù),當(dāng)被調(diào)用時其行為類似于 func 附帶位置參數(shù) args 和關(guān)鍵字參數(shù) keywords 被調(diào)用。 如果為調(diào)用提供了更多的參數(shù),它們會被附加到 args。 如果提供了額外的關(guān)鍵字參數(shù),它們會擴(kuò)展并重載 keywords。 這個函數(shù)是使用 C 而不是 Python 實現(xiàn)的,大致等價于:

def partial(func, /, *args, **keywords):
    def newfunc(*fargs, **fkeywords):
        newkeywords = {**keywords, **fkeywords}
        return func(*args, *fargs, **newkeywords)
    newfunc.func = func
    newfunc.args = args
    newfunc.keywords = keywords
    return newfunc

partial() 會被“凍結(jié)了”一部分函數(shù)參數(shù)和/或關(guān)鍵字的部分函數(shù)應(yīng)用所使用,從而得到一個具有簡化簽名的新對象。 例如,partial() 可用來創(chuàng)建一個行為類似于 int() 函數(shù)的可調(diào)用對象,其中 base 參數(shù)默認(rèn)為二:

from functools import partial

basetwo = partial(int, base=2)
basetwo.__doc__ = 'Convert base 2 string to an int.'

basetwo('10010')
# 18

在類中使用

在類中如果想實現(xiàn) partial 類似的派生方法的話,可以使用 functools.partialmethod 方法,如:

import functools

class RGB(object):
    def __init__(self, red, blue, green):
        super(RGB, self).__init__()
        self._red = red
        self._blue = blue
        self._green = green

    def _color(self, type):
        return getattr(self, type)

    red = functools.partialmethod(_color, type='_red')
    blue = functools.partialmethod(_color, type='_blue')
    green = functools.partialmethod(_color, type='_green')

?partial 對象

partial 對象是由 partial() 創(chuàng)建的可調(diào)用對象。 它們具有三個只讀屬性:

  • partial.func:一個可調(diào)用對象或函數(shù)。 對 partial 對象的調(diào)用將被轉(zhuǎn)發(fā)給 func 并附帶新的參數(shù)和關(guān)鍵字。
  • partial.args:最左邊的位置參數(shù)將放置在提供給 partial 對象調(diào)用的位置參數(shù)之前。
  • partial.keywords:當(dāng)調(diào)用 partial 對象時將要提供的關(guān)鍵字參數(shù)。

partial 對象與 function 對象的類似之處在于它們都是可調(diào)用、可弱引用的對象并可擁有屬性。 但兩者也存在一些重要的區(qū)別。 例如前者不會自動創(chuàng)建?__name__?和?__doc__?屬性。 而且,在類中定義的 partial 對象的行為類似于靜態(tài)方法,并且不會在實例屬性查找期間轉(zhuǎn)換為綁定方法。

如上例 basetwo 就是一個 partial 對象:

from functools import partial

basetwo = partial(int, base=2)
basetwo
# functools.partial(<class 'int'>, base=2)

basetwo.args
# ()
basetwo.func
# int
basetwo.keywords
# {'base': 2}

偏函數(shù)可用于從常規(guī)函數(shù)派生專用函數(shù),從而幫助我們重用代碼。

這個特性類似于C++中的綁定。

Currying 是將一個具有n個參數(shù)的函數(shù)劃分為 n 個具有一個參數(shù)的連續(xù)函數(shù)。部分應(yīng)用程序是使用一些參數(shù)“預(yù)填充”函數(shù)( 'pre-filling' a function),然后返回參數(shù)數(shù)量較少的函數(shù)。

partialmethod()?

Python 內(nèi)置模塊 functools 的一個高階函數(shù) partialmethod 與 partial() 偏函數(shù) 類似,partialmethod 偏方法也是在對象里對已有的方法進(jìn)行派生,將功能復(fù)雜的方法衍生出簡單功能的方法。這是從 Python 3.4 版新功能。

偏函數(shù)基本概念

對于python 偏函數(shù)partial理解運(yùn)用起來比較簡單,就是對原函數(shù)某些參數(shù)設(shè)置默認(rèn)值,生成一個新函數(shù)。而如果對于類方法,因為第一個參數(shù)是 self,使用 partial 就會報錯了。

class functools.partialmethod(func, /, *args, **keywords)

返回一個新的 partialmethod 描述器,其行為類似 partial 但它被設(shè)計用作方法定義而非直接用作可調(diào)用對象。

func 必須是一個 descriptor 或可調(diào)用對象(同屬兩者的對象例如普通函數(shù)會被當(dāng)作描述器來處理)。

當(dāng) func 是一個描述器(例如普通 Python 函數(shù), classmethod(), staticmethod(), abstractmethod() 或其他 partialmethod 的實例)時, 對?__get__?的調(diào)用會被委托給底層的描述器,并會返回一個適當(dāng)?shù)?部分對象 作為結(jié)果。

當(dāng) func 是一個非描述器類可調(diào)用對象時,則會動態(tài)創(chuàng)建一個適當(dāng)?shù)慕壎ǚ椒ā?當(dāng)用作方法時其行為類似普通 Python 函數(shù):將會插入 self 參數(shù)作為第一個位置參數(shù),其位置甚至?xí)幱谔峁┙o partialmethod 構(gòu)造器的 args 和 keywords 之前。

定義類方法

from functools import partialmethod

class Cell:
    def __init__(self):
        self._alive = False
    @property
    def alive(self):
        return self._alive
    def set_state(self, state):
        self._alive = bool(state)

    set_alive = partialmethod(set_state, True)
    set_dead = partialmethod(set_state, False)

    print(type(partialmethod(set_state, False)))
    # <class 'functools.partialmethod'>

c = Cell()
c.alive
# False

c.set_alive()
c.alive
# True

c.set_alive() 和 c.set_dead() 作為 Cell 的方法,更加直觀,省去專門的定義代碼。

派生三方庫方法

pandas 的 apply 方法 默認(rèn) axis=0 按行去操作,我們需要一個派生一個按列的的操作:

from functools import partialmethod
import pandas as pd
import pandas._testing as tm

df = tm.makeDataFrame()
df
'''
                   A         B         C         D
D4mjVx3GtT  1.808966 -1.199819 -0.779483 -0.566463
ylYk4vm4MZ -1.509050 -0.361186  0.486100  0.021837
tDbfPX8Eva  0.141416  0.397220  0.172930 -0.504479
...
19tYkM1qrE -0.617952  1.137066 -0.962393  0.982731
mpQIQkifPC  0.874417  0.226630  0.739977 -0.786624
'''

# 使用原函數(shù)
df.apply(sum)
'''
A    4.621611
B    8.959269
C    0.126089
D    2.828309
dtype: float64
'''

# 定義偏方法
pd.DataFrame.apply_col = partialmethod(pd.DataFrame.apply, axis=1)

# 使用偏方法
df.apply_col(sum)
'''
D4mjVx3GtT   -0.736799
ylYk4vm4MZ   -1.362299
tDbfPX8Eva    0.207087
...
19tYkM1qrE    0.539452
mpQIQkifPC    1.054401
dtype: float64
'''

partial 對象

partialmethod 派生出的新方法是一個 partial 對象,它有 args、func、keywords 三個屬性,如在上例中:

pd.DataFrame.apply_col
# functools.partial(<function DataFrame.apply at 0x7fdb3057ae60>, axis=1)

pd.DataFrame.apply_col.args
# ()

pd.DataFrame.apply_col.func
# <function pandas.core.frame.DataFrame.apply(self, func: 'AggFuncType',
# axis: 'Axis' = 0, raw: 'bool' = False, result_type=None, args=(), **kwargs)>

pd.DataFrame.apply_col.keywords
# {'axis': 1}

與 partial 偏函數(shù)的區(qū)別

?partialmethod 針對對象中的方法進(jìn)行派生,partial 是對獨(dú)立的函數(shù)進(jìn)行派生。偏函數(shù) partial 對原函數(shù)某些參數(shù)設(shè)置默認(rèn)值,生成一個新函數(shù)。而如果對于類方法,因為第一個參數(shù)是 self,使用 partial 就會報錯,因此要使用 partialmethod。文章來源地址http://www.zghlxwxcb.cn/news/detail-684929.html

到了這里,關(guān)于Python高階函數(shù)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實不符,請點(diǎn)擊違法舉報進(jìn)行投訴反饋,一經(jīng)查實,立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • 深入理解Python裝飾器:解析高階函數(shù)與代碼美學(xué)

    深入理解Python裝飾器:解析高階函數(shù)與代碼美學(xué)

    當(dāng)談到Python編程中的高級特性時,裝飾器(decorators)是一個不可忽視的重要概念。裝飾器為我們提供了一種優(yōu)雅的方式來修改或擴(kuò)展函數(shù)的行為,而無需修改其原始代碼。在本文中,我們將深入探討Python裝飾器的概念、用法以及實際示例。 在Python中,裝飾器是一種特殊類型

    2024年02月12日
    瀏覽(31)
  • Python高階函數(shù)(Higher-order Function)

    Python高階函數(shù)(Higher-order Function)

    Python高階函數(shù)(Higher-order Function) abs()這個內(nèi)置函數(shù)來得到一個數(shù)的絕對值 print(abs(-100)) #輸出:100 我們把代碼修改下,把a(bǔ)bs賦值給一個變量: f = abs print(f(-100)) #輸出:100 函數(shù)名其實就是指向函數(shù)的變量 , abs(-100)是函數(shù)調(diào)用,而其名稱abs是函數(shù)本身,我們可以將其賦值給變

    2023年04月08日
    瀏覽(19)
  • Python內(nèi)置的20個高階函數(shù)的功能和示例詳解

    Python內(nèi)置的20個高階函數(shù)的功能和示例詳解

    ?? 個人網(wǎng)站:ipengtao.com Python是一門功能豐富的編程語言,提供了許多內(nèi)置函數(shù)來處理各種數(shù)據(jù)操作。其中,高階函數(shù)是一類特殊的函數(shù),它們接受其他函數(shù)作為參數(shù),或者返回函數(shù)作為結(jié)果。高階函數(shù)是函數(shù)式編程的核心概念之一,可以大大提高代碼的可讀性和靈活性。本

    2024年01月22日
    瀏覽(29)
  • 【python基礎(chǔ)語法六】迭代器,生成器,推導(dǎo)式和高階函數(shù)

    內(nèi)置函數(shù): dir 獲取當(dāng)前對象的內(nèi)置成員 高階函數(shù) : 能夠把函數(shù)當(dāng)成參數(shù)傳遞的就是高階函數(shù) (map ,filter ,reduce , sorted) 案例: 1. enumerate 2. zip 元組推導(dǎo)式是生成器( generator ) (1) 基本語法 (2) 優(yōu)化生成器代碼 (3) send 的使用方式 (給上一個 yield 發(fā)送數(shù)據(jù)) (4) yield from 的使用 (5) 案例

    2024年02月02日
    瀏覽(63)
  • C++&Python&C# 三語言O(shè)penCV從零開發(fā)(2):教程選擇

    C++&Python&C# 三語言O(shè)penCV從零開發(fā)(2):教程選擇

    C++PythonCsharp in OpenCV OpenCV 有官方的教程和簡單的視頻教程: OpenCV 官方教程 B站也有相關(guān)的視頻教學(xué) OpenCV4 C++ 快速入門視頻30講 - 系列合集 OpenCV4 C++ 課程筆記 那么選擇文本教程還是視頻教程呢?我個人建議是 視頻教程:零基礎(chǔ),一點(diǎn)都沒有接觸過 文本教程:有一定的基礎(chǔ),

    2024年01月21日
    瀏覽(29)
  • Python-Python高階技巧:HTTP協(xié)議、靜態(tài)Web服務(wù)器程序開發(fā)、循環(huán)接收客戶端的連接請求

    Python-Python高階技巧:HTTP協(xié)議、靜態(tài)Web服務(wù)器程序開發(fā)、循環(huán)接收客戶端的連接請求

    當(dāng)前版本號[20231114]。 版本 修改說明 20231114 初版 1.1 網(wǎng)址的概念 網(wǎng)址又稱為URL,URL的英文全拼是(Uniform Resoure Locator),表達(dá)的意思是 統(tǒng)一資源定位符 ,通俗理解就是網(wǎng)絡(luò)資源地址。 URL地址:https://www.itcast.com/18/1122/10/E178J2O4000189FH.html 1.2 URL的組成 域名 : IP地址的別名 ,它是用

    2024年02月04日
    瀏覽(39)
  • 高階C語言|字符函數(shù)和字符串函數(shù)--函數(shù)的模擬實現(xiàn)

    高階C語言|字符函數(shù)和字符串函數(shù)--函數(shù)的模擬實現(xiàn)

    C語言中對字符和字符串的處理很是頻繁,但是C語言本身是沒有字符串類型的,字符串通常放在 常量字符串 中或者 字符數(shù)組 中。 字符串常量 適用于那些對它不做修改的字符串函數(shù) size_t代表strlen函數(shù)返回的是一個無符號整形,str指向的是字符串,接收字符串的地址 字符串已

    2024年02月16日
    瀏覽(23)
  • 手把手QQ機(jī)器人制作教程,根據(jù)官方接口進(jìn)行開發(fā),基于Python語言制作的詳細(xì)教程(更新中)

    手把手QQ機(jī)器人制作教程,根據(jù)官方接口進(jìn)行開發(fā),基于Python語言制作的詳細(xì)教程(更新中)

    QQ開放平臺官方地址:https://q.qq.com/#/app/bot QQ開放平臺包含:QQ機(jī)器人、QQ小程序、QQ小游戲,我們這邊選擇QQ機(jī)器人。 機(jī)器人類型:設(shè)置私域機(jī)器人或者公域機(jī)器人,當(dāng)然公域機(jī)器人對于服務(wù)器的要求過高,我們這邊選擇 私域機(jī)器人 進(jìn)行開發(fā)。 特別注意在選擇沙箱頻道的時候

    2023年04月08日
    瀏覽(28)
  • Python教程(14)——Python函數(shù)的入門學(xué)習(xí)

    函數(shù)是什么?在編程中,函數(shù)是一段可重用的代碼塊,用于完成特定任務(wù)或執(zhí)行特定操作。它可以接輸入?yún)?shù)并返回一個值或執(zhí)行一系列操作。函數(shù)可以幫助程序員將代碼模塊化,提高代碼的可讀性和可維護(hù)性。 函數(shù)通常包括以下組成部分: 函數(shù)名:用于標(biāo)識函數(shù),并可以

    2024年02月08日
    瀏覽(45)
  • 〖Python 數(shù)據(jù)庫開發(fā)實戰(zhàn) - MongoDB篇?〗- MongoDB創(chuàng)建索引時的一些實用的重要選項參數(shù)

    訂閱 Python全棧白寶書-零基礎(chǔ)入門篇 可報銷! 白嫖入口-請點(diǎn)擊我。 推薦他人訂閱,可獲取扣除平臺費(fèi)用后的35%收益,文末名片加V! 說明:該文屬于 Python全棧白寶書專欄, 免費(fèi)階段訂閱數(shù)量4300+ , 購買任意白寶書體系化專欄可加入 TFS-CLUB 私域社區(qū)。 福利:加入社區(qū)的小伙

    2024年02月02日
    瀏覽(73)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包