亚洲中字慕日产2020,大陆极品少妇内射AAAAAA,无码av大香线蕉伊人久久,久久精品国产亚洲av麻豆网站

資訊專(zhuān)欄INFORMATION COLUMN

[python] 初探'函數(shù)式編程'

xcc3641 / 1824人閱讀

摘要:前言繼續(xù)向下看廖大教程,看到了函數(shù)式編程這一節(jié),當(dāng)時(shí)是覺(jué)得沒(méi)啥用直接跳過(guò)了,這次準(zhǔn)備要仔細(xì)看一遍了,并記錄下一些心得。

前言

繼續(xù)向下看廖大教程,看到了函數(shù)式編程這一節(jié),當(dāng)時(shí)是覺(jué)得沒(méi)啥用直接跳過(guò)了,這次準(zhǔn)備要仔細(xì)看一遍了,并記錄下一些心得。

函數(shù)式編程

上學(xué)期有上一門(mén)叫 "人工智能" 的課,老師強(qiáng)行要我們學(xué)了一個(gè)叫做 prolog 的語(yǔ)言,哇那感覺(jué)確實(shí)難受,思維方式完全和之前學(xué)過(guò)的不一樣,寫(xiě)個(gè)漢諾塔想了半天,最后還是在網(wǎng)上找了段代碼修改一下(怕被老師發(fā)現(xiàn)抄襲)才寫(xiě)出來(lái),貼一段出來(lái)感受一下:

hanoi(N) :- dohanoi(N, "a", "b", "c").
dohanoi(0, _ , _ , _ )    :- !.
dohanoi(N, A, B, C)    :-
  N1 is N-1,
  dohanoi(N1, A, C, B),
  writeln([move, N, A-->C]), 
  dohanoi(N1, B, A, C).

當(dāng)時(shí)是差不多弄懂了,主要是資料實(shí)在太少,debug 都無(wú)從談起,一遇上 bug 就 gg,我現(xiàn)在自己看也有點(diǎn)頭暈。不過(guò)據(jù)說(shuō) prolog 當(dāng)年能和 Lisp 一爭(zhēng)高下,最近對(duì) Lisp 也有點(diǎn)興趣,等弄完這些就去參拜一下這類(lèi)函數(shù)式語(yǔ)言。

何謂函數(shù)式編程?廖大這里寫(xiě)道:

函數(shù)式編程就是一種抽象程度很高的編程范式,純粹的函數(shù)式編程語(yǔ)言編寫(xiě)的函數(shù)沒(méi)有變量,因此,任意一個(gè)函數(shù),只要輸入是確定的,輸出就是確定的,這種純函數(shù)我們稱(chēng)之為沒(méi)有副作用。而允許使用變量的程序設(shè)計(jì)語(yǔ)言,由于函數(shù)內(nèi)部的變量狀態(tài)不確定,同樣的輸入,可能得到不同的輸出,因此,這種函數(shù)是有副作用的。

可能看完還是有些不太理解,不急,先看完這幾個(gè)小節(jié)吧。

高階函數(shù)

在數(shù)學(xué)和計(jì)算機(jī)科學(xué)中,高階函數(shù)是至少滿(mǎn)足下列一個(gè)條件的函數(shù):

接受一個(gè)或多個(gè)函數(shù)作為輸入

輸出一個(gè)函數(shù)

也就是說(shuō),把函數(shù)本身當(dāng)成參數(shù)傳遞,或者返回一個(gè)函數(shù)。

例如,可以像普通賦值一樣將函數(shù)賦值給變量:

>>> min(1, 2)
1
>>> f = min
>>> f(1, 2)
1
>>> f

>>> min

也可以給函數(shù)賦值(代碼接上):

>>> min = 10
>>> min(1, 2)
Traceback (most recent call last):
  File "", line 1, in 
TypeError: "int" object is not callable
>>> f(1, 2)
1
>>> min = f
>>> min(1, 2)
1

還可以傳參,例如,一個(gè)計(jì)算所有數(shù)字的和的函數(shù):

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

