Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ability to use self within factories #25

Closed
econchick opened this issue Sep 2, 2015 · 9 comments
Closed

Add ability to use self within factories #25

econchick opened this issue Sep 2, 2015 · 9 comments
Milestone

Comments

@econchick
Copy link
Contributor

A non-attrs example:

class Foo(object):
  def __init__(self, x):
    self.x = x
    self.y = 'bla'

class Bar(Foo):
  def __init__(self, x):
    super(Bar, self).__init__(x)
    self.z = self.foo()  # this is what I want to do with attrs

  def foo(self):
    return self.y 
>>> b = Bar(1)
>>> b.foo()
'bla'
>>> b.z
'bla'

Or ideally with attrs:

@attr.s
class Foo(object):
    x = attr.ib()
    y = attr.ib(default='bla')

@attr.s
class Bar(Foo):
    z = attr.ib(default=attr.Factory(foo, pass_self=True)

    def foo(self):
        return self.y

or something like that.

DANKE.

@hynek
Copy link
Member

hynek commented Dec 20, 2015

So the problem here is that when z is defined, foo doesn’t exist yet.

It would be possible to pass self into factories but they’d have to be functions which kind of defeats the purpose, right?

I wonder if something like:

@attr.s(post=True)
class C:
    x = attr.ib(init=False)

   def __post_init__(self):
      """
      Called at the end of __init__.
      """
      self.x = "whatever"

would make sense?

@econchick
Copy link
Contributor Author

I think so - if class C inherited from another class, e.g. class B, can __post__ access attributes defined in class B?

@hynek
Copy link
Member

hynek commented Dec 23, 2015

I’m thinking that attrs will generate:

def __init__(self):
    self._x = None
    self.__post_init__()

for you.

@grahamegee
Copy link

Personally I would like to be able to mix and match having the attr generated __init__ along with some user defined __init__, and be able to decide which is executed first. Is there currently any way at all to execute user defined initialisation other than not decorating your class with @attr.s?

@wearpants
Copy link

@hynek I could use something similar to your __post_init__() as well, but I'd like the usual attr-provided __init__ to be called first. My use case is an object that takes a regex string as an arg and saves a compiled versions to a private attribute.

Currently I'm doing this with a classmethod constructor:

@attr.s
class A:
     some_regex = attr.ib()

    @classmethod
    def create(cls, *args, **kwargs):
        self = cls(*args, **kwargs)
        self._some_regex = re.compile(self.some_regex)
        return self

but this is less than ideal / breaks user expectations since the way to make an A instance is A.create(..) instead of A(..) (which gives you a half-built object).

I initially implemented a version using __init__ that (ab)used side effects in a validator to do the compilation, but then decided that was too hacky even for me.

@hynek
Copy link
Member

hynek commented Aug 18, 2016

Why would you say "but"? That's the whole point of post. :)

@wearpants
Copy link

I was kinda confused by signature of __init__ here and here not taking any arguments, and the value being set in post_init, but I think that's specific to x = attr.ib(init=False)

If we had:

@attr.s
class A:
    x = attr.ib()

    def __post_init__(self):
        assert hasattr(self, 'x')

I'd expect attrs to generate something like:

class A:
    def __init__(self, x):
        self.x = x
        self.__post_init__()

Sorry if I'm confusing things, been up since 4 AM for no good reason.

@hynek
Copy link
Member

hynek commented Aug 18, 2016

heh yeah my current plan is what you'd expect. This but thread started in a different direction until it settled on this. :)

I think I'll tackle it once immutably is in.

@hynek
Copy link
Member

hynek commented Aug 21, 2016

Closing in favor of #68 which contains a more succinct description of what we came up with.

@hynek hynek closed this as completed Aug 21, 2016
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants