python3學習筆記4---引用http://python3-cookbook.readthedocs.io/zh_CN/latest/

来源:https://www.cnblogs.com/lijinxi/archive/2018/03/01/8487818.html
-Advertisement-
Play Games

2018-03-01數據結構與演算法(4) 1.16過濾序列元素 最簡單的過濾序列元素的方法就是使用列表推導。比如: 用列表推導的一個潛在缺陷就是如果輸入非常大的時候會產生一個非常大的結果集,占用大量記憶體。 如果你對記憶體比較敏感, 那麼你可以使用生成器表達式迭代產生過濾的元素。比如: 有時候,過濾規則 ...


2018-03-01數據結構與演算法(4)

1.16過濾序列元素

最簡單的過濾序列元素的方法就是使用列表推導。比如:

>>> mylist = [1, 4, -5, 10, -7, 2, 3, -1]
>>> [n for n in mylist if n > 0]
[1, 4, 10, 2, 3]
>>> [n for n in mylist if n < 0]
[-5, -7, -1]
>>>

  用列表推導的一個潛在缺陷就是如果輸入非常大的時候會產生一個非常大的結果集,占用大量記憶體。 如果你對記憶體比較敏感,

那麼你可以使用生成器表達式迭代產生過濾的元素。比如:

>>> pos = (n for n in mylist if n > 0)
>>> pos
<generator object <genexpr> at 0x1006a0eb0>
>>> for x in pos:
... print(x)
...
1
4
10
2
3
>>>

 有時候,過濾規則比較複雜,不能簡單的在列表推導或者生成器表達式中表達出來。 比如,假設過濾的時候需要處理一些異常或者其他複雜情況。這時候你可以將過濾代碼放到一個函數中, 然後使用內建的 filter() 函數。示例如下:

values = ['1', '2', '-3', '-', '4', 'N/A', '5']
def is_int(val):
    try:
        x = int(val)
        return True
    except ValueError:
        return False
ivals = list(filter(is_int, values))
print(ivals)
# Outputs ['1', '2', '-3', '4', '5']

 列表推導和生成器表達式通常情況下是過濾數據最簡單的方式。 其實它們還能在過濾的時候轉換數據。比如:

>>> mylist = [1, 4, -5, 10, -7, 2, 3, -1]
>>> import math
>>> [math.sqrt(n) for n in mylist if n > 0]
[1.0, 2.0, 3.1622776601683795, 1.4142135623730951, 1.7320508075688772]
>>>

 過濾操作的一個變種就是將不符合條件的值用新的值代替,而不是丟棄它們。 比如,在一列數據中你可能不僅想找到正數,而且還想將不是正數的數替換成指定的數。 通過將過濾條件放到條件表達式中去,可以很容易的解決這個問題,就像這樣:

>>> clip_neg = [n if n > 0 else 0 for n in mylist]
>>> clip_neg
[1, 4, 0, 10, 0, 2, 3, 0]
>>> clip_pos = [n if n < 0 else 0 for n in mylist]
>>> clip_pos
[0, 0, -5, 0, -7, 0, 0, -1]
>>>

  另外一個值得關註的過濾工具就是 itertools.compress() , 它以一個 iterable 對象和一個相對應的 Boolean 選擇器序列作為輸入參數。 然後輸出 iterable 對象中對應選擇器為 True 的元素。 當你需要用另外一個相關聯的序列來過濾某個序列的時候,這個函數是非常有用的。 比如,假如現在你有下麵兩列數據:

 

addresses = [
    '5412 N CLARK',
    '5148 N CLARK',
    '5800 E 58TH',
    '2122 N CLARK',
    '5645 N RAVENSWOOD',
    '1060 W ADDISON',
    '4801 N BROADWAY',
    '1039 W GRANVILLE',
]
counts = [ 0, 3, 10, 4, 1, 7, 6, 1]

  現在你想將那些對應 count 值大於5的地址全部輸出,那麼你可以這樣做:

>>> from itertools import compress
>>> more5 = [n > 5 for n in counts]
>>> more5
[False, False, True, False, False, True, True, False]
>>> list(compress(addresses, more5))
['5800 E 58TH', '1060 W ADDISON', '4801 N BROADWAY']
>>>

  