>>> def mysum(f, *l):
...     a = 0
...     for i in l:
...             a = f(a, i)
...     return a
...
>>> mysum(add, 1, 2, 3)
6
>>> mysum(add, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
55

當(dāng)然,將這個(gè) f 換成乘法就是計(jì)算所有數(shù)字的乘積了。

再來(lái)看看 python 內(nèi)置的一些高階函數(shù),經(jīng)常會(huì)用到。

map/reduce

記得上學(xué)期上云計(jì)算的課程時(shí)依稀有聽(tīng)到過(guò)這個(gè)詞,不過(guò)這課很水,就沒(méi)怎么聽(tīng),在這里看到好像發(fā)現(xiàn)不太一樣??

不過(guò)沒(méi)啥說(shuō)的,簡(jiǎn)單說(shuō)一下每個(gè)函數(shù)的作用。

對(duì)于 map,其計(jì)算式可以看成這樣:

map(f, [x1, x2, ..., xn]) = [f(x1), f(x2), ..., f(xn)]

對(duì)于 reduce,其計(jì)算式可以看成這樣:

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

廖大那里說(shuō)得很清楚啦。

filter

filter 和 map 函數(shù)類(lèi)似,接受一個(gè)函數(shù)和 iterable,返回也是一個(gè) list,不過(guò)其功能是根據(jù)函數(shù)返回值是否為 True 來(lái)判斷是否保留該值。例如:

def is_odd(n):
    return n % 2 == 1

list(filter(is_odd, [1, 2, 4, 5, 6, 9, 10, 15]))
# 結(jié)果: [1, 5, 9, 15]
sorted

sorted 函數(shù)同樣是一個(gè)高階函數(shù),對(duì)參數(shù) key 傳遞函數(shù)可以將需要排列的序列經(jīng)過(guò) key 函數(shù)處理后再進(jìn)行排序,不過(guò)不會(huì)改變序列的值,例如:

>>> sorted([36, 5, -12, 9, -21], key=abs)
[5, 9, -12, -21, 36]
裝飾器(decorator)

匿名函數(shù)就不說(shuō)了,以后用時(shí)再仔細(xì)看吧,裝飾器我記得之前看 flask 的時(shí)候都研究了好久,這次再來(lái)復(fù)習(xí)一下。

簡(jiǎn)單裝飾器

首先是一個(gè)簡(jiǎn)單的裝飾器,在每次調(diào)用函數(shù)前打印出日志:

import logging

def log(func):
    def wrapper(*args, **kw):
        logging.warn("%s is running" % func.__name__)
        func(*args, **kw)
    return wrapper

這就是一個(gè)極其簡(jiǎn)單的裝飾器,如何使用它呢?我最先看到的用法是在需要裝飾的函數(shù)前添加@,但其實(shí)這是 Python 的一個(gè)語(yǔ)法糖,最原始的用法反而更能讓人理解,先定義一個(gè)函數(shù) f:

def f():
    print("in function f")

f = log(f)

這樣定義了之后,我們?cè)僬{(diào)用 f 函數(shù):

>>> f()
WARNING:root:f is running
in function f

使用 @log 的結(jié)果與其一樣,其實(shí)@符號(hào)作為裝飾器的語(yǔ)法糖,與前面的賦值語(yǔ)句具有相同的功能,使代碼看起來(lái)更簡(jiǎn)潔明了,避免再一次賦值操作,就像下面這樣:

@log
def f():
    print("in function f")
含參數(shù)的裝飾器

有時(shí)候我們還需要向裝飾器中傳入?yún)?shù),例如,狀態(tài),層次等信息,只需要在 wrapper 函數(shù)外再"包裹"一層函數(shù),如下所示:

import logging

def log(level):
    def decorator(func):
        def wrapper(*args, **kw):
            logging.warn("%s is running at level %d" % (func.__name__, level))
            return func(*args, **kw)
        return wrapper
    return decorator

@log(2)
def f():
    print("in function f")
    
>>> f()
WARNING:root:f is running at level 2
in function f
進(jìn)一步理解

為了再進(jìn)一步理解裝飾器,我們可以打印出函數(shù) f 的 name 屬性:

#對(duì)于不加裝飾器的 f,其 name 不變
>>> def f():
...     print("in function f")
...
>>> f.__name__
"f"

#對(duì)于添加裝飾器的函數(shù),其 name 改變了
>>> @log
... def f():
...     print("in function f")
...
>>> f.__name__
"wrapper"

聯(lián)系到最前面的裝飾器賦值語(yǔ)句,就可以大致明白發(fā)生了什么:f = log(f) 使得 f 指向修改為 log(f) 的返回值,即 wrapper 函數(shù)。每次運(yùn)行原函數(shù) f 時(shí),則會(huì)調(diào)用 wrapper 函數(shù),在我們這個(gè)例子中,則是先打印日志,然后運(yùn)行原函數(shù) f。

不過(guò)這樣有一個(gè)問(wèn)題,這樣使得原函數(shù) f 的元信息被替換了,關(guān)于 f 的許多信息消失不見(jiàn),這是很難令人接受的,不過(guò)好在我們有 functools 模塊,修改函數(shù)為:

import functools
import logging

def log(func):
    functools.wraps(func)
    def wrapper(*args, **kw):
        logging.warn("%s is running" % func.__name__)
        func(*args, **kw)
    return wrapper

>>> @log
... def f():
...     print("in function f")
...
>>> f.__name__
"f"

另外,還可以對(duì)同一個(gè)函數(shù)添加多個(gè)裝飾器:

@a
@b
@c
def f ():


