美文网首页
collection.namedtuple用法以及所谓的Pyth

collection.namedtuple用法以及所谓的Pyth

作者: realnickman | 来源:发表于2019-04-08 04:56 被阅读0次

Namedtuple,顾名思义就是为了方便使得tuple每一项都有实际的意义,如果你想建立一个简单的不想改变的且没有method的类(尤其是数据库读出来的数据),那么使用namedtuple就会特别方便。
创建就用collections.namedtuple(typename, field_names, *, rename=False, defaults=None, module=None),一个返回class的工厂方法。
一些实用代码举例如下:

from collections import namedtuple

# nametuple: Factory Function for Tuples with Named Fields
Person = namedtuple("Person", ["name","age", "sex"])
p1 = Person("Jason", 30, sex = "Man")
p2 = Person("Merry", 60, sex = "Woman")
print("person's information:", p1.name, p1.age, p1.sex)
print(p2)

输出如下:

person's information: Jason 30 Man
Person(name='Merry', age=60, sex='Woman')

三个自带方法分别是_asdict(),_replace() 和 _make

# unpacking like a regular tuple
name, age, sex = p1
print("unpacking:", name, age, sex)

# New an OrderedDict
mydict = p1._asdict()
print("OrderDict:", mydict.get("name"), mydict.get("age"), mydict.get("sex"))

# Return a new instance of the named tuple
new_person = p1._replace(name = "Kitty", age = 1, sex = "Woman")
print(new_person)

# make new instances with existing iterables
p3 = Person._make(["Kobe",38, "Man"])
print("_make an instance:",p3)

输出:

unpacking: Jason 30 Man
OrderDict: Jason 30 Man
Person(name='Kitty', age=1, sex='Woman')
_make an instance: Person(name='Kobe', age=38, sex='Man')

几种常用用法

1. 把dict转为namedtuple

mydict2 = {"name": "X", "age": 30, "sex": "Woman"}
print("Dict to namedtuple:", Person(**mydict2))

输出:

Dict to namedtuple: Person(name='X', age=30, sex='Woman')

2. 获取csv或者sqlite3的数据文件中的记录,使用_make()以及map()方法,然后iterate就可以了

print("\nRead csv file 'users.csv':")
import csv
Name = namedtuple("Name", ["first","last"])
for nm in map(Name._make, csv.reader(open("users.csv"))):
    print(nm.first,nm.last)

print("\nConnect sqlite3  file 'my_friends.db':")
import sqlite3
conn = sqlite3.connect('my_friends.db')
cursor = conn.cursor()
cursor.execute('select * from friends where closeness > 700 order by closeness')
Friend = namedtuple("Friend", ["first",'last','closeness'])
for frd in map(Friend._make, cursor.fetchall()):
    print(frd.first,frd.last,frd.closeness)

CSV输出:

Read csv file 'users.csv':
First Name Last Name
Grace Hopper
Alan Turing

SQLITE3输出:

Connect sqlite3  file 'my_friends.db':
niubi Gong 777
shenye Gong 888
Yeye Gong 999
zong Gong 999

后面还看到了一个在Fluent Python这本书里面很好的一个例子,不仅仅讲了namedtuple 在创造“小类”方面的精妙用法,还顺便给出了重载dunder methods的优势。比如我们需要创建一个类表示一堆牌,那么其中每一张就是单独的一个card, 有两个属性,大小和点数。那么这个card就非常适合用namedtuple.

Card = namedtuple("Card",['rank',"suit"])
class ClassicDeck():
    ranks = [str(n) for n in range(2,11)] + list("JQKA")
    suits = "spades diamonds clubs heart".split()

    def __init__(self):
        self._cards = [Card(rank,suit) for rank in self.ranks for suit in self.suits]

    def __len__(self):
        return len(self._cards)

    def __getitem__(self, pos): 
        return self._cards[pos]

deck = ClassicDeck()
print(deck[2])
print(len(deck))
print(deck[2:6])
from random import choice
print("random:",choice(deck))

# print out last 8 cards
i = 8
for card in reversed(deck):
    if i > 0:
        print(card)
        i = i-1
    else:
        break 

其中精妙之处在于,"__getitem__"使得使用“collections[index]”获取元素成为可能,不仅如此,还让deck完全成为了一个iterable,可以执行slicing操作或者被iterate。 那么如果我要找一个随机的牌,按照传统用java写OOP的想法,本来是想在类里面写一个方法去产生随机牌,但是现在不需要了,直接用python库里面的函数random.choice()去做这个操作。 如果需要知道这堆牌的数量,原来还需要在类里面去写函数去执行,然后客户拿到类之后还需要记住是用deck.length() 或者deck.size() ,但是你直接重载dunder method __len__后,使用的时候直接拿len()就好了。这其实是一种非常pythonic的思想。

相关文章

网友评论

      本文标题:collection.namedtuple用法以及所谓的Pyth

      本文链接:https://www.haomeiwen.com/subject/tqsyiqtx.html