這裡的關鍵點在於先創建一個 Boolean 序列,指示哪些元素符合條件。 然後 compress() 函數根據這個序列去選擇輸出對應位置為 True 的元素。

filter() 函數類似, compress() 也是返回的一個迭代器。因此,如果你需要得到一個列表, 那麼你需要使用 list() 來將結果轉換為列表類型。

1.17從字典中提取子集 

 

prices = {
    'ACME': 45.23,
    'AAPL': 612.78,
    'IBM': 205.55,
    'HPQ': 37.20,
    'FB': 10.75
}
# Make a dictionary of all prices over 200
p1 = {key: value for key, value in prices.items() if value > 200}
# Make a dictionary of tech stocks
tech_names = {'AAPL', 'IBM', 'HPQ', 'MSFT'}
p2 = {key: value for key, value in prices.items() if key in tech_names}

 大多數情況下字典推導能做到的,通過創建一個元組序列然後把它傳給 dict() 函數也能實現。比如: 

p1 = dict((key, value) for key, value in prices.items() if value > 200)

 但是,字典推導方式表意更清晰,並且實際上也會運行的更快些 (在這個例子中,實際測試幾乎比 dcit() 函數方式快整整一倍)。

 有時候完成同一件事會有多種方式。比如,第二個例子程式也可以像這樣重寫:

 

# Make a dictionary of tech stocks
tech_names = { 'AAPL', 'IBM', 'HPQ', 'MSFT' }
p2 = { key:prices[key] for key in prices.keys() & tech_names }

 但是,運行時間測試結果顯示這種方案大概比第一種方案慢 1.6 倍。 如果對程式運行性能要求比較高的話,需要花點時間去做計時測試。 

 1.18映射名稱到序列元素

 collections.namedtuple() 函數通過使用一個普通的元組對象來幫你解決這個問題。 這個函數實際上是一個返回 Python 中標準元組類型子類的一個工廠方法。 你需要傳遞一個類型名和你需要的欄位給它,然後它就會返回一個類,你可以初始化這個類,為你定義的欄位傳遞值等。 代碼示例:

>>> from collections import namedtuple
>>> Subscriber = namedtuple('Subscriber', ['addr', 'joined'])
>>> sub = Subscriber('[email protected]', '2012-10-19')
>>> sub
Subscriber(addr='[email protected]', joined='2012-10-19')
>>> sub.addr
'[email protected]'
>>> sub.joined
'2012-10-19'
>>>

 儘管 namedtuple 的實例看起來像一個普通的類實例,但是它跟元組類型是可交換的,支持所有的普通元組操作,比如索引和解壓。 比如:

>>> len(sub)
2
>>> addr, joined = sub
>>> addr
'[email protected]'
>>> joined
'2012-10-19'
>>>

 

命名元組的一個主要用途是將你的代碼從下標操作中解脫出來。 因此,如果你從資料庫調用中返回了一個很大的元組列表,通過下標去操作其中的元素, 當你在表中添加了新的列的時候你的代碼可能就會出錯了。但是如果你使用了命名元組,那麼就不會有這樣的顧慮。

為了說明清楚,下麵是使用普通元組的代碼:

def compute_cost(records):
    total = 0.0
    for rec in records:
        total += rec[1] * rec[2]
    return total

下標操作通常會讓代碼表意不清晰,並且非常依賴記錄的結構。 下麵是使用命名元組的版本:

from collections import namedtuple

Stock = namedtuple('Stock', ['name', 'shares', 'price'])
def compute_cost(records):
    total = 0.0
    for rec in records:
        s = Stock(*rec)
        total += s.shares * s.price
    return total

 命名元組另一個用途就是作為字典的替代,因為字典存儲需要更多的記憶體空間。 如果你需要構建一個非常大的包含字典的數據結構,那麼使用命名元組會更加高效。 但是需要註意的是,不像字典那樣,一個命名元組是不可更改的。比如:

>>> s = Stock('ACME', 100, 123.45)
>>> s
Stock(name='ACME', shares=100, price=123.45)
>>> s.shares = 75
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: can't set attribute
>>>

 如果你真的需要改變屬性的值,那麼可以使用命名元組實例的 _replace() 方法, 它會創建一個全新的命名元組並將對應的欄位用新的值取代。比如:

