[Python-ideas] Simple class initialization

Adam Matan adam at matan.name
Sat Apr 16 13:50:55 CEST 2011


0. Abstract
===========

A class initialization often begins with a long list of explicit variable
declaration statements at the __init__() method. This repetitively copies
arguments into local data attributes.
This article suggests some semi-automatic techniques to shorten and clarify
this code section. Comments and responses are highly appreciated.

1. Credit
=========

The idea emerged from my question at stackoverflow.com. I would like to
thank
all those who answered and commented on that thread.

http://stackoverflow.com/questions/1389180

2. The problem
==============

Consider the following class:

        class Process:
            def __init__(self, pid, ppid, cmd, fd, reachable, user):

If the instance needs to hold these arguments internally, local data
attributes
are declared and the value of the argument is being copied, using two
mainstream
notations:

a.

                self.pid=pid
                self.ppid=ppid
                self.cmd=cmd
                self._fd=fd
                self.reachable=reachable
                self.user=user

b.

                self.pid, self.ppid, self.cmd, self._fd, self.reachable,
self.user = pid, ppid, cmd, fd, reachable, user

a. takes an unreasonable amount of lines and has a repetative form.
b. is long and prone to errors, especially when the argument list changes
   during development.

3. Solution outline
===================

1. Generally comply with the Zen of Python.
1. Explicit. The instance should not store any value unless told.
2. Short.
3. Backward compatible. Current Class syntax should work with the
   new solution.
4. Readable and intuitive.
5. Flexible. There should be a way to store any given subset of
   the arguments.
6. Allow storage of "private" variables by adding a single or double
   underscore before the variable name.

4. Solutions
============

4.1 Decorator
-------------

Nadia Alramli suggested this at the aforementiond thread at stackoverflow:

        from functools import wraps
        import inspect

        def initializer(fun):
            names, varargs, keywords, defaults = inspect.getargspec(fun)
            @wraps(fun)
            def wrapper(self, *args):
                for name, arg in zip(names[1:], args):
                    setattr(self, name, arg)
                fun(self, *args)
            return wrapper

        class Process:
            @initializer
            def __init__(self, pid, ppid, cmd, fd, reachable, user)

Pros:
    Simple, short, explicit and intuitive.
    Easy to add to the standard library, fully backward-compatible.

Cons:
    Stores all arguments.
    Does not support private data attributes notation (underscore prefix).

See
http://stackoverflow.com/questions/1389180/python-automatically-initialize-instance-variables/1389216#1389216


4.2. Argument tagging
---------------------

Arguments that needed to be stored within the instance could be marked with
a
special character, e.g. '~'. The character would be placed after the
argument
name for private variables:

        class Process:
            def __init__(self, ~pid, ~ppid, ~cmd, fd~, ~reachable, ~user)

Pros:
    Simple, short and explicit.
    Can store any subset of the arguments.
    Supports private variable notation.

Cons:
    Not intuitive. Changes the method signature and might be confusing.


4.3 Standard function
---------------------

A function will be called to store the argument as data attributes.

        class Process:
            def __init__(self, pid, ppid, cmd, fd, reachable, user)
                acquire(pid, ppid, cmd, reachable, user)
                acquire(fd, prefix='_')

Possible keywords can ba acquire, store, absorp.

Pros:
    Explicit, clear and intuitive.

Cons:
    Long - especially if more than a single prefix is used.

4.4 Initialization list
-----------------------

The argument list would include the name of the local data attribute, a
separator, and the argument name.

        class Process:
            def __init__(self, pid:pid, ppid:ppid, cmd:cmd, _fd:fd,
reachable:reachable, user:user)
            """ pid, ppid, cmd, reachable and user are stored as data
properties
                with the same name. fd is stored as _fd."""

Or:

        class Process:
            def __init__(self, :pid, :ppid, :cmd, _fd:fd, :reachable, :user)
            """Same, but local data attributes with the same name as
arguments
               would be stored without stating their name twice."""

This is a developed argument tagging (4.2).

Pros:
     See 4.2

Cons:
     Alters the method signature
     Not intuitive.


Looking forward for comments,
Adam matan
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/python-ideas/attachments/20110416/92987df5/attachment.html>


More information about the Python-ideas mailing list