17

Can I have easily a list of field from a dataclass ?

@dataclass
class C:
    x: int
    y: int
    z: int
    t: int

expected result:

[x,y,z,t]
Lars Blumberg
  • 19,326
  • 11
  • 90
  • 127
Sylvain Page
  • 581
  • 1
  • 7
  • 21

2 Answers2

27

The answer depends on whether or not you have access to an object of the class.

Just using the class

If you only have access to the class, then you can use dataclasses.fields(C) which returns a list of field objects (each of which has a .name property):

[field.name for field in dataclasses.fields(C)]

From an existing object

If you have a constructed object of the class, then you have two additional options:

  1. Use dataclasses.fields on the object:
[field.name for field in dataclasses.fields(obj)]
  1. Use dataclasses.asdict(obj) (as pointed out by this answer) which returns a dictionary from field name to field value. It sounds like you are only interested in the .keys() of the dictionary:
dataclasses.asdict(obj).keys()       # gives a dict_keys object
list(dataclasses.asdict(obj).keys()) # gives a list
list(dataclasses.asdict(obj))        # same 

Full example

Here are all of the options using your example:

from dataclasses import dataclass, fields, asdict


@dataclass
class C:
    x: int
    y: int
    z: int
    t: int

# from the class
print([field.name for field in fields(C)])

# using an object
obj = C(1, 2, 3, 4)

print([field.name for field in fields(obj)])
print(asdict(obj).keys())
print(list(asdict(obj).keys()))
print(list(asdict(obj)))

Output:

['x', 'y', 'z', 't']
['x', 'y', 'z', 't']
dict_keys(['x', 'y', 'z', 't'])
['x', 'y', 'z', 't']
['x', 'y', 'z', 't']
teichert
  • 3,963
  • 1
  • 31
  • 37
13

You can use the asdict method of the dataclasses module. For example:

from dataclasses import dataclass, asdict


@dataclass
class Person:
    age: int
    name: str


adam = Person(25, 'Adam')

# if you want the keys

print(asdict(adam).keys()) # dict_keys(['age', 'name'])

# if you want the values

print(asdict(adam).values()) # dict_values([25, 'Adam'])

Both methods above return a View object which you can iterate on, or you can convert it to list using list(...).

adnanmuttaleb
  • 3,388
  • 1
  • 29
  • 46
  • asdict(instance).keys().... can it be done on Nc class object ? – Sylvain Page Nov 04 '19 at 14:48
  • on your dataclass object e.g: `obj = C(1,2,4,5)` you can call `obj.asdict().keys()`. I hope it is clear @SylvainPage. – adnanmuttaleb Nov 04 '19 at 14:52
  • 1
    I don't know why but obj.asdict() returns me "C has no attribute asdict". This why I do asdict(obj).keys().... My import was from dataclasses import dataclass, asdict. Never mind it works as well as C.__dataclass_fields__.keys() ... – Sylvain Page Nov 04 '19 at 22:14
  • @SylvainPage you can review the docs, the link exist in the answer. – adnanmuttaleb Nov 05 '19 at 06:12
  • Unfortunately this is not usable for frozen dataclasses, resulting in `FrozenInstanceError` exception. – Abel Cheung Oct 01 '20 at 20:02
  • 3
    @SylvainPage You need `from dataclasses import asdict` and then you can call `asdict(C())` to get the dict. – Patrick Jun 03 '21 at 09:51
  • Thanks for the additional comment Patrick, that worked for me! – user3358107 Oct 01 '21 at 16:13
  • 1
    Is this answer not wrong? I believe the correct use is `asdict(obj)`, not `obj.asdict()`. – ayoon Apr 10 '22 at 21:30
  • 1
    This answer is certainly wrong, there is no such thing as an "asdict" method on the dataclass instance, there is function asdict that can be imported and used on the instances. I'm surprised this has so many upvotes and was marked as accepted response until recently when it doesn't work and can't work. – Disruption Apr 13 '22 at 09:24
  • @Disruption, thank you for your note, I have update the answer – adnanmuttaleb Apr 13 '22 at 21:17
  • 1
    Please keep in mind that if your dataclass stores more complicated objects (e.g. other dataclasses), `asdict` will convert them to dictionaries as well. So technically, they're not the original values of that dataclass. For example, you'd lose the ability to call their methods. That is the reason why I prefer to use `[getattr(adam, field.name) for field in fields(adam)]` than `asdict(adam).values()`. – kszl Jun 23 '22 at 00:17