Python函數式編程 map reduce filter

 

函數式編程,使代碼簡潔高效。html

函數編程語言最重要的基礎是λ演算(lambda calculus),函數能夠像數值同樣被賦值於變量,還能夠做爲其餘函數的輸入(引數)和輸出(傳出值)進行傳遞。python

函數能夠當作參數來進行傳遞,造成所謂的高階函數,形如 z=g(f(x),y),還能像變量同樣被建立和修改。算法

 

 

Map函數:編程

  map(func, *iterables),做用是將一個列表映射到另外一個列表。設計模式

class map(object):
    """
    map(func, *iterables) --> map object
    
    Make an iterator that computes the function using arguments from
    each of the iterables.  Stops when the shortest iterable is exhausted.
    """
View Code

 

使用方法:數組

def f(x):
    return x**2

li = range(1,10)
res = map(f,li)
print(res)
print(list(res))

"""
<map object at 0x000000000117E2E8>
[1, 4, 9, 16, 25, 36, 49, 64, 81]
"""

       

 

map(functioniterable...)app

map()函數接收兩個參數,一個是函數,一個是可迭代的對象,map將傳入的函數依次做用到序列的每一個元素,返回一個map對象,不是list。編程語言

 

基本等價於 [f(x) for x in interable],列表推導比map效率要高一些ide

map(lambda x: x+1, range(1, 3)) => [x+1 for x in range(1,3)]函數式編程

 

str = ["far","foo","bar"]
mp = map(lambda x:x.upper(),str)
res = list(mp)
print(res)

"""
['FAR', 'FOO', 'BAR']
"""
View Code

 

 

Reduce函數

  reduce(function, sequence[, initial]),對可迭代對象依次作累計操做,如依次相加或相乘。

  reduce()方法接收一個函數做爲累加器(accumulator),數組中的每一個值(從左到右)開始合併,最終爲一個值。

def reduce(function, sequence, initial=None): # real signature unknown; restored from __doc__
    """
    reduce(function, sequence[, initial]) -> value
    
    Apply a function of two arguments cumulatively to the items of a sequence,
    from left to right, so as to reduce the sequence to a single value.
    For example, reduce(lambda x, y: x+y, [1, 2, 3, 4, 5]) calculates
    ((((1+2)+3)+4)+5).  If initial is present, it is placed before the items
    of the sequence in the calculation, and serves as a default when the
    sequence is empty.
    """
View Code

 

直接使用會報錯

reduce(lambda x, y : x + y, [1, 3, 5, 7, 9])
"""
NameError: name 'reduce' is not defined
"""

正確的使用是:reduce是functools中的一個函數,須要引用:from functools import reduce

 

使用方法:

from functools import reduce

res1 = reduce(lambda x, y: x*y, [1, 2, 3])
res2 = reduce(lambda x, y : x + y, [1, 3, 5])
print(res1)
print(res2)

"""
6
9
"""

 

 Python內置的all(),any(),sum(),max(),min()等函數都是從reduce()衍生而來。

 

Filter函數

  filter(function or None, iterable),做用是按照所定義的函數過濾掉列表中的一些元素

class filter(object):
    """
    filter(function or None, iterable) --> filter object
    
    Return an iterator yielding those items of iterable for which function(item)
    is true. If function is None, return the items that are true.
    """
View Code

 

使用方法:

flt = filter(lambda x: x > 5, range(10))
res = list(flt)
print(flt)
print(res)
"""
<filter object at 0x0000000000649A58>
[6, 7, 8, 9]
"""

 

 

生成器

 

經過列表生成式,能夠直接建立一個列表。但受內存限制,列表容量有限。建立一個包含100萬個元素的列表,會佔用很大的存儲空間,若是咱們僅僅須要訪問其中幾個元素,那絕大多數元素佔用的空間都白白浪費了。

因此,若是列表元素能夠按照某種算法推算出來,那咱們是否能夠在循環的過程當中不斷推算出後續的元素呢?這樣就沒必要建立完整的list,從而節省大量的空間。在Python中,這種一邊循環一邊計算的機制,稱爲生成器:generator。

 

要建立一個generator,有不少種方法。最簡單的方法是,只要把一個列表生成式的[]改爲(),就建立了一個generator:

lis = [x*x for x in range(10)]  # list
gen = (x*x for x in range(10))  # generator對象,與list的區別,只是最外層的()
print(lis)
print(gen)
"""
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
<generator object <genexpr> at 0x000000000118C8E0>
"""

 

  一個函數調用時返回一個迭代器,那這個函數就叫作生成器(generator);

  若是函數中包含yield語法,那這個函數就會變成生成器。

def cube(n):
    for i in range(n):
        yield i ** 3

for i in cube(5):
    print(i)

"""
0
1
8
27
64
"""
View Code

 

生成器的特色:

1)生成器只有在調用時纔會生成相應的數據;

2)只記錄當前位置;

3)只有一個__next__()方法;

 

yield 的實現

def simple_yield(start):
    n = start
    while True:
        yield n
        n += 1

if __name__ == '__main__':
    for i in simple_yield(5):
        print(i)
        if i >= 10:
            break
"""
5
6
7
8
9
10
"""
View Code

從 simple_yield 中拿數據,拿到數據後,yield 會當即返回(可能有返回值),函數自己並無結束,只是被掛起,直到下次調用(for 循環會調用 next 方法)再從掛起的地方(yield)開始執行。

 

怎麼打印出generator的每個元素?

一、若是要一個一個打印出來,能夠經過next()函數得到generator的下一個返回值;

二、for循環迭代

lis = [x*x for x in range(10)]  # list
gen = (x*x for x in range(10))  # generator對象,與list的區別,只是最外層的()
print(lis)
print(gen)
print(next(gen))
print(next(gen))
print(next(gen))

for i in gen:
    print(i)

"""
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
<generator object <genexpr> at 0x000000000119C8E0>
0
1
4
9
16
25
36
49
64
81
"""
View Code

 

斐波拉契數列(Fibonacci)

除第一個和第二個數外,任意一個數均可由前兩個數相加獲得:1, 2, 3, 5, 8, 13, 21, 34, ...

def fib(max):
    n,a,b = 0,0,1
    while n < max:
        print(b)
        a,b = b, a + b
        n += 1
View Code

 

 

迭代器

 

能夠直接做用於for循環的數據類型有如下幾種:

一類是集合數據類型,如listtupledictsetstr等;

一類是generator,包括生成器和帶yield的generator function。

 

這些能夠直接做用於for循環的對象統稱爲可迭代對象:Iterable。可使用isinstance()判斷一個對象是不是Iterable對象。

from collections import Iterable

lt1 = isinstance([],Iterable)
lt2 = isinstance({},Iterable)
lt3 = isinstance('abc',Iterable)
lt4 = isinstance((x for x in range(10)), Iterable)
lt5 = isinstance(100, Iterable)

print(lt1, lt2,lt3,lt4,lt5)
"""
True True True True False
"""
View Code

 

凡是可做用於for循環的對象都是Iterable類型;

凡是可做用於next()函數的對象都是Iterator類型,它們表示一個惰性計算的序列;

 

集合數據類型如listdictstr等是Iterable,但不是Iterator,不過能夠經過iter()函數得到一個Iterator對象。

 

Python的for循環本質上就是經過不斷調用next()函數實現的,例如:

for in [1,2,3,4,5]:

pass
 
實際上徹底等價於:
# 首先得到Iterator對象:
it = iter([1, 2, 3, 4, 5])
# 循環:
while True:
    try:
        # 得到下一個值:
        x = next(it)
    except StopIteration:
        # 遇到StopIteration就退出循環
        break

 

 

裝飾器

本質上是個函數,功能是裝飾其餘函數——就是爲其餘函數添加附加功能。

 

裝飾器是一個很著名的設計模式,常常被用於有切面需求的場景,較爲經典的有插入日誌、性能測試、事務處理等。裝飾器是解決這類問題的絕佳設計,有了裝飾器,咱們就能夠抽離出大量函數中與函數功能自己無關的雷同代碼並繼續重用。歸納的講,裝飾器的做用就是爲已經存在的對象添加額外的功能。

 

裝飾器原則:

1)不能修改被裝飾函數的源代碼;

 2)不能修改被裝飾函數的調用方式;

 

 

########## 基本裝飾器 ##########
def orter(func):    #定義裝飾器
    def inner():
        print("This is inner before.")
        s = func()    #調用原傳入參數函數執行
        print("This is inner after.")
        return s        #return原函數返回值
    return inner      #將inner函數return給name函數

@orter    #調用裝飾器(將函數name當參數傳入orter裝飾器)
def name():
    print("This is name.")
    return True        #name原函數return True 

ret = name()
print(ret)

輸出結果:
This is inner before.
This is name.
This is inner after.
True
View Code

 

############ 裝飾器傳參數 ###########
def orter(func):
    def inner(a,b):      #接收傳入的2個參數
        print("This is inner before.")
        s = func(a,b)    #接收傳入的原函數2個參數
        print("This is inner after.")
        return s
    return inner

@orter
def name(a,b):    #接收傳入的2個參數,並name總體函數當參數傳入orter裝飾器
    print("This is name.%s,%s"%(a,b))
    return True

ret = name('nick','jenny')    #傳入2個參數
print(ret)

輸出結果:
This is inner before.
This is name.nick,jenny
This is inner after.
True
View Code

 

########## 萬能參數裝飾器 ##########
def orter(func):
    def inner(*args,**kwargs):        #萬能參數接收多個參數
        print("This is inner before.")
        s = func(*args,**kwargs)       #萬能參數接收多個參數
        print("This is inner after.")
        return s
    return inner

@orter
def name(a,b,c,k1='nick'):        #接受傳入的多個參數
    print("This is name.%s,%s"%(a,b))
    return True

ret = name('nick','jenny','car')
print(ret)

輸出結果:
This is inner before.
This is name.nick,jenny
This is inner after.
True
View Code

 

########### 一個函數應用多個裝飾器 #########

