namedtuplepython
1. 說說 python 的具名元組
Python 提供的元組與列表類似,不同之處在於元組的元素不能修改。雖然有時候很方便,但因為不能為元組內部的數據進行命名,所以沒有那麼直觀。
Python 引入了 collections.namedtuple 這個工廠函數,用來構造一個帶欄位名的元組。
(1)聲明與實例化
我們一般這樣來構造具名元組:
下面是聲明一個具名元組及其實例化方法的示例:
運行結果:
這里通過 collections.namedtuple 創建了一個具名元組,用來表示一張撲克牌。rank 表示撲克牌點數,suit 表示花色。可以通過欄位名或者位置來實例化一個具名元組。這里的 select_card 表示抽到一張黑桃 10。
(2)特有屬性與方法
具名元組還擁有以下這些特有的屬性與方法。
運行結果:
另外,通過 . 語法還可以獲取具名元組中所對應的屬性值:
運行結果:
2. python 為什麼要使用元組
有的常數要求不變,放在元組裡面保險呀。再就是有時間元組。
3. Python 數據模型
Python 風格的關鍵完全體現在 Python 的數據模型上,數據模型所描述的 API ,為使用最地道的語言特性來構建開發者自己的對象提供了工具。
當 Python 解析器遇到特殊句法時,會使用特殊方法去激活一些基本的對象操作。特殊方法以雙下劃線開頭,以雙下劃線結尾。如: obj[key] 的背後就是 __getitem__ 方法。魔術方法是特殊方法的昵稱,特殊方法也叫雙下方法。
使用 __getitem__ 和 __len__ 創建一摞有序的紙牌:
上面的例子,使用 collections.namedtuple 構建了一個簡單的類來表示一張紙牌, namedtuple 用以構建只有少數屬性但沒有方法的類。
我們自定義的 FrenchDeck 類可以像任何 python 標准集合類型一樣使用 len() 函數,查看一疊牌有多少張:
也可以像列表一樣,使用位置索引, d[i] 將調用 __getitem__ 方法:
也可以使用標准庫模塊提供的 random.choice 方法,從序列中隨機選取一個元素。下面,我們如隨機取出一張紙牌:
現在我們已經體會到通過 python 特殊方法,來使用 Python 數據模型的 2 個好處:
因為 __getitem__ 方法把 [] 操作交給了 self.cards 列表,所以我們的 FrenchDeck 實例自動支持切片:
僅僅實現了 __getitem__ 方法,這一摞牌即變得可迭代:
運行結果:
也可以直接調用內置的 reversed 函數,反向迭代 FrenchDeck 實例:
運行結果:
迭代通常是隱式的,比如一個集合類型沒有實現 __contains__ 方法,那麼 in 運算符就會按順序做一次迭代搜索。
因此, in 運算符可以用在我們的 FrenchDeck 實例上,因為它是可迭代的:
FrenchDeck 還可以使用 Python 標准庫中的 sorted 函數,實現排序:
首先定義一個排序依據的函數:
優先按 rank 的大小排序,rank 相同時則比較 suit 的值:
運行結果:
優先按 suit 的大小排序,suit 相同時則比較 rank 的值:
運行結果:
按照目前的設計,FrenchDeck 還不支持洗牌,因為它是不可變的:
shuffle 函數要調換集合中元素的位置,而 FrenchDeck 只實現了不可變的序列協議,可變的序列還必須提供 __setitem__ 方法:
洗牌:
沒有任何的返回值,可見 random.shuffle 就地修改了可變序列 d 。為便於觀察結果,我們定義輸入的輸出函數:
運行結果:
每次洗牌,都是一個隨機的序列:
首先明確一點,特殊方法的存在是為了被 Python 解析器調用的,例如:我們不會使用 obj.__len__() 這種寫法,而是 len(obj) 。在執行 len(obj) 時,如果 obj 是一個自定義類的對象,那麼 Python 會自己去調用我們實現的 __len__ 方法。
對於 Python 內置的數據類型,比如列表、字元串、位元組序列等,那麼 CPython 會抄個近路, __len__ 實際上會返回 PyVarObject 里的 ob_size 屬性,這是因為直接讀取屬性比調用一個方法要快得多。
很多時候,特殊方法的調用是隱式的,比如 for i in x: 這個語句其實是調用 iter(x) ,而這個函數的背後是 x.__iter__() 方法。
通過內置函數如來使用特殊方法是最好的選擇。這些內置函數不僅會調用這些方法,通常還提供額外的好處,對於內置類型來說,它們的速度更快。
下面,我們通過定義一個簡單的二維向量類,再來體會一下 Python 特殊方法的美妙:
使用 Vector 類,就像使用 Python 內置的數據類型一樣簡單:
4. 命名參數可以與Python枚舉一起使用嗎
雖然不能像枚舉那樣使用命名參數,但是可以通過namedtuple混音:
from collections import namedtuple
from enum import Enum
Body = namedtuple("Body", ["mass", "radius"])
class Planet(Body, Enum):
MERCURY = Body(mass=3.303e+23, radius=2.4397e6)
VENUS = Body(mass=4.869e+24, radius=6.0518e6)
EARTH = Body(mass=5.976e+24, radius=3.3972e6)
# ... etc.
你不必寫一個__init__方法。
示例使用:
>>> Planet.MERCURY
<Planet.MERCURY: Body(mass=3.303e+23, radius=2439700.0)>
>>> Planet.EARTH.mass
5.976e+24
>>> Planet.VENUS.radius
6051800.0
5. 用python獲取電腦cpu溫度代碼
from __future__ import division
import os
from collections import namedtuple
_nt_cpu_temp = namedtuple('cputemp', 'name temp max critical')
def get_cpu_temp(fahrenheit=False):
"""Return temperatures expressed in Celsius for each physical CPU
installed on the system as a list of namedtuples as in:
>>> get_cpu_temp()
[cputemp(name='atk0110', temp=32.0, max=60.0, critical=95.0)]
"""
# http://www.mjmwired.net/kernel/Documentation/hwmon/sysfs-interface
cat = lambda file: open(file, 'r').read().strip()
base = '/sys/class/hwmon/'
ls = sorted(os.listdir(base))
assert ls, "%r is empty" % base
ret = []
for hwmon in ls:
hwmon = os.path.join(base, hwmon)
label = cat(os.path.join(hwmon, 'temp1_label'))
assert 'cpu temp' in label.lower(), label
name = cat(os.path.join(hwmon, 'name'))
temp = int(cat(os.path.join(hwmon, 'temp1_input'))) / 1000
max_ = int(cat(os.path.join(hwmon, 'temp1_max'))) / 1000
crit = int(cat(os.path.join(hwmon, 'temp1_crit'))) / 1000
digits = (temp, max_, crit)
if fahrenheit:
digits = [(x * 1.8) + 32 for x in digits]
ret.append(_nt_cpu_temp(name, *digits))
return ret
6. 怎麼用python讀取csv數據
這兩天剛好看到,Python CookBook上有說到。這里是三種讀取csv的方法。
文件格式是這樣的
Region,DATE_,RAW_ACU
zh_ch,Jan 27 2017,208172
importcsv
#withopen('data.csv')asf:
#f_csv=csv.reader(f)
#headers=next(f_csv)
#forrowinf_csv:
##print(row)
#print(row[0],row[1])
#withopen('data.csv',encoding='utf-8-sig')asf:
#f_csv=csv.reader(f)
#headers=next(f_csv)
#print(headers)
#Row=namedtuple('Row',headers)
#forrinf_csv:
#row=Row(*r)
#print(row.Region,row.DATE_)
withopen('data.csv',encoding='utf-8-sig')asf:
f_csv=csv.DictReader(f)
forrowinf_csv:
print(row['DATE_'],row)
具體可以看這個文檔。http://python3-cookbook.readthedocs.io/zh_CN/latest/c06/p01_read_write_csv_data.html。