国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

Python學習之路24-一等函數(shù)

wind3110991 / 2001人閱讀

摘要:函數(shù)內省的內容到此結束。函數(shù)式編程并不是一個函數(shù)式編程語言,但通過和等包的支持,也可以寫出函數(shù)式風格的代碼。

《流暢的Python》筆記。
本篇主要講述Python中函數(shù)的進階內容。包括函數(shù)和對象的關系,函數(shù)內省,Python中的函數(shù)式編程。
1. 前言

本片首先介紹函數(shù)和對象的關系;隨后介紹函數(shù)和可調用對象的關系,以及函數(shù)內省。函數(shù)內省這部分會涉及很多與IDE和框架相關的東西,如果平時并不寫框架,可以略過此部分。最后介紹函數(shù)式編程的相關概念,以及與之相關的兩個重要模塊:operator模塊和functools模塊。

首先補充“一等對象”的概念。“一等對象”一般定義如下:

在運行時創(chuàng)建;

能賦值給變量或數(shù)據(jù)結構中的元素;

能作為參數(shù)傳給函數(shù);

能作為函數(shù)的返回結果。

從上述定義可以看出,Python中的函數(shù)符合上述四點,所以在Python中函數(shù)也被視作一等對象。

“把函數(shù)視作一等對象”簡稱為“一等函數(shù)”,但這并不是指有一類函數(shù)是“一等函數(shù)”,在Python中所有函數(shù)都是一等函數(shù)

2. 函數(shù) 2.1 函數(shù)是對象

為了表明Python中函數(shù)就是對象,我們可以使用type()函數(shù)來判斷函數(shù)的類型,并且訪問函數(shù)的__doc__屬性,同時我們還將函數(shù)賦值給一個變量,并且將函數(shù)作為參數(shù)傳入另一個函數(shù):

def factorial(n):
    """return n!"""
    return 1 if n < 2 else n * factorial(n - 1)
# 在Python控制臺中,help(factorial)也會訪問函數(shù)的__doc__屬性。
print(factorial.__doc__)
print(type(factorial))
# 把函數(shù)賦值給一個變量
fact = factorial
print(fact)
fact(5)
# 把函數(shù)傳遞給另一個函數(shù)
print(list(map(fact, range(11))))

# 結果:
return n!


[1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880, 3628800]

從上述結果可以看出,__doc__屬性保存了函數(shù)的文檔字符串,而type()的結果說明函數(shù)其實是function類的一個實例。將函數(shù)賦值給一個變量和將函數(shù)作為參數(shù)傳遞給另一個函數(shù)則體現(xiàn)了“一等對象”的特性。

2.2 高階函數(shù)

接收函數(shù)作為參數(shù),或者把函數(shù)作為結果返回的函數(shù)叫做高階函數(shù)(higher-order function),上述的map函數(shù)就是高階函數(shù),還有我們常用的sorted函數(shù)也是。

大家或多或少見過mapfilterreduce三個函數(shù),這三個就是高階函數(shù),在過去很常用,但現(xiàn)在它們都有了替代品:

Python3中,mapfilter依然是內置函數(shù),但由于有了列表推導和生成器表達式,這兩個函數(shù)已不常用;

Python3中,reduce已不是內置函數(shù),它被放到了functools模塊中。它常被用于求和,但現(xiàn)在求和最好用內置的sum函數(shù)。

sumreduce這樣的函數(shù)叫做歸約函數(shù),它們的思想是將某個操作連續(xù)應用到一系列數(shù)據(jù)上,累計之前的結果,最后得到一個值,即將一系列元素歸約成一個值。

內置的歸約函數(shù)還有allany

all(iterable):如果iterable中每個值都為真,則返回Trueall([])返回True

any(iterable):如果iterable中有至少一個元素為真,則返回Trueany([])返回False

2.3 匿名函數(shù)

