Python 用于字典转换的特殊方法名的内置函数
我一直在深入研究Python类中的运算符重载和特殊方法,我注意到许多内置函数都有其等效的特殊方法名称:Python 用于字典转换的特殊方法名的内置函数,python,python-3.x,function,class,oop,Python,Python 3.x,Function,Class,Oop,我一直在深入研究Python类中的运算符重载和特殊方法,我注意到许多内置函数都有其等效的特殊方法名称: int(x)调用x.\uuuu int\uuuu() next(x)调用Python2中的x.\uuuu next\uuuu()或x.next() 但是,一对函数,即tuple()和dict(),没有任何等效函数。我知道还没有必要使用这种特殊方法,但在某些情况下,对类调用的dict()转换方法可能很有用。我该如何实现这一点?或者,对于试图使用这种逻辑的人,你会怎么评论 # I think
调用int(x)
x.\uuuu int\uuuu()
调用Python2中的next(x)
或x.\uuuu next\uuuu()
x.next()
tuple()
和dict()
,没有任何等效函数。我知道还没有必要使用这种特殊方法,但在某些情况下,对类调用的dict()
转换方法可能很有用。我该如何实现这一点?或者,对于试图使用这种逻辑的人,你会怎么评论
# I think this is quite interesting, so I shall post my own implementation of it as well
以最简单的形式,我可以尝试检索
对象。我还创建了一个名为obj.\uuuuu dictionary\uuuu
的方法,它返回一个dict
,但可以自定义返回的值和方式。我实现了一个小函数,尝试调用obj.\uuuuu dictionary\uuuu
和其他方法的其他连续尝试:
def dct(obj=None, *args, **kwargs):
if obj:
try:
r = obj.__dictionary__()
except AttributeError:
try:
r = dict(obj)
except TypeError:
try:
r = obj.__dict__
except AttributeError as e:
raise AttributeError(e) from None
else:
return r
else:
return r
else:
return r
else:
return dict(*args, **kwargs)
为了演示,有一个小类封装了一个“Person”
:
class Person:
def __init__(self, name, age, job):
self.name = name
self.age = age
self.job = job
def __dictionary__(self):
return {'name': self.name,
'age': self.age,
'job': self.job,
'title': '{} {}'.format(self.job, self.name)}
p = Person('bob', 42, 'farmer')
现在考虑调用我的习惯>代码> DCT 函数对几个对象进行测试:
>>> dct(p)
{'name': 'bob', 'age': 42, 'job': 'farmer', 'title': 'farmer bob'}
>>> dct(item='apple', quantity=5)
{'item': 'apple', 'quantity': 5}
>>> dct([('username', 'admin'), ('password', '123')])
{'username': 'admin', 'password': '123'}
>>> dct({'a': 1, 'b': 2})
{'a': 1, 'b': 2}
正如你所看到的,它似乎工作在一个体面的方式。我知道,对于我简单的Person
类演示,我可以简单地返回p.uuu dict\uuuu
,但我添加了一个额外的p.title
属性,该属性只存在于dict
表单中,以表明这支持额外的定制。另外,如果我用\uuuuuuuuuuuuuuuuuuuuuuuuuuu>定义Person
类,那么dct(p)
调用将失败
AttributeError: 'Person' object has no attribute '__dict__'
显然,我可以扩展try/except
块来尝试访问\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu>插槽,但这并不是我想要了解的重点:如果我在自定义\uuuuu
按预期工作:
def __dictionary__(self):
return {name: getattr(self, name, None)
for name in self.__slots__}
选项1:\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
强制转换为元组
或dict
,或任何接受iterable的类型,都依赖于\uuuuuuuuuuuuuuuuuuuuuuuuu
方法
class ListOfKeys():
def __init__(self, lst):
self.lst = lst
def __iter__(self):
for k in self.lst:
yield (k, None)
lok = ListOfKeys([1, 2, 3])
d = dict(lok)
print(d) # {1: None, 2: None, 3: None}
这同样适用于元组
t = tuple(lok)
print(t) # ((1, None), (2, None), (3, None))
选项2:键
和\uu获取项目
或者,要转换为dict
,您可以同时实现键和键
class ListOfKeys():
def __init__(self, lst):
self.lst = lst
def keys(self):
yield from self.lst
def __getitem__(self, item):
return None
lok = ListOfKeys([1, 2, 3])
d = dict(lok)
print(d) # {1: None, 2: None, 3: None}
选项3:两者都支持多种类型
最后,如果您希望您的类具有不同的行为来强制转换为dict
和tuple
,下面的示例演示dict
将对键
和getitem
解决方案进行优先级排序
class Foo:
def __iter__(self):
yield 1
def keys(self):
yield 2
def __getitem__(self, item):
return 3
print(dict(Foo())) # {2: 3}
print(tuple(Foo())) # (1,)
dict
接受任何iterable对,假装语言实现了它没有实现的钩子有什么意义?dict
构造函数不支持它,那么为什么不简单地使用一个to_dict
方法呢?为了方便起见,我可以调用dict()
任何东西,而不必担心它是否有自己的to_dict
方法,然后用方法将它包装起来,然后尝试:返回obj.to_dict(),除了AttributeError:return obj.u dict
。。。我的主要观点是你不应该添加你自己的“特殊”邓德方法。事实上,确切地说,这在\uu iter\uuuuu
或\uuuu getitem\uuuuuuuuu
中被明确禁止。这似乎是最具python风格的方法。它肯定比我的干净。只是一个小小的评论:如果想让dict()、tuple()和iter()都有不同的行为,该怎么办?比如说,迭代只会产生值,而不是值对。@NChauhan在这种情况下,您的方法是正确的,只需去掉dunder命名.to_dict
,。to tuple
@NChauhan dict实际为密钥getitem解决方案排定优先级,请参阅更新的答案