def orter(func):
    def inner(*args,**kwargs):
        print("This is inner one before.")
        print("This is inner one before angin.")
        s = func(*args,**kwargs)
        print("This is inner one after.")
        print("This is inner one after angin.")
        return s
    return inner

def orter_2(func):
    def inner(*args,**kwargs):
        print("This is inner two before.")
        print("This is inner two before angin.")
        s = func(*args,**kwargs)
        print("This is inner two after.")
        print("This is inner two after angin.")
        return s
    return inner

@orter            #將如下函數總體當參數傳入orter裝飾器  
@orter_2          #將如下函數當參數傳入orter_2裝飾器  
def name(a,b,c,k1='nick'):
    print("This is name.%s and %s."%(a,b))
    return True

ret = name('nick','jenny','car')
print(ret)

輸出結果:
This is inner one before.
This is inner one before angin.
This is inner two before.
This is inner two before angin.
This is name.nick and jenny.
This is inner two after.
This is inner two after angin.
This is inner one after.
This is inner one after angin.
True
View Code

 

 

實現裝飾器知識儲備:

函數即「變量」

定義一個函數至關於把函數體賦值給了函數名

 

1.函數調用順序

與其餘高級語言相似,python不容許在函數未聲明以前,對其進行引用或者調用

錯誤示範:

def foo():
    print('in the foo')
    bar()
foo()

"""
NameError: name 'bar' is not defined
"""
View Code

 

正確示範:(注意,python爲解釋執行,函數foo在調用前已經聲明瞭bar和foo,因此bar和foo無順序之分)

def foo():
    print('in the foo')
    bar()
def bar():
    print('in the bar')
foo()

def bar():
    print('in the bar')
def foo():
    print('in the foo')
    bar()
foo()

"""
in the foo
in the bar
in the foo
in the bar
"""
View Code

 

2.高階函數

知足下列條件之一就可稱函數爲高階函數

  1.某一函數當作參數傳入另外一個函數中

  2.函數的返回值包含n個函數,n>0

 

高階函數示範:

def bar():
    print('in the bar')
def foo(func):
    res=func()
    return res
foo(bar)
"""
in the bar
"""
View Code

 

3.內嵌函數和變量做用域

  在一個函數體內建立另外一個函數,這種函數就叫內嵌函數。

 

嵌套函數:

def foo():
    def bar():
        print('in the bar')
    bar()
foo()
"""
in the bar
"""
View Code

 

局部做用域和全局作用域的訪問順序

x = 0
def grandpa():
    def dad():
        x = 2
        def son():
            x=3
            print(x)
        son()
    dad()
grandpa()
"""
3
"""
View Code

 

4.高階函數+內嵌函數  ==》 裝飾器

 

函數參數固定

def decorartor(func):
    def wrapper(n):
        print('starting')
        func(n)
        print('stopping')
    return wrapper

def test(n):
    print('in the test arg is %s' %n)
decorartor(test)('alex')
View Code

 

函數參數不固定

def decorartor(func):
    def wrapper(*args,**kwargs):
        print('starting')
        func(*args,**kwargs)
        print('stopping')
    return wrapper

def test(n,x=1):
    print('in the test arg is %s' %n)
decorartor(test)('alex',x=2222)
View Code

 

1.無參裝飾器

import time
def decorator(func):
    def wrapper(*args,**kwargs):
        start_time=time.time()
        func(*args,**kwargs)
        stop_time=time.time()
        print("%s" %(stop_time-start_time))
    return wrapper

@decorator
def test(list_test):
    for i in list_test:
        time.sleep(0.1)
        print('-'*20,i)

#decorator(test)(range(10))
test(range(10))
View Code

 

2.有參裝飾器

import time
def timer(timeout=0):
    def decorator(func):
        def wrapper(*args,**kwargs):
            start=time.time()
            func(*args,**kwargs)
            stop=time.time()
            print('run time is %s ' %(stop-start))
            print(timeout)
        return wrapper
    return decorator
@timer(2)
def test(list_test):
    for i in list_test:
        time.sleep(0.1)
        print ('-'*20,i)
  
#timer(timeout=10)(test)(range(10))
test(range(10))
View Code

 

3.終極裝飾器

user,passwd = 'alex','abc123'
def auth(auth_type):
    print('auth func:',auth_type)
    def outer_wrapper(func):
        def wrapper(*args,**kwargs):
            print("wrapper func args:",*args,**kwargs)
            if auth_type=="local":
                username = input("Username:").strip()
                password = input("Password:").strip()
                if user == username and passwd == password:
                    res = func(*args,**kwargs)
                    print("---after authentication")
                    return res
                else:
                    exit("\033[31;1mInvalid username or password\033[0m")
            elif auth_type == "ldap":
                print('搞毛線ldap,不會......')

        return wrapper
    return outer_wrapper

def index():
    print("welcome to index page")
@auth(auth_type="local")    #home = wrapper()
def home():
    print("welcome to home page")
    return "from home"
@auth(auth_type="ldap")
def bbs():
    print("welcome to bbs page")

index()
print(home())#wrapper()
bbs()
View Code

 

http://www.cnblogs.com/suoning/p/5499812.html

相關文章
相關標籤/搜索