lambda關鍵字在Python表達式內創(chuàng)建匿名函數(shù),但在Python中,匿名函數(shù)內不能賦值,也不能使用whiletry等語句。但它和def語句一樣,實際創(chuàng)建了函數(shù)對象。

如果使用lambda表達式導致一段代碼難以理解,最好還是將其轉換成用def語句定義的函數(shù)。

3. 可調用對象

函數(shù)其實一個可調用對象,它實現(xiàn)了__call__方法。Python數(shù)據(jù)模型文檔列出了7種可調用對象:

用于定義的函數(shù):使用def語句或lambda表達式創(chuàng)建;

內置函數(shù):使用C語言(CPython)實現(xiàn)的函數(shù),如lentime.strftime

內置方法:使用C語言實現(xiàn)的方法,如dict.get

方法:在類的定義體中定義的函數(shù);

類:調用類時(也就是實例化一個類時)會運行類的__new__方法創(chuàng)建一個實例,然后運行__init__方法初始化實例,最后把實例返回給調用方。因為Python沒有new運算符,所以調用類相當于調用函數(shù);

類的實例:如果類實現(xiàn)了__call__方法,那么它的實例可以作為函數(shù)調用;

生成器函數(shù):使用yield關鍵字的函數(shù)或方法。調用生成器函數(shù)返回的是生成器對象。

3.1 用戶定義的可調用類型

任何Python對象都可以表現(xiàn)得像函數(shù),只要實現(xiàn)__call__方法。

class SayHello:
    def sayhello(self):
        print("Hello!")

    def __call__(self):
        self.sayhello()

say = SayHello()
say.sayhello()
say()
print(callable(say))

# 結果:
Hello!
Hello!
True

實現(xiàn)__call__方法的類是創(chuàng)建函數(shù)類對象的簡便方式。有時這些類必須在內部維護一些狀態(tài),讓它在調用之間可用,比如裝飾器。裝飾器必須是函數(shù),而且有時還要在多次調用之間保存一些數(shù)據(jù)。

3.2 函數(shù)內省

以下內容在編寫框架和IDE時用的比較多。

筆者之前偶有見到”內省“,但一直不明白”內省“這個詞究竟是什么意思。“自我反省”?其實在編程中,這個詞的意思就是:讓代碼自動確定某一段代碼能干什么。如果以函數(shù)舉例,就是函數(shù)A自動確定函數(shù)B是什么,包含哪些信息,能干什么。不過在講Python函數(shù)的內省之前,先來看看函數(shù)都有哪些屬性和方法。

3.2.1 函數(shù)的屬性和方法

dir函數(shù)可以檢測一個參數(shù)所含有的屬性和方法。我們可以用該函數(shù)查看一個函數(shù)所包含的屬性和方法:

>>> dir(factorial)
["__annotations__", "__call__", "__class__", "__closure__", "__code__", "__defaults__", 
"__delattr__", "__dict__", "__dir__", "__doc__", "__eq__", "__format__", "__ge__", "__get__", 
"__getattribute__", "__globals__", "__gt__", "__hash__", "__init__", "__init_subclass__", 
"__kwdefaults__", "__le__", "__lt__", "__module__", "__name__", "__ne__", "__new__", 
"__qualname__", "__reduce__", "__reduce_ex__", "__repr__", "__setattr__", "__sizeof__", 
"__str__", "__subclasshook__"]

其中大多數(shù)屬性是Python對象共有的。函數(shù)獨有的屬性如下:

>>> class C:pass
>>> obj = C()
>>> def func():pass
>>> sorted(set(dir(func)) - set(dir(obj)))
["__annotations__", "__call__", "__closure__", "__code__", "__defaults__", "__get__", 
"__globals__", "__kwdefaults__", "__name__", "__qualname__"]
3.2.2 __dict__屬性

與用戶定義的常規(guī)類一樣,函數(shù)使用__dict__屬性存儲用戶賦予它的屬性。這相當于一種基本形式的注解。

