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

Means to pass arguments to __attrs_post_init__ #180

Closed
brouhaha opened this issue Apr 20, 2017 · 6 comments
Closed

Means to pass arguments to __attrs_post_init__ #180

brouhaha opened this issue Apr 20, 2017 · 6 comments

Comments

@brouhaha
Copy link

I'd like to be able to use attrs_post_init() to support alternate means of initializing the object, based on extra arguments to the initializer. For my purposes it's fine if the normal attrs initialization is done first. For instance, I might want to write:

x = Foo(a = 37, b = 62, c = 'hello')
y = Foo(file = 'foo.json')

Perhaps only if an attrs_post_init() exits, and there are any arguments that can't be handled in the usual way, those arguments could be passed to attrs_post_init()?

I wouldn't object too much if the initialization of y as shown above didn't work if the a, b, and c attributes didn't have default values. On the other hand, perhaps it would be nice for an alternate initialization to work even if non-defaulted arguments weren't provided.

Perhaps there's a better way to do this which I've simply overlooked.

I could do something like:

y = Foo(a = 37, b = 62, c = 'hello')
y.load_file(file = 'foo.json')

but that can't be used if Foo is 'frozen'.

@Tinche
Copy link
Member

Tinche commented Apr 20, 2017

The usual pattern (not just in attrs, but in Python) is to use class methods as alternate constructors.

x = Foo(a = 37, b = 62, c = 'hello')
y = Foo.from_file('foo.json')

You haven't showed us Foo, so presumably foo.json contains the values for a, b and c :)

@hynek
Copy link
Member

hynek commented Apr 20, 2017

Yep, @Tinche is 💯 on this one. I’m closing this now, feel free to comment/ask if you have any further questions though!

@hynek hynek closed this as completed Apr 20, 2017
@brouhaha
Copy link
Author

brouhaha commented Apr 20, 2017

I oversimplified what I'm trying to do, which is actually some fairly complex initialization that uses the normal attrs initialization then adds more stuff, where the more stuff is done in attrs_post_init(). A little closer to what I'm trying to do is:

x = Foo(a = 16, b = 119, c = 72, d = 'bar')
y = Foo(a = 37, b = 62, image = some_bytearray, offset = 0x180)

where a and b are defined with attrs, but various other attributes (possibly including c and d) need to be pulled from the binary image, and the object is intended to be immutable (frozen).

In general, it seems like a way to pass args to attrs_post_init() would be useful for any number of things, not just what I'm doing right now.

@hynek
Copy link
Member

hynek commented Apr 20, 2017

You should really look into using classmethods for building your objects and making your __init__ machinery only validate and set attributes. You’ll get much nicer and obvious APIs out of it.

@brouhaha
Copy link
Author

I must just be really dense. I still don't see how to do it that way for a frozen object. I need it to be frozen because it needs to be hashable.

@hynek
Copy link
Member

hynek commented Apr 20, 2017

Untested example:

@attr.s(frozen=True)
class Foo:
    x = attr.ib()

    @classmethod
    def from_file(cls, path):
        with open(path) as f:
            return cls(x=f.read())

Gives you a very explicit way to instantiate Foo and at the same time makes it easy to test it since you can instantiate it with anything.

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

3 participants