首頁  >  文章  >  後端開發  >  Python中的高階程式設計一些小技巧總結

Python中的高階程式設計一些小技巧總結

伊谢尔伦
伊谢尔伦原創
2017-06-28 13:29:401414瀏覽

這篇文章主要介紹了介紹Python中的一些高級編程技巧,包括推導師和裝飾器等重要的進階知識點,皆為深入學習Python開發的必備基本功,需要的朋友可以參考下

 正文:

本文展示一些進階的Python設計結構和它們的使用方法。在日常工作中,你可以根據需要選擇合適的資料結構,例如對快速查找性的要求、對資料一致性的要求或是對索引的要求等,同時也可以將各種資料結構適當地結合在一起,從而產生具有邏輯性並易於理解的資料模型。 Python的資料結構從句法上來看非常直觀,並且提供了大量的可選操作。這篇指南嘗試將大部分常用的資料結構知識放在一起,並且提供對其最佳用法的探討。
推導式(Comprehensions)

如果你已經使用了很長時間的Python,那麼你至少應該聽過列表推導(list comprehensions)。這是一種將for迴圈、if表達式、賦值語句放到單一語句中的一種方法。換句話說,你能夠透過一個表達式對一個列表做映射或過濾操作。

一個清單推導式包含以下幾個部分:

  •     一個輸入序列

  •     一個表示輸入序列成員的變數

  •     一個可選的斷言表達式

  • #    將輸入序列中滿足斷言表達式的成員轉換成輸出清單成員的輸出表達式式

舉個例子,我們需要從一個輸入清單中將所有大於0的整數平方產生一個新的序列,你也許會這麼寫:

num = [1, 4, -5, 10, -7, 2, 3, -1]
filtered_and_squared = []
 
for number in num:
 if number > 0:
 filtered_and_squared.append(number ** 2)
print filtered_and_squared
 
# [1, 16, 100, 4, 9]

很簡單吧?但這就會有4行程式碼,兩層嵌套外加一個完全不必要的append操作。而如果使用filter、lambda和map函數,則能夠將程式碼大大簡化:

num = [1, 4, -5, 10, -7, 2, 3, -1]
filtered_and_squared = map(lambda x: x ** 2, filter(lambda x: x > 0, num))
print filtered_and_squared
 
# [1, 16, 100, 4, 9]

嗯,這麼一來程式碼就會在水平方向上展開。那麼是否能夠繼續簡化程式碼呢?列表推導能夠給我們答案:

num = [1, 4, -5, 10, -7, 2, 3, -1]
filtered_and_squared = [ x**2 for x in num if x > 0]
print filtered_and_squared
 
# [1, 16, 100, 4, 9]
  •    迭代器(iterator)遍歷輸入序列num的每個成員x

  • #    斷言式判斷每位成員是否大於零

  •     若成員大於零,則交給輸出表達式,平方之後成為輸出清單的成員。

清單推導式被封裝在一個清單中,所以很明顯地它能夠立即產生一個新清單。這裡只有一個type函數呼叫而沒有隱式呼叫lambda函數,列表推導式正是使用了一個常規的迭代器、一個表達式和一個if表達式來控制可選的參數。

另一方面,列表推導也可能會有一些負面效應,那就是整個列表必須一次加載於內存之中,這對上面舉的例子而言不是問題,甚至擴大若干倍之後也都不是問題。但是總是會達到極限,記憶體總會用完。

針對上面的問題,生成器(Generator)能夠很好的解決。生成器表達式不會一次將整個列表載入到記憶體之中,而是產生一個生成器物件(Generator objector),所以一次只載入一個列表元素。

生成器表達式同列表推導式有著幾乎相同的語法結構,差異在於生成器表達式是被圓括號包圍,而不是方括號:

num = [1, 4, -5, 10, -7, 2, 3, -1]
filtered_and_squared = ( x**2 for x in num if x > 0 )
print filtered_and_squared
 
# <generator object <genexpr> at 0x00583E18>
 
for item in filtered_and_squared:
 print item
 
# 1, 16, 100 4,9

這比列表推導效率稍微提高一些,讓我們再一次改造一下程式碼:

num = [1, 4, -5, 10, -7, 2, 3, -1]
 
def square_generator(optional_parameter):
 return (x ** 2 for x in num if x > optional_parameter)
 