這里可能有人覺得別扭:之前都是給變量或者對象賦予屬性,現(xiàn)在是給函數(shù)或者方法賦予屬性。不過正如前面說的,Python中函數(shù)就是對象。

一般來說,為函數(shù)賦予屬性不是個常見的做法,但Django框架就有這樣的行為:

def upper_case_name(obj):
    return ("%s %s" % (obj.first_name, obj.last_name)).upper()
upper_case_name.short_description = "Customer name"   # 給方法賦予了一個屬性
3.2.3 獲取關于參數(shù)的信息

從這里開始就是函數(shù)內省的內容。在HTTP為框架Bobo中有個使用函數(shù)內省的例子,它以裝飾器的形式展示:

import bobo

@bobo.query("/")
def hello(person):
    return "Hello %s!" % person

通過裝飾器bobo.query,Bobo會內省hello函數(shù):Bobo會發(fā)現(xiàn)這個hello函數(shù)需要一個名為person的參數(shù),然后它就會從請求中獲取這個參數(shù),并將這個參數(shù)傳給hello函數(shù)。

有了這個裝飾器,我們就不用自己處理請求對象來獲取person參數(shù),Bobo框架幫我們自動完成了。

那這究竟是怎么實現(xiàn)的呢?Bobo怎么知道我們寫的函數(shù)需要哪些參數(shù)?它又是怎么知道參數(shù)有沒有默認值呢?

這里用到了函數(shù)對象特有的一些屬性(如果不了解參數(shù)類型,可以閱讀筆者的“Python學習之路7”中的相關內容):

__defaults__的值是一個元組,存儲著關鍵字參數(shù)的默認值位置參數(shù)

__kwdefaults__存儲著命名關鍵字參數(shù)的默認值

__code__屬性存儲參數(shù)的名稱,它的值是一個code對象引用,自身也有很多屬性。

下面通過一個例子說明這些屬性的用途:

def func(a, b=10):
    """This is just a test"""
    c = 20
    if a > 10:
        d = 30
    else:
        e = 30

print(func.__defaults__)
print(func.__code__)
print(func.__code__.co_varnames)
print(func.__code__.co_argcount)

# 結果:
(10,)

("a", "b", "c", "d", "e")
2

可以看出,這種信息的組織方式并不方便:

參數(shù)名在__code__.co_varnames中,它同時還存儲了函數(shù)定義體中的局部變量,因此,只有前__code__.co_argcount個元素是參數(shù)名(不包含前綴為***的的變長參數(shù));

如果想將參數(shù)名和默認值對應上,只能從后向前掃描__default__屬性,比如上例中關鍵字參數(shù)b的默認值10

不過,我們并不是第一個發(fā)現(xiàn)這種方式很不方便。已經有人為我們造好了輪子。

使用inspect模塊簡化上述操作
>>> from mytest import func
>>> from inspect import signature
>>> sig = signature(func) # 返回一個inspect.Signature對象(簽名對象)
>>> sig

>>> str(sig)
"(a, b=10)"
>>> for name, param in sig.parameters.items():
...     print(param.kind, ":", name, "=",param.default) 
...
POSITIONAL_OR_KEYWORD : a =  # 表示沒有默認值
POSITIONAL_OR_KEYWORD : b = 10

inspect.Signature對象有一個屬性parameters,該屬性是個有序映射,把參數(shù)名inspect.Parameter對象對應起來。inspect.Parameter也有自己的屬性,如:

name:參數(shù)的名稱;

default:參數(shù)的默認值;

kind:參數(shù)的類型,有5種,POSITIONAL_OR_KEYWORDVAR_POSITIONAL(任意數(shù)量參數(shù),以一個*號開頭的那種參數(shù)),VAR_KEYWORD(任意數(shù)量的關鍵字參數(shù),以**開頭的那種參數(shù)),KEYWORD_ONLY(命名關鍵字參數(shù))和POSITIONAL_ONLY(Python句法不支持該類型)

