Live data from Hacker News

Making Python's __init__ method magical

blog.lerner.co.il

21–30 of 42 posts

Re: Making Python's __init__ method magical

#21
post #18

And here's a more magical version that wraps it with a decorator. If you're gonna do this I kind of like this way better, but I'm pretty sure your average python programmer finds it obscene: from pprint import pprint def default_init(init_func): arg_count = init_func.func_code.co_argcount arg_vars = init_func.func_code.co_varnames[1:1+arg_count] def wrap_init(self, *args, **kwargs): idx = 0 for arg in arg_vars: if ar…

nice but it doesn't work if not all kwargs are passed..

Here is another version implemented as a decorator. Actually I’d also like not to use inspect, but didn’t find any nice way to get the kwargs default values without it, any suggestion?

    import inspect
    
    def autoinit(decorated_init):
        def _wrap(*args, **kwargs):
            obj,  nargs= args[0], args[1:]
            names = decorated_init.func_code.co_varnames[1:len(nargs)+1]
            nargs = {k: nargs[names.index(k)] for k in names}
            kwa_keys = decorated_init.func_code.co_varnames[len(nargs)+1:]
            kwa_defaults = inspect.getargspec(decorated_init).defaults
            for k in kwa_keys:
                nargs[k] = kwargs[k] if (k in kwargs) else kwa_defaults[kwa_keys.index(k)]
            for k, v in nargs.iteritems():
                setattr(obj, k, v)
            return decorated_init(*args, **kwargs)
        return _wrap
    
    
    if __name__ == '__main__':
    
        class Foo():
            @autoinit
            def __init__(self, a, b, x=0, y=0):
                self.p = 'Hello, I am set inside the __init__'
                self.s = self.a + self.b + self.x + self.y
    
        f = Foo(1, 2, x=120, y=5)
        for param in 'abxyps':
            print param, '=>', getattr(f, param)
    
        f = Foo(31, 33, x=64)
        for param in 'abxyps':
            print param, '=>', getattr(f, param)
    
        f = Foo(7, 121)
        for param in 'abxyps':
            print param, '=>', getattr(f, param)

Re: Making Python's __init__ method magical

#22
post #18

And here's a more magical version that wraps it with a decorator. If you're gonna do this I kind of like this way better, but I'm pretty sure your average python programmer finds it obscene: from pprint import pprint def default_init(init_func): arg_count = init_func.func_code.co_argcount arg_vars = init_func.func_code.co_varnames[1:1+arg_count] def wrap_init(self, *args, **kwargs): idx = 0 for arg in arg_vars: if ar…

nice but it doesn't work if not all kwargs are passed..

Good call. It's amazing how many things you have to be careful of when writing decorators.

Re: Making Python's __init__ method magical

#23

Oh boy, so I started using Python first. I took "reflection everywhere" for granted so hard without even knowing it. I learned Clojure next, and while it had its rough points I never thought, "Man this is really hard!" Then, I learned some Scala & Java. That's when I realized how for granted I took this thing called "reflection". Especially when it came to ORMs. Holy mackerel. I got over it but it is definitely a hug…

The JVM does have powerful reflection capabilities, even though most programmers don't use it directly.

You do see it used for mocking, ORMs, dependency injection, etc.

Re: Making Python's __init__ method magical

#25
post #5

CoffeeScript has a nice syntactic sugar for setting properties by prefixing the argument name with "@": class Foo constructor: (@x, @y) -> @z = @x + @y setFoo: (@foo) -> Which compiles to: http://coffeescript.org/#try:class%20Foo%0A%20%20constructor...

Interesting you mentioned CoffeeScript and syntactic sugar, because adding an equivalent "self." in python inits' parameter names doesn't work the same way in CoffeeScript.

    def __init__(self, self.x, self.y):  # fail
        pass
Did you mention this because there is an existing PEP that proposes this functionality?

Re: Making Python's __init__ method magical

#26
I had a different take on this - it's somewhat inspired by collections.namedtuple but mutable and has some other convenient features for data classes: https://gist.github.com/tomstrummer/8240282

(see the examples at the bottom of the file)

This could also be tweaked to use __dict__ instead of __slots__ so it can act as an expando class which I believe is more similar to what the OP achieves.

Re: Making Python's __init__ method magical

#28
I don't see much value autoassignining args. I do see being useful at times to auto-assign kwargs.

  class Base(object):
      def __init__(self, *args, **kws):
          self.__dict__.update(kws)

  class Foo(Base):
      def__init__("foo", age=30):
          self.name = "foo"
          super(Foo, self).__init__("foo", age=30)
or you can do the same using a decorator for the init.

  def update(init_meth):
      def wrapped(self, *args, **kws):
          init_meth(self, *args, **kws)
          self.__dict__.update(kws)
      return wrapped

  class Foo(object):
      @update
      def__init__("foo", age=30):
          self.name = "foo"

Re: Making Python's __init__ method magical

#29
post #9

Earlier quoted context omitted.

I'll have to check my terminology to understand this better. But I can assure you that most of the programmers who take my Python classes (who tend to come from Java, C#, and C++) are rather surprised that the constructor modifies an existing object, and doesn't actually create the object. That said, I'm totally willing to believe that neither they nor I understood the difference between an "allocator" and a "constru…

Well, they have a poor understanding[1] of the sequence of events in C++ if they think that the constructor allocates the object there (I won't speak too strongly to Java or C#, since I don't work in them if I don't have to, but I believe that they both work in a very similar way). This would in fact be impossible, since many constructors are usually called for any given object (and all constructors in the object's g…

Hi, I'm a C# developer who has done some Java and C++ in the past. You may consider me in the box of people who thinks the constructor creates the object, and the object not existing until the constructor finishes. The allocation of memory is not what I would count as creation of an object, as a model of memory is basically unrelated to the idea of objects and language semantics as I use them. If the object cannot be used, I would consider it not yet created.

I am not trying to argue (on the contrary, I would defer to your expertise), but rather I mean to add a small data point of what perspective developers with my background may have.

Post reply on HN