Well that seems super unfortunate. You can opt out of the auto generate 
constructor and do it yourself:

  @dataclass(init=False)
  class Foo:
      foo: str
      bar: str = None
      baz: str

      def __init__(self, *, foo, bar = None, baz):
          self.foo = foo
          self.bar = bar
          self.baz = baz
    

  Foo(foo='a', bar='b', baz='c')

but this seems to take away from the utility of dataclasses. One could imagine 
there being a new argument to @dataclass that would make this work. Something 
like:


@dataclass(init_kwargs_only=True)
  class Foo:
      foo: str
      bar: str = None
      baz: str

where you would then get an auto generated constructor like with keyword only 
arguments. Personally I think this should have been the default, but it's at 
least a nice addition now.

/ Anders


> On 24 Oct 2018, at 05:13, Philip Martin <philip.martin2...@gmail.com> wrote:
> 
> Hi, I just started to use the new dataclasses module. My initial use case 
> boils down to somewhere between a namedtuple and a class where I want a 
> record with a few methods.
> 
> Mainly, I am trying to build a specific record from various sources, and then 
> have the class handle validation and serialization. One roadblock I have 
> found is that I can't use the field order I define for the class to say write 
> out a csv file if any of the fields have default value. I know this bucks 
> Python's args, kwargs ordering, but I think having the ability define 
> optional arguments and required arguments in any order helps improve the 
> classes intended usability. For instance, imagine "account_description_2" is 
> None for most sources, but must appear before "other_required_field" in a CSV 
> exported file. I think it would be useful to be able to do the following:
> 
> import csv
> from datetime import date
> from dataclasses import dataclass, fields
> from typing import List
> 
> OBJECT_SERIALIZERS = {date: date.isoformat}
> 
> @dataclass
> class Account:
>     account_id: str
>     account_description: str
>     account_description_2: str = None
> 
>     # INVALID
>     other_required_field: str
> 
>     def serialize(self):
>         for field in fields(self):
>             value = getattr(self, field.name <http://field.name/>)
>             serializer = OBJECT_SERIALIZERS.get(field.type, None)
> 
>             if serializer:
>                 value = serializer(value)
>             yield value
> 
>     @property
>     def field_names(self):
>         return [field.name <http://field.name/> for field in fields(self)]
> 
>     @classmethod
>     def from_source_a(cls, record):
>         return cls(account_id=record['account_code'],
>                    account_description=record['account_name'],
>                    other_required_field=record['other_field'])
> 
> @dataclass
> class AccountList:
>     accounts: List[Account]
> 
>     @property
>     def field_names(self):
>         return [
>             field.name <http://field.name/> for field in 
> fields(fields(self)[0].type.__args__[0])
>         ]
> 
>     @property
>     def record_field(self):
>         return fields(self)[0].name
> 
>     def to_csv(self, path):
>         with open(path, 'w') as file:
>             self.write_file(file)
> 
>     def write_file(self, file):
>         records_field = self.record_field
> 
>         writer = csv.writer(file)
>         writer.writerow(self.field_names)
>         writer.writerows(
>             record.serialize() for record in getattr(self, records_field)
>         )
> 
> _______________________________________________
> Python-ideas mailing list
> Python-ideas@python.org
> https://mail.python.org/mailman/listinfo/python-ideas
> Code of Conduct: http://python.org/psf/codeofconduct/

_______________________________________________
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to