1.18 映射名稱到序列元素

2018-02-24 15:26 更新

問(wèn)題

你有一段通過(guò)下標(biāo)訪問(wèn)列表或者元組中元素的代碼,但是這樣有時(shí)候會(huì)使得你的代碼難以閱讀,于是你想通過(guò)名稱來(lái)訪問(wèn)元素。

解決方案

collections.namedtuple() 函數(shù)通過(guò)使用一個(gè)普通的元組對(duì)象來(lái)幫你解決這個(gè)問(wèn)題。這個(gè)函數(shù)實(shí)際上是一個(gè)返回Python中標(biāo)準(zhǔn)元組類型子類的一個(gè)工廠方法。你需要傳遞一個(gè)類型名和你需要的字段給它,然后它就會(huì)返回一個(gè)類,你可以初始化這個(gè)類,為你定義的字段傳遞值等。代碼示例:

>>> from collections import namedtuple
>>> Subscriber = namedtuple('Subscriber', ['addr', 'joined'])
>>> sub = Subscriber('jonesy@example.com', '2012-10-19')
>>> sub
Subscriber(addr='jonesy@example.com', joined='2012-10-19')
>>> sub.addr
'jonesy@example.com'
>>> sub.joined
'2012-10-19'
>>>

盡管namedtuple的實(shí)例看起來(lái)像一個(gè)普通的類實(shí)例,但是它跟元組類型是可交換的,支持所有的普通元組操作,比如索引和解壓。比如:

>>> len(sub)
2
>>> addr, joined = sub
>>> addr
'jonesy@example.com'
>>> joined
'2012-10-19'
>>>

命名元組的一個(gè)主要用途是將你的代碼從下標(biāo)操作中解脫出來(lái)。因此,如果你從數(shù)據(jù)庫(kù)調(diào)用中返回了一個(gè)很大的元組列表,通過(guò)下標(biāo)去操作其中的元素,當(dāng)你在表中添加了新的列的時(shí)候你的代碼可能就會(huì)出錯(cuò)了。但是如果你使用了命名元組,那么就不會(huì)有這樣的顧慮。

為了說(shuō)明清楚,下面是使用普通元組的代碼:

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

下標(biāo)操作通常會(huì)讓代碼表意不清晰,并且非常依賴記錄的結(jié)構(gòu)。下面是使用命名元組的版本:

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

討論

命名元組另一個(gè)用途就是作為字典的替代,因?yàn)樽值浯鎯?chǔ)需要更多的內(nèi)存空間。如果你需要構(gòu)建一個(gè)非常大的包含字典的數(shù)據(jù)結(jié)構(gòu),那么使用命名元組會(huì)更加高效。但是需要注意的是,不像字典那樣,一個(gè)命名元組是不可更改的。比如:

>>> 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
>>>

如果你真的需要改變?nèi)缓蟮膶傩裕敲纯梢允褂妹M實(shí)例的 _replace() 方法, 它會(huì)創(chuàng)建一個(gè)全新的命名元組并將對(duì)應(yīng)的字段用新的值取代。比如: >>> s = s._replace(shares=75)

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

_replace() 方法還有一個(gè)很有用的特性就是當(dāng)你的命名元組擁有可選或者缺失字段時(shí)候,它是一個(gè)非常方便的填充數(shù)據(jù)的方法。你可以先創(chuàng)建一個(gè)包含缺省值的原型元組,然后使用 _replace() 方法創(chuàng)建新的值被更新過(guò)的實(shí)例。比如:

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)
>>>

最后要說(shuō)的是,如果你的目標(biāo)是定義一個(gè)需要更新很多實(shí)例屬性的高效數(shù)據(jù)結(jié)構(gòu),那么命名元組并不是你的最佳選擇。這時(shí)候你應(yīng)該考慮定義一個(gè)包含 __slots__ 方法的類(參考8.4小節(jié))。

以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)