annotationreturn_annotation:參數(shù)和返回值的注解,后面會講到。

inspect.Signature對象有個bind方法,它可把任意個參數(shù)綁定到Singature中的形參上,框架可使用這個方法在真正調用函數(shù)前驗證參數(shù)是否正確。比如你自己寫的框架中的某函數(shù)A自動獲取用戶輸入的參數(shù),并根據(jù)這些參數(shù)調用函數(shù)B,但在調用B之前,你想檢測下這些參數(shù)是否符合函數(shù)B對形參的要求,此時你就有可能用到這個bind方法,看能不能將這些參數(shù)綁定到函數(shù)B上,如果能,則可認為能夠根據(jù)這些參數(shù)調用函數(shù)B:

>>> from mytest import func
>>> from inspect import signature
>>> sig = signature(func)
>>> my_tag = {"a":10, "b":20}
>>> bound_args = sig.bind(**my_tag)
>>> bound_args

>>> for name, value in bound_args.arguments.items():
...    print(name, "=", value)
a = 10
b = 20

>>> del my_tag["a"]
>>> bound_args = sig.bind(**my_tag)
Traceback (most recent call last):
TypeError: missing a required argument: "a"
3.2.4 函數(shù)注解

Python3提供了一種句法,用于為函數(shù)聲明中的參數(shù)和返回值附加元數(shù)據(jù)。如下:

# 未加注解
def func(a, b=10):
    return a + b
# 添加注解
def func(a: int, b: "int > 0" = 10) -> int:
    return a + b

各個參數(shù)可以在冒號后面增加注解表達式,如果有默認值,注解放在冒號和等號之間。上述-> int是對返回值添加注解的形式。

這些注解都存放在函數(shù)的__annotations__屬性中,它是一個字典:

print(func.__annotations__)

# 結果
# "return"表示返回值
{"a": , "b": "int > 0", "return": }

Python只是將注解存儲在函數(shù)的__annotations__屬性中,除此之外,再無任何操作。換句話說,這些注解對Python解釋器來說沒有意義。而這些注解的真正用途是提供給IDE、框架和裝飾器等工具使用,比如Mypy靜態(tài)類型檢測工具,它就會根據(jù)你寫的這些注解來檢測傳入的參數(shù)的類型是否符合要求。

inspect模塊可以獲取這些注解。inspect.Signature有個一個return_annotation屬性,它保存返回值的注解;inspect.Parameter對象中的annotation屬性保存了參數(shù)的注解。

函數(shù)內省的內容到此結束。后面將介紹標準庫中為函數(shù)式編程提供支持的常用包。

4. 函數(shù)式編程

Python并不是一個函數(shù)式編程語言,但通過operator和functools等包的支持,也可以寫出函數(shù)式風格的代碼。

4.1 operator模塊

在函數(shù)式編程中,經常需要把算術運算符當做函數(shù)使用,比如非遞歸求階乘,實現(xiàn)如下:

from functools import reduce
def fact(n):
    return reduce(lambda a, b: a * b, range(1, n + 1))

operator模塊為多個算術運算符提供了對應的函數(shù)。使用算術運算符函數(shù)可將上述代碼改寫如下:

from functools import reduce
from operator import mul
def fact(n):
    return reduce(mul, range(1, n + 1))

operator模塊中還有一類函數(shù),能替代從序列中取出元素或讀取對象屬性的lambda表達式:itemgetterattrgetter。這兩個函數(shù)其實會自行構建函數(shù)。

4.1.1 itemgetter()

以下代碼展示了itemgetter的常見用途:

from operator import itemgetter

test_data = [
    ("A", 1, "Alpha"),
    ("B", 3, "Beta"),
    ("C", 2, "Coco"),
]
# 相當于 lambda fields: fields[1]
for temp in sorted(test_data, key=itemgetter(1)):
    print(temp)

# 傳入多個參數(shù)時,它構建的函數(shù)返回下標對應的值構成的元組
part_tuple = itemgetter(1, 0)
for temp in test_data:
    print(part_tuple(temp))
    
# 結果:
("A", 1, "Alpha")
("C", 2, "Coco")
("B", 3, "Beta")
(1, "A")
(3, "B")
(2, "C")

itemgetter內部使用[]運算符,因此它不僅支持序列,還支持映射和任何實現(xiàn)了__getitem__方法的類。

4.1.2 attrgetter()

attrgetteritemgetter作用類似,它創(chuàng)建的函數(shù)根據(jù)名稱提取對象的屬性。如果傳入多個屬性名,它也會返回屬性名對應的值構成的元組。這里要展示的是,如果參數(shù)名中包含句點.attrgetter會深入嵌套對象,獲取指定的屬性:

from collections import namedtuple
from operator import attrgetter

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)),
]

LatLong = namedtuple("LatLong", "lat long")
Metropolis = namedtuple("Metropolis", "name, cc, pop, coord")
metro_areas = [Metropolis(name, cc, pop, LatLong(lat, long)) for
               name, cc, pop, (lat, long) in metro_data]
# 返回新的元組,獲取name屬性和嵌套的coord.lat屬性
name_lat = attrgetter("name", "coord.lat")   
for city in sorted(metro_areas, key=attrgetter("coord.lat")): # 嵌套
    print(name_lat(city))

# 結果:
("Mexico City", 19.433333)
("Delhi NCR", 28.613889)
("Tokyo", 35.689722)
4.1.3 methodcaller()

從名字也可看出,它創(chuàng)建的函數(shù)會在對象上調用參數(shù)指定的方法(注意是方法,而不是函數(shù))。

>>> from operator import methodcaller
>>> s = "The time has come"
>>> upcase = methodcaller("upper")
>>> upcase(s)  # 相當于s.upper()
"THE TIME HAS COME"
>>> hiphenate = methodcaller("replace"," ","-")
>>> hiphenate(s)  # 相當于s.replace(" ", "-")
"The-time-has-come"

hiphenate這個例子可以看出,methodcaller還可以凍結某些參數(shù),即部分應用(partial application),這與functools.partial函數(shù)的作用類似。

4.2 使用functools.partial凍結參數(shù)

functool模塊提供了一系列高階函數(shù),reduce函數(shù)相信大家已經很熟悉了,本節(jié)主要介紹其中兩個很有用的函數(shù)partial和它的變體partialmethod

functools.partial用到了一個“閉包”的概念,這個概念的詳細內容下一篇再介紹。使用這個函數(shù)可以把接收一個或多個參數(shù)的函數(shù)改編成需要回調的API,這樣參數(shù)更少。

>>> from operator import mul
>>> from functools import partial
>>> triple = partial(mul, 3)
>>> triple(7)
21
>>> list(map(triple, range(1,10))) # 這里無法直接使用mul函數(shù)
[3, 6, 9, 12, 15, 18, 21, 24, 27]
>>> triple.func  # 訪問原函數(shù)

>>> triple.args # 訪問固定參數(shù)
(3,)
>>> triple.keywords  # 訪問關鍵字參數(shù)
{}

functools.partialmethod函數(shù)的作用于partial一樣,只不過partialmethod用于方法,partial用于函數(shù)。

補充回調函數(shù)(callback function)可以簡單理解為,當一個函數(shù)X被傳遞給函數(shù)A時,函數(shù)X就被稱為回調函數(shù),函數(shù)A調用函數(shù)X的過程叫做回調

5. 總結

本篇首先介紹了函數(shù),包括函數(shù)與對象的關系,高階函數(shù)和匿名函數(shù),重點是函數(shù)就是對象;隨后介紹了函數(shù)和可調用對象的關系,以及函數(shù)的內省;最后,我們介紹了關于函數(shù)式編程的概念以及與之相關的兩個重要模塊。


