Skip to content

Add ability to use self within factories #25

Closed

Description

@econchick

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.

Activity

  1. hynek commented on Dec 20, 2015

    @hynek
    Member

    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?

  2. econchick commented on Dec 22, 2015

    @econchick
    ContributorAuthor

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

  3. hynek commented on Dec 23, 2015

    @hynek
    Member

    I’m thinking that attrs will generate:

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

    for you.

  4. grahamegee commented on Mar 4, 2016

    @grahamegee

    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?

  5. added this to the 16.1 milestone on Aug 15, 2016
  6. wearpants commented on Aug 18, 2016

    @wearpants

    @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.

  7. hynek commented on Aug 18, 2016

    @hynek
    Member

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

  8. wearpants commented on Aug 18, 2016

    @wearpants

    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.

  9. hynek commented on Aug 18, 2016

    @hynek
    Member

    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.

  10. hynek commented on Aug 21, 2016

    @hynek
    Member

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions