Re: [Python-ideas] Python 3.7 dataclasses attribute order

2018-10-24 Thread Eric V. Smith

On 10/24/2018 5:30 AM, Anders Hovmöller wrote:
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.


https://bugs.python.org/issue33129

I definitely wouldn't want this to be the default. And as you say, it's 
too late anyway.


I haven't decided how the interaction of per-field and whole class 
versions of keyword-only should operate.


Eric

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


Re: [Python-ideas] Python 3.7 dataclasses attribute order

2018-10-24 Thread Anders Hovmöller
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  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 )
> serializer = OBJECT_SERIALIZERS.get(field.type, None)
> 
> if serializer:
> value = serializer(value)
> yield value
> 
> @property
> def field_names(self):
> return [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  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/