print square_generator(0)
# <generator object <genexpr> at 0x004E6418>
 
# Option I
for k in square_generator(0):
 print k
# 1, 16, 100, 4, 9
 
# Option II
g = list(square_generator(0))
print g
# [1, 16, 100, 4, 9]

除非特殊的原因,應該經常在程式碼中使用生成器表達式。但除非是面對非常大的列表,否則是不會看出明顯差異的。

下例使用zip()函數一次處理兩個或多個列表中的元素:

alist = [&#39;a1&#39;, &#39;a2&#39;, &#39;a3&#39;]
blist = [&#39;1&#39;, &#39;2&#39;, &#39;3&#39;]
 
for a, b in zip(alist, blist):
 print a, b
 
# a1 1
# a2 2
# a3 3

再來看一個透過兩階列表推導式遍歷目錄的範例:

import os
def tree(top):
 for path, names, fnames in os.walk(top):
 for fname in fnames:
  yield os.path.join(path, fname)
 
for name in tree(&#39;C:\Users\XXX\Downloads\Test&#39;):
 print name

裝飾器(Decorators)

裝飾器為我們提供了一個增加已有函數或類別的功能的有效方法。聽起來是不是很像Java中的面向切面程式設計(Aspect-Oriented Programming)概念?兩者都很簡單,裝飾器有著更強大的功能。舉個例子,假定你希望在一個函數的入口和退出點做一些特別的操作(比如一些安全、追蹤以及鎖定等操作)就可以使用裝飾器。

裝飾器是一個包裝了另一個函數的特殊函數:主函數被調用,並且其返回值將會傳給裝飾器,接下來裝飾器將返回一個包裝了主函數的替代函數,程式的其他部分看到的將是這個包裝函數。

def timethis(func):
 &#39;&#39;&#39;
 Decorator that reports the execution time.
 &#39;&#39;&#39;
 pass
 
@timethis
def countdown(n):
 while n > 0:
 n -= 1

語法糖@標識了裝飾器。

好了,让我们回到刚才的例子。我们将用装饰器做一些更典型的操作:

import time
from functools import wraps
 
def timethis(func):
 &#39;&#39;&#39;
 Decorator that reports the execution time.
 &#39;&#39;&#39;
 @wraps(func)
 def wrapper(*args, **kwargs):
 start = time.time()
 result = func(*args, **kwargs)
 end = time.time()
 print(func.name, end-start)
 return result
 return wrapper
 
@timethis
def countdown(n):
 while n > 0:
 n -= 1
 
countdown(100000)
 
# (&#39;countdown&#39;, 0.006999969482421875)

当你写下如下代码时:
 

@timethis
def countdown(n):

意味着你分开执行了以下步骤:

def countdown(n):
...
countdown = timethis(countdown)

装饰器函数中的代码创建了一个新的函数(正如此例中的wrapper函数),它用 *args 和 **kwargs 接收任意的输入参数,并且在此函数内调用原函数并且返回其结果。你可以根据自己的需要放置任何额外的代码(例如本例中的计时操作),新创建的包装函数将作为结果返回并取代原函数。

@decorator
def function():
 print("inside function")

当编译器查看以上代码时,function()函数将会被编译,并且函数返回对象将会被传给装饰器代码,装饰器将会在做完相关操作之后用一个新的函数对象代替原函数。

装饰器代码是什么样的?大部分的例子都是将装饰器定义为函数,而我发觉将装饰器定义成类更容易理解其功能,并且这样更能发挥装饰器机制的威力。

对装饰器的类实现唯一要求是它必须能如函数一般使用,也就是说它必须是可调用的。所以,如果想这么做这个类必须实现call方法。

这样的装饰器应该用来做些什么?它可以做任何事,但通常它用在当你想在一些特殊的地方使用原函数时,但这不是必须的,例如:

class decorator(object):
 
 def init(self, f):
 print("inside decorator.init()")
 f() # Prove that function definition has completed
 
 def call(self):
 print("inside decorator.call()")
 
@decorator
def function():
 print("inside function()")
 
print("Finished decorating function()")
 
function()
 
# inside decorator.init()
# inside function()
# Finished decorating function()
# inside decorator.call()

以上是Python中的高階程式設計一些小技巧總結的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn