[Python-ideas] Simple class initialization
dag.odenhall at gmail.com
dag.odenhall at gmail.com
Sat Apr 16 14:08:45 CEST 2011
On 16 April 2011 13:50, Adam Matan <adam at matan.name> wrote:
> 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
class Process:
# Defaults and documentation as class attributes
pid = None
def __init__(self, **kwargs):
for k, v in kwargs.iteritems():
setattr(self, k, v)
More information about the Python-ideas
mailing list