构造一个带字段名的元组。和普通元组消耗的内存一样多,会返回一个(k,v)组成放入列表#OrderedDict([(‘sa’, ‘7’), (‘sq’, ‘diamonds’)])#类似。在内存开支上比dict要小
collections.namedtuple(typename, field_names, *, rename=False, defaults=None, module=None) 菜鸟上的参数和源码的参数不太一样,可能是改版了
typename:元组名称,是不能为python中的关键字的
field_names: 元组中元素的名称。
必须是一个list或者是以","或者空格为分割的str 源码第一部分很清楚
rename: field_names中含有 python 的关键字或者以"_"开头也是不行的#应该是防止私有化的函数被访问以及篡改,则必须设置为 rename=True
源码会用_iskeyword()来检测
defaults: 为field_names中的字段元素赋得默认值,最后形成一个tuple,长度要短于field_names形成的list得长度
它的与field_names中的字段采用zip从tuple或者list的末尾向开头一一对应
#源码是如此
dict(reversed(list(zip(reversed(field_names),reversed(defaults)))))
module:可能是可以制定一些表单这个确实没看懂
简单示例:
Card=collections.namedtuple('Card',['rank','suit'])
Card=collections.namedtuple('Card',"rank,suit")
Card=collections.namedtuple('list',"def sq",rename=True)
Card=collections.namedtuple('list',"def _sq",rename=True)
Card=collections.namedtuple('_list',"def sq")
以下都是不行的:def关键字
Card=collections.namedtuple('list',"def sq")
Card=collections.namedtuple('_list',"def _sq")
Card=collections.namedtuple('def',"def sq",rename=True)
Card=collections.namedtuple('def',"def sq")
Card._fields:打印类的字段名
这种方法。。。酷
class_namespace = {
'__doc__': f'{typename}({arg_list})',
'__slots__': (),
'_fields': field_names,##
'_fields_defaults': field_defaults,
'__new__': __new__,
'_make': _make,
'_replace': _replace,
'__repr__': __repr__,
'_asdict': _asdict,
'__getnewargs__': __getnewargs__,
}
结果:('sp', 'sq')
Card._make():接受可迭代对象为field_names赋值,同样传入的对象长度不能长于field_names的长度
print(Card._make([1,4]))
输出:list(sp=1, sq=4)
print(Card._make([(1,4),(2,3)]))
输出:list(sp=(1, 4), sq=(2, 3))
user._asdict() :将User对象转换成字典
print(Card('7','diamonds')._asdict())
输出:OrderedDict([('sp', '7'), ('sq', 'diamonds')])
print(Card('7','diamonds')._asdict().get('sp'))
输出:7
user._replace():修改对象属性
print(Card('7','diamonds')._replace(sp=3))
输出:3
然后了从流畅的py中有一个扑克牌的小游戏的衍生:
class French:
ranks=[str(n) for n in range(2,11)]+list('JQKA')
suits='spades diamonds clubs hearts'.split()
def __init__(self):
self._card=[Card(rank,suit) for suit in self.suits for rank in self.ranks]#两次循环加一个列表推导式打造了一副完整的扑克牌
print(self._card)
def __len__(self):
return len(self._card)
def __getitem__(self, position):
return self._card[position]
__len__:返回集合长度
__getitem__(self, item) 使用索引访问元素
def __getitem__(self, item):
return self.x[item]
__setitem__(self, key, value) 对索引赋值,使用 self[key] = value #有点类似上面replace的方式
def __setitem__(self, key, value):
self.x[key]=value
__delitem__(self, key) 删除索引值 del self[key]##返回bool
例:def __delitem__(self, key):
del self.x[key]
__contains__ 实现in运算符,如果没有实现这个方法python也会调用__getitem__来使in运算符可用,返回bool
#方法应该把成员关系定义为对一个映射应用键(并且可以使用快速查找),以及用于序列的搜索
例:def __contains__(self, item):
return item in self.x
for…in… 迭代对象时会有一个先后顺序:python解释器调用的先后顺序
__contains__ >__iter__>__getitem__
迭代器生成器:
for … in… 这个语句其实做了两件事。第一件事是获得一个可迭代器,即调用了__iter__()函数。
第二件事是循环的过程,循环调用__next__()函数。
在没有__iter__声明的前提不使用__next__()而直接使用for循环,那么此时就会报错应为不是个迭代器
class test():
def __init__(self,data=1):
self.data = data
# def __iter__(self):
# return self
def __next__(self):
if self.data > 5:
raise StopIteration
else:
self.data+=1
return self.data
for item in test(3):
print(item)
#在没有__iter__声明的前提下含有该__next__()函数仍然是个迭代器函数
class test():
def __init__(self,data=1):
self.data = data
def __next__(self):
if self.data > 5:
raise StopIteration
else:
self.data+=1
return self.data
t = test(3)
for i in range(3):
print(t)#映射到内存当中
print(t.__next__())#从内存中迭代出值
生成器是一种特殊的迭代器,yield这是将结果挂起,通过list()将列表生成
def fib(end = 1000):
prev,curr=0,1
while curr < end:
yield curr
prev,curr=curr,curr+prev
print(list(fib()))
python解释器调用顺序,流畅py也是如此说的
迭代器和生成器
同时了流畅的py说内置函数本省是通过特殊函数实现的速度可能会更加优于特殊函数,也有更多扩展,所以在不是元编程的情况下最后使用内置函数