優雅的python

在知乎上看到的問題——python有哪些優雅的代碼實現。html

下面的代碼大概也算不上優雅。python

一下代碼在python3中實現微信

更多內容可見:http://book.pythontips.com/en/latest/args_and_kwargs.htmlapp

lambda函數的使用

lambda,又稱匿名函數。當咱們在傳入函數時,有些時候,不須要顯式地定義函數,直接傳入匿名函數更方便。函數

好比命名一個普通的函數:spa

def f(x):
    return x * x

在這裏,f爲函數名,x是函數的參數,x*x則是函數的返回結果。code

咱們能夠換成lambda的形式則是:htm

>>> lambda x : x*x
<function <lambda> at 0x7fa2d1298048>
>>> f = lambda x : x*x
>>> f(3)
9

 lambda函數有一個限制就是函數中只能有一個表達式(事例中的x*x),該表達式的結果便是返回值。固然這個表達式能夠用下面的一些技巧寫的更「優雅」一些。對象

其中lambda函數返回是一個對象,其實在python中,絕大部分的都是對象,函數也是對象。因此咱們能將lambda函數賦給其它對象(事例中的f)。可是不建議這麼作。通常使用lambda表達式時要注意:blog

1.邏輯簡單,切忌在一個lambda表達式中作出很複雜的邏輯,這麼作可能感受逼格很高可是代碼的可讀性會變得很是差。

2.一次性使用,就像上面所說的不建議使用f = lambda  x:....的形式

map,reduce,filter函數的使用

map()函數接收兩個參數,一個是函數,一個是Iterablemap將傳入的函數依次做用到序列的每一個元素,並把結果做爲新的Iterator返回。

好比咱們有一個函數f(x)=x2,要把這個函數做用在一個list [1, 2, 3, 4, 5, 6, 7, 8, 9]上,就能夠用map()實現以下:

>>> def f(x):
...     return x * x
...
>>> r = map(f, [1, 2, 3, 4, 5, 6, 7, 8, 9])
>>> list(r)
[1, 4, 9, 16, 25, 36, 49, 64, 81]

 其中注意,傳進map()的第一個參數是 f 而不是f(),其中f表示的是f函數對象自己而f()則是對函數f的調用。

map()做爲高階函數,事實上它把運算規則抽象了,所以,咱們不但能夠計算簡單的f(x)=x2,還能夠計算任意複雜的函數,好比,把這個list全部數字轉爲字符串:

>>> list(map(str, [1, 2, 3, 4, 5, 6, 7, 8, 9]))
['1', '2', '3', '4', '5', '6', '7', '8', '9']

 固然,map()中還能夠傳入lambda表達式:

>>> list(map(lambda x: x*x,range(10)))
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

 或者再結合一下:

>>> list(map(lambda x: str(x*x),range(10)))
['0', '1', '4', '9', '16', '25', '36', '49', '64', '81']

 再看reduce的用法。reduce把一個函數做用在一個序列[x1, x2, x3, ...]上,這個函數必須接收兩個參數,reduce把結果繼續和序列的下一個元素作累積計算,其效果就是:

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

 

比方說對一個序列求和,就能夠用reduce實現:

>>> from functools import reduce
>>> reduce(lambda x,y:x+y,[1,2,3,4])
10

 

Python內建的filter()函數用於過濾序列。

map()相似,filter()也接收一個函數和一個序列。和map()不一樣的是,filter()把傳入的函數依次做用於每一個元素,而後根據返回值是True仍是False決定保留仍是丟棄該元素。

例如返回一個list中的奇數:

>>> list(filter(lambda x:x % 2 == 1,range(10)))
[1, 3, 5, 7, 9]

 

列表推導

列表推導,又稱列表生成式,即List Comprehensions,是Python內置的很是簡單卻強大的能夠用來建立list的生成式。

舉個例子,要生成list [0,1, 2, 3, 4, 5, 6, 7, 8, 9]能夠用list(range(10))

>>> list(range(10))
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

 在python2中有點區別,python2中的range()直接生產列表而python3中生產的是一個range對象,須要經過list或者[]來生成。