迎大家關注我的微信公眾號"代碼港" & 個人網站 www.vpointer.net ~

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/44715.html

相關文章

  • Python學習之路25-使用一等函數(shù)實現(xiàn)設計模式

    摘要:本篇主要講述中使用函數(shù)來實現(xiàn)策略模式和命令模式,最后總結出這種做法背后的思想。 《流暢的Python》筆記。本篇主要講述Python中使用函數(shù)來實現(xiàn)策略模式和命令模式,最后總結出這種做法背后的思想。 1. 重構策略模式 策略模式如果用面向對象的思想來簡單解釋的話,其實就是多態(tài)。父類指向子類,根據(jù)子類對同一方法的不同重寫,得到不同結果。 1.1 經典的策略模式 下圖是經典的策略模式的U...

    econi 評論0 收藏0
  • python學習筆記 函數(shù)

    摘要:一等函數(shù)在中,函數(shù)是一等對象。匿名函數(shù)關鍵字在表達式內創(chuàng)建匿名函數(shù)然而,簡單的句法限制了函數(shù)的定義體只能使用純表達式,即函數(shù)的定義體中不能賦值,不能使用等語句。匿名函數(shù)適合用于作為函數(shù)的參數(shù) 一等函數(shù) 在python中,函數(shù)是一等對象。編程語言理論家把一等對象定義為滿足以下條件的程序實體: 在運行時創(chuàng)建 能賦值給變量或數(shù)據(jù)結構中的元素 能作為參數(shù)傳給函數(shù) 能作為函數(shù)的返回結果 在p...

    Scorpion 評論0 收藏0
  • Python一等函數(shù)簡析

    摘要:本文重點了解函數(shù)在中是一等對象了解中的可調用對象掌握正確定義函數(shù)參數(shù)的方法了解和中支持函數(shù)式編程的方法。歸約函數(shù)定義能夠接受一個可迭代對象并返回單個結果的函數(shù)是歸約函數(shù)。 導語:本文章記錄了本人在學習Python基礎之函數(shù)篇的重點知識及個人心得,打算入門Python的朋友們可以來一起學習并交流。 本文重點: 1、了解函數(shù)在Python中是一等對象;2、了解Python中的可調用對象;3...

    shusen 評論0 收藏0
  • Python一等函數(shù)簡析

    摘要:本文重點了解函數(shù)在中是一等對象了解中的可調用對象掌握正確定義函數(shù)參數(shù)的方法了解和中支持函數(shù)式編程的方法。歸約函數(shù)定義能夠接受一個可迭代對象并返回單個結果的函數(shù)是歸約函數(shù)。 本文章記錄了本人在學習Python基礎之函數(shù)篇的重點知識及個人心得,歡迎打算入門Python的朋友與我一起學習交流。。 本文重點: 1、了解函數(shù)在Python中是一等對象;2、了解Python中的可調用對象;3、掌握...

    鄒立鵬 評論0 收藏0
  • Python學習之路14-生成數(shù)據(jù)

    摘要:小結本篇主要講述了如何生成數(shù)據(jù)集以及如何對其進行可視化如何使用創(chuàng)建簡單的圖表如果使用散點圖來探索隨機漫步過程如何使用創(chuàng)建直方圖,以及如何使用直方圖來探索同時擲兩個面數(shù)不同的骰子的結果。 《Python編程:從入門到實踐》筆記。從本篇起將用三篇的篇幅介紹如何用Python進行數(shù)據(jù)可視化。 1. 前言 從本篇開始,我們將用三篇的篇幅來初步介紹如何使用Python來進行數(shù)據(jù)可視化操作。本篇的...

    wanglu1209 評論0 收藏0

發(fā)表評論

0條評論

wind3110991

|高級講師

TA的文章

閱讀更多
最新活動
閱讀需要支付1元查看
<