Issue
I have a list of dicts and I'd like to use python-attrs
to convert them into classes.
Here's the sample data:
[[characters]]
first_name = 'Duffy'
last_name = 'Duck'
[[characters]]
first_name = 'Bugs'
last_name = 'Bunny'
[[characters]]
first_name = 'Sylvester'
last_name = 'Pussycat'
[[characters]]
first_name = 'Elmar'
last_name = 'Fudd'
[[characters]]
first_name = 'Tweety'
last_name = 'Bird'
[[characters]]
first_name = 'Sam'
last_name = 'Yosemite'
[[characters]]
first_name = 'Wile E.'
last_name = 'Coyote'
[[characters]]
first_name = 'Road'
last_name = 'Runner'
This will then turn into a dictionary after reading the content:
{'characters': [{'first_name': 'Duffy', 'last_name': 'Duck'},
{'first_name': 'Bugs', 'last_name': 'Bunny'},
{'first_name': 'Sylvester', 'last_name': 'Pussycat'},
{'first_name': 'Elmar', 'last_name': 'Fudd'},
{'first_name': 'Tweety', 'last_name': 'Bird'},
{'first_name': 'Sam', 'last_name': 'Yosemite'},
{'first_name': 'Wile E.', 'last_name': 'Coyote'},
{'first_name': 'Road', 'last_name': 'Runner'}]}
My classes look like this:
@define(kw_only=True)
class Character:
first_name: str
last_name: str
@define
class LooneyToons:
characters: List[Character] = field(factory=list, converter=Character)
But it does not work:
TypeError: Character.__init__() takes 1 positional argument but 2 were given
Of course I could modify the class a bit and use this code (which works):
@define
class LooneyToons:
characters: List[Character]
> LooneyToons([Character(**x) for x in d['characters']])
LooneyToons(characters=[Character(first_name='Duffy', last_name='Duck'), Character(first_name='Bugs', last_name='Bunny'), Character(first_name='Sylvester', last_name='Pussycat'), Character(first_name='Elmar', last_name='Fudd'), Character(first_name='Tweety', last_name='Bird'), Character(first_name='Sam', last_name='Yosemite'), Character(first_name='Wile E.', last_name='Coyote'), Character(first_name='Road', last_name='Runner')])
But it would be more elegant (from my point of view) to handle this within the class LooneyToons
by just giving d['characters']
as argument to the class.
Any hints for me? I already checked out cattrs
but I don't get the point on how it may be useful in my case.
Solution
I'm the author of cattrs (and a maintainer of attrs ;).
The problem is your converter
argument on LooneyToons.characters
. Here's the solution without it:
from typing import List
from attrs import define, field
from cattrs import structure
d = {
"characters": [
{"first_name": "Duffy", "last_name": "Duck"},
{"first_name": "Bugs", "last_name": "Bunny"},
{"first_name": "Sylvester", "last_name": "Pussycat"},
{"first_name": "Elmar", "last_name": "Fudd"},
{"first_name": "Tweety", "last_name": "Bird"},
{"first_name": "Sam", "last_name": "Yosemite"},
{"first_name": "Wile E.", "last_name": "Coyote"},
{"first_name": "Road", "last_name": "Runner"},
]
}
@define(kw_only=True)
class Character:
first_name: str
last_name: str
@define
class LooneyToons:
characters: List[Character] = field(factory=list)
structure(d, LooneyToons)
If you insist on using a converter, it'll have to be a little more sophisticated than just Character
(see other answer). But I suggest just removing it.
Answered By - Tin Tvrtković
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.