>>> [x for x in range(10)]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

 或者進階一點點:

>>> [x*x for x in range(10)]
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
>>> [str(x) for x in range(10)]
['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']
>>> L = ['Hello', 'World', 'IBM', 'Apple'] >>> [s.lower() for s in L] ['hello', 'world', 'ibm', 'apple']

感受它的寫法有點想lambda表達式。

而後其中也能夠多幾層的嵌套:

>>> [m + n for m in 'ABC' for n in 'XYZ']
['AX', 'AY', 'AZ', 'BX', 'BY', 'BZ', 'CX', 'CY', 'CZ']

 三層和三層以上的循環就不多用到了。

 

yield和generator生成器

簡單地講,yield 的做用就是把一個函數變成一個 generator。

例如使用yield生成裴波那契數列:

 def fab(max): 
    n, a, b = 0, 0, 1 
    while n < max: 
        yield b 
        # print b 
        a, b = b, a + b 
        n = n + 1 

 

 >>> for n in fab(5): 
 ...     print n 
 ... 
 1 
 1 
 2 
 3 
 5

使用yield的好處在於,它返回的是一個generator生成器。相似於python3中的range()和python2中的xrange()。帶有 yield 的函數再也不是一個普通函數,Python 解釋器會將其視爲一個 generator,調用 fab(5) 不會執行 fab 函數,而是返回一個 iterable 對象!在 for 循環執行時,每次循環都會執行 fab 函數內部的代碼,執行到 yield b 時,fab 函數就返回一個迭代值,下次迭代時,代碼從 yield b 的下一條語句繼續執行,而函數的本地變量看起來和上次中斷執行前是徹底同樣的,因而函數繼續執行,直到再次遇到 yield。

由於返回的是一個生成器,因此可使用next()方法進行訪問:

>>> f = fab(5)
>>> next(f)
1
>>> next(f)
1
>>> next(f)
2
>>> next(f)
3
>>> next(f)
5

 generator生成器,前面咱們看了列表推導,使用[]進行生成,其中把[]換成(),就建立了一個generator:

>>> L = [x * x for x in range(10)]
>>> L
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
>>> g = (x * x for x in range(10))
>>> g
<generator object <genexpr> at 0x7fd2264607d8>

 L是一個list,而g是一個generator。其中generator是可迭代的。

 

裝飾器

裝飾器(Decorator),當咱們但願爲函數增長功能,可是卻不想修改原函數又或者沒有權限修改原函數的時候,就須要用到裝飾器了。

好比咱們有一個函數:

def func():
    print("I have a dream!")
func()

I have a dream!

 是的,我有一個夢想!如今咱們想要知道我何時有一個夢想,就是咱們須要在執行函數的時候打印時間。那麼:

'''定義一個裝飾器'''
def log_time(func):
    def wrapper(*args, **kw):
        print("run %s() and time is :" % func.__name__+str(datetime.datetime.now()))
        return func(*args,**kw)
    return wrapper

@log_time
def func():
    print("I have a dream!")

func()

 輸出:

run func() and time is :2016-10-10 14:26:08.296495
I have a dream!

 本質上,decorator就是一個返回函數的高階函數。其中,咱們給log_tim()傳入一個參數,這個參數是一個函數對象,而且返回一個函數對象。而後在其中定義了wrapper(),這兩個參數並無意義,只是爲了說明這裏面能夠傳入任意類型的參數。

而後用@語法將其放在函數定義處。其至關於:

func = log_time(func)

 因爲log_time()是一個decorator,返回一個函數,因此,原來的func()函數仍然存在,只是如今同名的func變量指向了新的函數,因而調用func()將執行新函數,即在log_time()函數中返回的wrapper()函數。

在使用裝飾器時請注意:

用decorator修飾一個函數獲得另外一個函數時,原來的那個函數依然是邏輯中心,而decorator所增長的只是相對外圍的功能,不能那個什麼賓那個什麼主。

即便去掉裝飾器,整個函數的邏輯仍需完整、清晰。

歡迎多來訪問博客:http://liqiongyu.com/blog

微信公衆號:

相關文章
相關標籤/搜索