J'essaye de surcharger la méthode __add__
sur des instances namedtuple et j'ai un peu de problème.surcharger correctement le __add__ d'un namedtuple
Les paramètres entrés dans mes namedtuples sont générés dynamiquement. Quatre paramètres sont toujours les mêmes et dans le même ordre, mais le reste peut être n'importe quoi et n'importe quel nombre. Je dois donc pouvoir définir dynamiquement ma fabrique de classes namedtuple. Et après avoir créé plusieurs instances, j'aimerais pouvoir les ajouter ensemble dans une nouvelle instance namedtuple, avec tous les paramètres uniques ensemble. Mais j'ai de la difficulté à surcharger correctement la méthode __add__
. Cela ne semble pas fonctionner.
Ainsi, par exemple, si j'ai 3 instances namedtuple
e = Row(a=1, b=2, c=3, d=4)
m = Row(a=1, b=2, c=3, d=4, param1='a', param2='b')
t = Row(a=1, b=2, c=3, d=4, param3='val', param4=10)
Je voudrais pouvoir les ajouter comme e + m + t
qui retourne
Row(a=1, b=2, c=3, d=4, param1='a', param2='b', param3='val', param4=10)
Voici mon code actuel
class Row(object):
''' Creates a new namedtuple object '''
__slots__ =()
def __new__(cls, *args, **kwargs):
''' make a new Row instance '''
default = namedtuple('Row', 'a, b, c, d')
newcols = set(args) - set(default._fields)
finalfields = default._fields + tuple(newcols) if newcols else default._fields
return namedtuple('Row', finalfields)
def __add__(self, other):
''' This is the new add '''
self_dict = self._asdict()
other_dict = other._asdict()
self_dict.update(other_dict)
new_fields = tuple(self_dict.keys())
new_row = namedtuple('Row', new_fields)
return new_row(**self_dict)
Avec ceci, je peux correc TLY générer dynamiquement de nouvelles namedtuples, et les instancier
e = Row()
m = Row(*['a', 'b', 'c', 'd', 'param1', 'param2'])
e._fields
('a', 'b', 'c', 'd')
m._fields
('a', 'b', 'c', 'd', 'param1', 'param2')
e2 = e(1, 2, 3, 4)
m2 = m(1, 2, 3, 4, 'a', 'b')
e2
Row(a=1, b=2, c=3, d=4)
type(e2)
__main__.Row
m2
Row(a=1, b=2, c=3, d=4, param1='a', param2='b')
mais quand je les ajoute, ma surcharge __add__
ne sera jamais appelé et je semble juste obtenir un objet régulier de tuple retour sur
w = e2 + m2
print(w)
(1, 2, 3, 4, 1, 2, 3, 4, 'a', 'b')
type(w)
tuple
Ma __add__
méthode ne semble pas être actif sur mes objets d'instance.
Row.__add__?
Signature: Row.__add__(self, other)
Docstring: This is the new add
File: <ipython-input-535-817d9f528ae7>
Type: instancemethod
e.__add__?
Type: wrapper_descriptor
String form: <slot wrapper '__add__' of 'tuple' objects>
Docstring: x.__add__(y) <==> x+y
e2.__add__?
Type: method-wrapper
String form: <method-wrapper '__add__' of Row object at 0x122614050>
Docstring: x.__add__(y) <==> x+y
Qu'est-ce que je fais mal? J'ai aussi essayé de sous-classer namedtuple ('Row', ...), comme indiqué dans les docs https://docs.python.org/2/library/collections.html#collections.namedtuple, mais je n'ai pas réussi à faire marcher ça. Je n'ai pas réussi à changer dynamiquement les paramètres nommés.
est que l'échec
BaseRow = namedtuple('BaseRow', 'a, b, c, d')
class Row(BaseRow):
__slots__ =()
def __new__(cls, *args, **kwargs):
new_fields = set(kwargs.keys()) - set(cls._fields)
cls._fields += tuple(new_fields)
obj = super(Row, cls).__new__(cls, *args, **kwargs)
return obj
e = Row(a=1, b=2, c=3, d=4, param1='a')
TypeError: __new__() got an unexpected keyword argument 'param1'
C'est ... contrairement à beaucoup de décisions de conception namedtuple, et peu susceptible de se révéler bien. Je recommande d'utiliser simplement des dicts. – user2357112