# 等價(jià)于

f = a(b(c(f)))
總結(jié)

關(guān)于函數(shù)式編程我也不是很了解,這里只是大概了解了一下其概念吧,平時(shí)肯定還是使用命令式編程用得多。不過(guò)有語(yǔ)言是純函數(shù)式語(yǔ)言,例如 Haskell 或 Lisp,學(xué)習(xí)它們會(huì)使得人打開(kāi)一種新思路。

以上~

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

轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/38437.html

相關(guān)文章

  • Python源碼理解: '+=' 和 'xx = xx + xx�

    摘要:前菜在我們使用的過(guò)程很多時(shí)候會(huì)用到運(yùn)算例如輸出不光在加法中使用在字符串的拼接也同樣發(fā)揮這重要的作用例如輸出同樣的在列表中也能使用例如輸出為什么上面不同的對(duì)象執(zhí)行同一個(gè)會(huì)有不同的效果呢這就涉及到的重載然而這不是本文要討論的重點(diǎn)上面的只是前菜而 前菜 在我們使用Python的過(guò)程, 很多時(shí)候會(huì)用到+運(yùn)算, 例如: a = 1 + 2 print a # 輸出 3 不光在加法中使用, 在...

    learning 評(píng)論0 收藏0
  • python3 logging 'ascii' codec can't

    摘要:環(huán)境問(wèn)題發(fā)現(xiàn)最近剛從換到下搬磚,發(fā)現(xiàn)在跑的好好的代碼,在下終端老是報(bào)錯(cuò)還是編碼錯(cuò)誤注冊(cè)失敗坦白說(shuō),看到這個(gè)錯(cuò)誤好無(wú)奈。既然能在跑,換到就出錯(cuò),那多半是環(huán)境問(wèn)題了,然后我就開(kāi)始了我的調(diào)試追蹤之旅了跟蹤調(diào)試先前調(diào)試都是一晃而過(guò),只看結(jié)果。 環(huán)境:mac 10.12 python3 django 1.10 問(wèn)題發(fā)現(xiàn) 最近剛從arch 換到 mac下搬磚, 發(fā)現(xiàn)在arch跑的好好的代碼,...

    txgcwm 評(píng)論0 收藏0
  • python】[轉(zhuǎn)載]UnicodeEncodeError: 'ascii'

    摘要:原因在安裝時(shí),默認(rèn)的編碼是,當(dāng)程序中出現(xiàn)非編碼時(shí),的處理常常會(huì)報(bào)這樣的錯(cuò),不過(guò)在就不會(huì)有這樣的問(wèn)題。 1、原因 python2.7在安裝時(shí),默認(rèn)的編碼是ascii,當(dāng)程序中出現(xiàn)非ascii編碼時(shí),python的處理常常會(huì)報(bào)這樣的錯(cuò),不過(guò)在python3就不會(huì)有這樣的問(wèn)題。 2、解決辦法 臨時(shí)解決方法: 代碼中加入如下三行import sys reload(sys) sys.setd...

    Airy 評(píng)論0 收藏0
  • local variable 'var1' referenced before

    摘要:起初是群里一個(gè)哥們這句話(huà)報(bào)錯(cuò)。我竟然沒(méi)看懂代碼如下其實(shí)這個(gè)代碼不能很好的反應(yīng)問(wèn)題。來(lái)看以下兩個(gè)我一開(kāi)始沒(méi)理解這個(gè)問(wèn)題。看到和粗略的理解成不能夠在閉包函數(shù)中改變上層函數(shù)的變量。實(shí)際上是,如果一個(gè)變量被賦值,那么會(huì)認(rèn)為其為局部變量。 起初是群里一個(gè)哥們這句話(huà)報(bào)錯(cuò)。后來(lái)之前的一個(gè)實(shí)習(xí)生,給出了鏈接來(lái)解釋這個(gè)問(wèn)題。 我竟然沒(méi)看懂.... http://stackoverflow.com/que...

    Aklman 評(píng)論0 收藏0
  • 寫(xiě)了2年python,知道 if __name__ == '__main__'

    摘要:原因很簡(jiǎn)單,因?yàn)橹械拇淼木褪钱?dāng)前執(zhí)行的模塊名。缺點(diǎn)就是主程序會(huì)受待執(zhí)行程序的影響,會(huì)出現(xiàn)待執(zhí)行程序中拋異?;蛑鲃?dòng)退出會(huì)導(dǎo)致主程序也退出的尷尬問(wèn)題??偨Y(jié)來(lái)說(shuō)就是,一個(gè)是在子進(jìn)程中執(zhí)行代碼,一個(gè)是在當(dāng)前進(jìn)程中執(zhí)行代碼。 showImg(https://segmentfault.com/img/remote/1460000018607395?w=502&h=318); 相信剛接觸Pytho...

    wangbinke 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<