On Wed, Apr 15, 2020 at 3:36 PM Eric V. Smith <e...@trueblade.com> wrote:

> In general, it's not possible to know how to call super.__init__() if you
> don't a priori know the arguments it takes. That's why dataclasses doesn't
> guess. The only general-purpose way to do it is to use *args and **kwargs.
>

I was about to make this same point, thanks. super.__init__() absolutely
should NOT be called by default in an auto-generated __init__.

However, dataclasses, could, optionally, take *args and **kwargs, and store
them in a instance attribute. Then you could call super(), or anything
else, in __post_init__. And there are other reasons to want them to take
arbitrary other parameters (like to ignore them, see the PR).


> Since a goal of dataclasses is to use good typing information that works
> with type checkers, that seems to defeat part of the purpose.
>

I have never used a type checker :-) -- but I still really dislike the
passing around of *args, **kwargs -- it makes your API completely non-self
documented. So I'll agree here.

> One thing you could do in this scenario is to use a classmethod as an
> "alternate constructor". This basically gives you any post- and pre- init
> functionality you want, using any regular parameters or *args and **kwargs
> as fits your case.
>
That's a nice way to go -- I suggested a similar way by adding another
layer of subclassing. Using a classmethod is cleaner, but using another
layer of subclassing allows you to keep the regular __init__ syntax -- and
if you want to make these classes for others to use, the familiar API is a
good thing.

I do wonder if we could have a __pre_init__ -- as a way to add something
like this classmethod, but as a regular __init__. Butnow that I think about
it, here's another option: if the user passes in init=False, (or maybe some
other value), then the __init__ could still be generated, and accesable to
the user's __init__. It might look something like this (to follow your
example):

from dataclasses import dataclass

class BaseClass:
    def __init__(self, x, y):
        print('initializing base class', x, y)
        self.x = x
        self.y = y

@dataclass(init=False)
class MyClass(BaseClass):
    a: int
    b: int
    c: int
    def __init__(self, a, b, c, x, y):
        super.__init__(x, y)
        #  _ds__init__ would be the auto-generated __init__
        self._ds__init__(self, a, b, c)
        return self


c = MyClass.new(1, 2, 3, 10, 20)
print(c)
print(c.x, c.y)

> To Brett's point: has anyone looked to see what attrs does here? When
last I looked, they didn't call any super __init__, but maybe they've added
something to address this.

"Please note that attrs does not call super() *ever*." (emphasis theirs)

So that's that. :-)

I also did see this: (from https://www.attrs.org/en/stable/init.html):
"Embrace classmethods as a filter between reality and what’s best for you
to work with"
and:
"Generally speaking, the moment you think that you need finer control over
how your class is instantiated than what attrs offers, it’s usually best to
use a classmethod factory..."

Which seems to support your classmethod idea :-)

But I still think that it would be good to have some kin dof way to
customise the __init__ without re-writting the whole thing, and/or have a
way to keep *args,**kwargs around to use in __post_init__

Maybe a gitHub repo just for dataclasses?
>

@Eric V. Smith <e...@trueblade.com>: what do you think? Is there a way to
> keep them moving forward?
>
I think it's fine to make suggestions and have discussions here.
> Dataclasses aren't sufficiently large that they need their own repo (like
> tulip did, for example).
>
Sure -- and go to know you're monitoring this list (and no, I don't expect
instant responses) But it's just that I've seen at least one idea (the
**kwargs one) kind of wither and die, rather than be rejected (at least not
obviously) -- which maybe would have happened anyway.

> But I also don't think we're going to just add lots of features to
> dataclasses. They're meant to be lean.
>
As they should be.

> I realize drawing the line is difficult. For example, I think asdict and
> astuple were mistakes, and should have been done outside of the stdlib.
>
I agree there -- I've found I needed to re-implement asdict anyway, as I
needed something a little special. But that's only possible because
dataclasses already have the infrastructure in place to do that.

So I think any enhancements should be to allow third-party extensions,
rather than actual new functionality. In this case, yes, folks can use an
alternate constructor, but there is no way to get other arguments passed
through an auto-generated__init__ -- so there are various ways that one
cannot extend dataclasses -- I'd like to see that additional feature, to
enable various third-party extensions.

-CHB

-- 
Christopher Barker, PhD

Python Language Consulting
  - Teaching
  - Scientific Software Development
  - Desktop GUI and Web Development
  - wxPython, numpy, scipy, Cython
_______________________________________________
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/FFMGPKUDFBCSNTBRFCK2DQOORKKQORLN/
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to