今天我正在学习使用*
和**
来解包参数
我发现list
,str
,tuple
,dict
都可以*
解包。
我猜因为它们都是迭代的。所以我做了自己的课。
# FILE CONTENT
def print_args(*args):
for i in args:
print i
class MyIterator(object):
count = 0
def __iter__(self):
while self.count < 5:
yield self.count
self.count += 1
self.count = 0
my_iterator = MyIterator()
# INTERPRETOR TEST
In [1]: print_args(*my_iterator)
0
1
2
3
4
有效!但是如何在python中创建一个mapping
对象,如dict
,以便**
解包对它起作用?有可能吗?除了mapping
之外,python中还有另一种dict
对象吗?
PS:
我知道我可以使一个对象继承自dict
类,使其成为一个映射对象。但有没有像magic_method
这样的关键__iter__
来制作没有类继承的映射对象?
PS2:
在@ mgilson的回答的帮助下,我创建了一个可以由**
解压缩而不从当前映射对象继承的对象:
# FILE CONTENT
def print_kwargs(**kwargs):
for i, j in kwargs.items():
print i, '\t', j
class MyMapping(object):
def __getitem__(self, key):
if int(key) in range(5):
return "Mapping and unpacking!"
def keys(self):
return map(str, range(5))
my_mapping = MyMapping()
print_kwargs(**my_mapping)
# RESULTS
1 Mapping and unpacking!
0 Mapping and unpacking!
3 Mapping and unpacking!
2 Mapping and unpacking!
4 Mapping and unpacking!
请注意,使用**
解压缩时,映射对象中的键应为str
,否则将引发TypeError。
答案 0 :(得分:1)
可以使用任何映射。我建议您继承collections.Mapping
或collections.MutableMapping
1 。它们是抽象的基类 - 你提供了几个方法,基类填补了其余的基础。
以下是您可以使用的“冻结”的示例:
from collections import Mapping
class FrozenDict(Mapping):
"""Immutable dictionary.
Abstract methods required by Mapping are
1. `__getitem__`
2. `__iter__`
3. `__len__`
"""
def __init__(self, *args, **kwargs):
self._data = dict(*args, **kwargs)
def __getitem__(self, key):
return self._data[key]
def __iter__(self):
return iter(self._data)
def __len__(self):
return len(self._data)
用法只是:
def printer(**kwargs):
print(kwargs)
d = FrozenDict({'a': 1, 'b': 2})
printer(**d)
为了回答你关于允许解压缩所需的“魔法”方法的问题 - 仅仅基于实验 - 在Cpython中,__getitem__
和keys
的类足以允许它将被**
解压缩。话虽如此,没有保证适用于其他实现(或CPython的未来版本)。要获得保证,您需要实现完整的映射接口(通常在我上面使用的基类的帮助下)。
在python2.x中,还有UserDict.UserDict
可以在python3.x中作为collections.UserDict
访问 - 但是如果你打算使用这个,你可以经常{{3} }。
1 请注意,从Python3.3开始,这些类已移至collections.abc
模块。
答案 1 :(得分:0)
首先,让我们定义解包:
def unpack(**kwargs):
"""
Collect all keyword arguments under one hood
and print them as 'key: value' pairs
"""
for key_value in kwargs.items():
print('key: %s, value: %s' % key_value)
现在,结构:两个内置选项可用collections.abc.Mapping和collections.UserDict。正如另一个答案探索高度可自定义的Mapping
类型一样,我将重点关注UserDict
:UserDict
如果你需要的只是一个基本的dict结构,可以更容易入手一些扭曲。定义后,基础UserDict
字典也可以作为.data
属性访问。
1.它可以内联使用,如下:
from collections import UserDict
>>> d = UserDict({'key':'value'})
>>> # UserDict makes it feel like it's a regular dict
>>> d, d.data
({'key':'value'}, {'key':'value'})
将UserDict
分成key = value对:
>>> unpack(**d)
key: key, value: value
>>> unpack(**d.data) # same a above
key: key, value: value
2.如果是子类化,您所要做的就是在__init__
中定义self.data。请注意,我使用(self + other)&#39; magic&#39;扩展了该类的附加功能。方法:
class CustomDict(UserDict):
def __init__(self, dct={}):
self.data = dct
def __add__(self, other={}):
"""Returning new object of the same type
In case of UserDict, unpacking self is the same as unpacking self.data
"""
return __class__({**self.data, **other})
def __iadd__(self, other={}):
"""Returning same object, modified in-place"""
self.update(other)
return self
用法是:
>>> d = CustomDict({'key': 'value', 'key2': 'value2'})
>>> d
{'key': 'value', 'key2': 'value2'}
>>> type(d), id(d)
(<class '__main__.CustomDict'>, 4323059136)
添加其他字典(或任何mapping
类型)将调用__add__
,返回新对象:
>>> mixin = {'a': 'aaa', 'b': 'bbb'}
>>> d_new = d + mixin # __add__
>>> d_new
{'key': 'value', 'a': 'aaa', 'key2': 'value2', 'b': 'bbb'}
>>>type(d_new), id(d_new)
(<class '__main__.CustomDict'>, 4323059248) # new object
>>> d # unmodified
{'key': 'value', 'key2': 'value2'}
使用__iadd__
进行就地修改将返回相同的对象(内存中的id相同)
>>> d += {'a': 'aaa', 'b': 'bbb'} # __iadd__
>>> d
{'key': 'value', 'a': 'aaa', 'key2': 'value2', 'b': 'bbb'}
>>> type(d), id(d)
(<class '__main__.CustomDict'>, 4323059136)
顺便说一句,我同意其他贡献者的观点,即你应该熟悉collections.abc.Mapping
和兄弟类型。对于基本字典探索,UserDict具有所有相同的功能,并且在变为可用之前不需要覆盖抽象方法。