>>> s = s._replace(shares=75)
>>> s
Stock(name='ACME', shares=75, price=123.45)
>>>

 _replace() 方法還有一個很有用的特性就是當你的命名元組擁有可選或者缺失欄位時候, 它是一個非常方便的填充數據的方法。 你可以先創建一個包含預設值的原型元組,然後使用 _replace() 方法創建新的值被更新過的實例。比如: 

 

from collections import namedtuple

Stock = namedtuple('Stock', ['name', 'shares', 'price', 'date', 'time'])

# Create a prototype instance
stock_prototype = Stock('', 0, 0.0, None, None)

# Function to convert a dictionary to a Stock
def dict_to_stock(s):
    return stock_prototype._replace(**s)

 下麵是它的使用方法:

>>> a = {'name': 'ACME', 'shares': 100, 'price': 123.45}
>>> dict_to_stock(a)
Stock(name='ACME', shares=100, price=123.45, date=None, time=None)
>>> b = {'name': 'ACME', 'shares': 100, 'price': 123.45, 'date': '12/17/2012'}
>>> dict_to_stock(b)
Stock(name='ACME', shares=100, price=123.45, date='12/17/2012', time=None)
>>>

 最後要說的是,如果你的目標是定義一個需要更新很多實例屬性的高效數據結構,那麼命名元組並不是你的最佳選擇。 這時候你應該考慮定義一個包含 __slots__ 方法的類 

1.19轉換並同時計算數據

一個非常優雅的方式去結合數據計算與轉換就是使用一個生成器表達式參數。 比如,如果你想計算平方和,可以像下麵這樣做:

nums = [1, 2, 3, 4, 5]
s = sum(x * x for x in nums)

 下麵是更多的例子: 

 

# Determine if any .py files exist in a directory
import os
files = os.listdir('dirname')
if any(name.endswith('.py') for name in files):
    print('There be python!')
else:
    print('Sorry, no python.')
# Output a tuple as CSV
s = ('ACME', 50, 123.45)
print(','.join(str(x) for x in s))
# Data reduction across fields of a data structure
portfolio = [
    {'name':'GOOG', 'shares': 50},
    {'name':'YHOO', 'shares': 75},
    {'name':'AOL', 'shares': 20},
    {'name':'SCOX', 'shares': 65}
]
min_shares = min(s['shares'] for s in portfolio)

  對於小型列表可能沒什麼關係,但是如果元素數量非常大的時候, 它會創建一個巨大的僅僅被使用一次就被丟棄的臨時數據結構。而生成器方案會以迭代的方式轉換數據,因此更省記憶體。

  在使用一些聚集函數比如 min()max() 的時候你可能更加傾向於使用生成器版本, 它們接受的一個 key 關鍵字參數或許對你很有幫助。 比如,在上面的證券例子中,你可能會考慮下麵的實現版本:

# Original: Returns 20
min_shares = min(s['shares'] for s in portfolio)
# Alternative: Returns {'name': 'AOL', 'shares': 20}
min_shares = min(portfolio, key=lambda s: s['shares'])

1.20合併多個字典或映射  

假如你有如下兩個字典:

a = {'x': 1, 'z': 3 }
b = {'y': 2, 'z': 4 }

現在假設你必須在兩個字典中執行查找操作(比如先從 a 中找,如果找不到再在 b 中找)。 一個非常簡單的解決方案就是使用 collections 模塊中的 ChainMap 類。比如:

from collections import ChainMap
c = ChainMap(a,b)
print(c['x']) # Outputs 1 (from a)
print(c['y']) # Outputs 2 (from b)
print(c['z']) # Outputs 3 (from a)

 一個 ChainMap 接受多個字典並將它們在邏輯上變為一個字典。 然後,這些字典並不是真的合併在一起了, ChainMap 類只是在內部創建了一個容納這些字典的列表 並重新定義了一些常見的字典操作來遍歷這個列表。大部分字典操作都是可以正常使用的,比如:

>>> len(c)
3
>>> list(c.keys())
['x', 'y', 'z']
>>> list(c.values())
[1, 2, 3]
>>>

  

如果出現重覆鍵,那麼第一次出現的映射值會被返回。 因此,例子程式中的 c['z'] 總是會返回字典 a 中對應的值,而不是 b 中對應的值。

對於字典的更新或刪除操作總是影響的是列表中第一個字典。比如:

>>> c['z'] = 10
>>> c['w'] = 40
>>> del c['x']
>>> a
{'w': 40, 'z': 10}
>>> del c['y']
Traceback (most recent call last):
...
KeyError: "Key not found in the first mapping: 'y'"
>>>

 ChainMap 對於編程語言中的作用範圍變數(比如 globals , locals 等)是非常有用的。 事實上,有一些方法可以使它變得簡單: 

>>> values = ChainMap()
>>> values['x'] = 1
>>> # Add a new mapping
>>> values = values.new_child()
>>> values['x'] = 2
>>> # Add a new mapping
>>> values = values.new_child()
>>> values['x'] = 3
>>> values
ChainMap({'x': 3}, {'x': 2}, {'x': 1})
>>> values['x']
3
>>> # Discard last mapping
>>> values = values.parents
>>> values['x']
2
>>> # Discard last mapping
>>> values = values.parents
>>> values['x']
1
>>> values
ChainMap({'x': 1})
>>>

 為 ChainMap 的替代,你可能會考慮使用 update() 方法將兩個字典合併。比如:

>>> a = {'x': 1, 'z': 3 }
>>> b = {'y': 2, 'z': 4 }
>>> merged = dict(b)
>>> merged.update(a)
>>> merged['x']
1
>>> merged['y']
2
>>> merged['z']
3
>>>

 這樣也能行得通,但是它需要你創建一個完全不同的字典對象(或者是破壞現有字典結構)。 同時,如果原字典做了更新,這種改變不會反應到新的合併字典中去。比如: 

 ChainMap 使用原來的字典,它自己不創建新的字典。所以它並不會產生上面所說的結果,比如:

>>> a = {'x': 1, 'z': 3 }
>>> b = {'y': 2, 'z': 4 }
>>> merged = ChainMap(a, b)
>>> merged['x']
1
>>> a['x'] = 42
>>> merged['x'] # Notice change to merged dicts
42
>>>

  

 

  

 

 

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 一款有著強大的文檔轉換功能的工具,無論何時何地都會是現代辦公環境極為需要的。在本篇文章中,將繼續介紹關於Word文檔的轉換功能(Word轉XPS/SVG/EMF/EPUB/TIFF)希望方法中的代碼能為各位開發者們提供一定的參考價值。 PS:更多Word轉換功能可以參閱這兩篇文章 Word轉HTML ...
  • 這是一道面試題,首先finally{}裡面的code肯定是會執行的,至於在return前還是後, 看答案說的是在return後執行,我覺得不對,百度了一下,有說return前的,有說return後的,還有return中間執行的。遂做了一個小測試如下: 測試結果如下: 所以我覺得finally{}裡面 ...
  • 在.Net 4.0以後的版本,提供了一個類,該類在 System.Diagnostics命名空間下,使用該類就可以計算出執行結果相同的兩端代碼的效率,在代碼優化上是很實用的。 泛型效率是高是低呢??我們來測試下,代碼如下: 經過上述執行,我們可以把我們程式框架裡面的幫助類都改成泛型的。 ...
  • 一、問題描述: 資料庫中欄位 nvarchar類型 存放數據如下: '3.3×10' 二、解決方案: --測試用例CREATE TABLE #temp(NAME NVARCHAR(20) null) INSERT INTO #temp select FecalColiform from Water ...
  • 原文: [Announcing .NET Core 2.1 Preview 1](https://blogs.msdn.microsoft.com/dotnet/2018/02/27/announcing-net-core-2-1-preview-1/) 今天,我們宣佈發佈 .NET Core 2... ...
  • 提到非同步,那麼與之對應的是什麼呢?同步。那麼C#的非同步和同步是如何工作的呢? 首先,我們先來看看慄子: 新建一個控制台應用程式,在Program文件中添加如下代碼: 這個慄子很簡單,定義了兩個方法:TaskOne,TaskTwo。在裡面每隔一秒輸出一次當前時間,和當前線程。TaskOne迴圈5次和T ...
  • 以下是我在項目開發中所做的關於Excel導出功能,不足之處還望大家指正,相互學習指正 ...
  • 上篇博客也說了下C#中通過XML導出Excel,這些文件操作都挺有用的,下麵是文件的下載,之前做項目都是把它寫的空間日誌中,以後有時間了把它們都弄出來 先把有問題的代碼貼出來吧 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...