Write a Class which returns different values when called as list(c) and dict(c)
我试图实现一个自定义类,当调用
例如:
1 2 3 4 5 6 7 8 | class Foo: def __init__(self): self._keys = ['a', 'b', 'd', 'd', 'e'] self._data = [10, 20, 30, 40, 50] def __iter__(self): for key, value in zip(self._keys, self._data): yield key, value |
打电话给
1 2 3 | >>> f = Foo() >>> dict(f) {'a': 10, 'b': 20, 'd': 40, 'e': 50} |
号
但是,我不能让
1 2 3 | >>> f = Foo() >>> list(f) [('a', 10), ('b', 20), ('d', 30), ('d', 40), ('e', 50)] |
字典的等效代码要干净得多:
1 2 3 4 5 | >>> f = {'a': 10, 'b': 20, 'c': 30, 'd': 40, 'e': 50} >>> dict(f) {'a': 10, 'b': 20, 'c': 30, 'd': 40, 'e': 50} >>> list(f) ['a', 'b', 'c', 'd', 'e'] |
。
显然,
python文档说明了
If a positional argument is given and it is a mapping object, a dictionary is created with the same key-value pairs as the mapping object.
号
现在,问题是什么"映射"对于
也就是说,
1 2 3 4 5 | if hasattr(source, 'keys'): for k in source.keys(): self[k] = source[k] else: self.update(iter(source)) |
用这个我们得到
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | class Foo: def __init__(self): self._keys = ['a', 'b', 'd', 'd', 'e'] self._data = [10, 20, 30, 40, 50] def __iter__(self): return iter(self.keys) def __getitem__(self, key): idx = self._keys.index(key) return self._data[idx] def keys(self): return self._keys |
号
测试:
1 2 3 4 5 6 | >>> f = Foo() >>> list(f) ['a', 'b', 'd', 'd', 'e'] >>> dict(f) {'d': 30, 'e': 50, 'a': 10, 'b': 20} |
(从上面的代码中可以看到,不需要实际继承任何东西)
但是,并不能保证所有映射构造函数的行为都是相同的——其他一些可能称为
1 2 3 4 5 6 7 8 9 10 11 | class Foo(collections.abc.Mapping): ... def __getitem__(self, key): idx = self._keys.index(key) return self._data[idx] def __iter__(self): return iter(self._keys) def __len__(self): return len(self._keys) |
。
@米吉尔森的评论是正确的,这可以通过继承
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | class Foo(collections.abc.Mapping): def __init__(self): self._keys = ['a', 'b', 'd', 'd', 'e'] self._data = [10, 20, 30, 40, 50] def __iter__(self): for key in self._keys: yield key def __getitem__(self, value): return self._data[self._keys.index(value)] def __len__(self): return len(self._keys) |
1 2 3 4 5 6 | >>> f = Foo() >>> list(f) ['a', 'b', 'd', 'd', 'e'] >>> dict(f) {'a': 10, 'b': 20, 'd': 30, 'e': 50} |
。