FAQ
There is a pattern that occurs fairly often in constructors in Python
and other OOP languages.

Let's take an example:

class Server(object):
def __init__(self, host, port, protocol, bufsize, timeout):
self.host = host
self.port = port
self.protocol = protocol
self.bufsize = bufsize
self.maxthreads = maxthreads
self.timeout = timeout

Imho, in the class above the assignment to instance fields does not
contain much programming logic and therefore can be safely 'abstracted
away' by the language itself with a syntax which would look something
like this:

class Server(object):
def __init__(self, @host, @port, @protocol, @bufsize, @timeout):
pass

This would be equivalent to the first example above, yet it does not
obfuscate the code in any way. Or does it? It does look much cleaner
to me.

Of course, the ampersand is just an arbitrary choice and might have
bad connotations for those who read it as 'take address of' but @ has
some allusion to delegates which maybe is ok.

I am not an experienced programmer and I am not sure if this is
necessarily a good idea, so I wanted to get some feedback from more
experienced Pythonistas before submitting it elsewhere.

Search Discussions

  • André at Jan 27, 2008 at 5:46 pm

    On Jan 27, 1:06 pm, coldpizza wrote:
    There is a pattern that occurs fairly often in constructors in Python
    and other OOP languages.

    Let's take an example:

    class Server(object):
    def __init__(self, host, port, protocol, bufsize, timeout):
    self.host = host
    self.port = port
    self.protocol = protocol
    self.bufsize = bufsize
    self.maxthreads = maxthreads
    self.timeout = timeout

    Imho, in the class above the assignment to instance fields does not
    contain much programming logic and therefore can be safely 'abstracted
    away' by the language itself with a syntax which would look something
    like this:

    class Server(object):
    def __init__(self, @host, @port, @protocol, @bufsize, @timeout):
    pass

    This would be equivalent to the first example above, yet it does not
    obfuscate the code in any way. Or does it? It does look much cleaner
    to me.

    Of course, the ampersand is just an arbitrary choice and might have
    bad connotations for those who read it as 'take address of' but @ has
    some allusion to delegates which maybe is ok.

    I am not an experienced programmer and I am not sure if this is
    necessarily a good idea, so I wanted to get some feedback from more
    experienced Pythonistas before submitting it elsewhere.
    If you search on this list, you will find that there has been *many*
    proposals to remove self (which, I realize is slightly different than
    what yo propose) and that the main argument can be summarized as
    "Explicit is better than implicit."

    Personally, I like the idea you suggest, with the modification that I
    would use "." instead of "@", as in

    class Server(object):
    def __init__(self, .host, .port, .protocol, .bufsize, .timeout):
    pass

    Andr?
  • Wildemar Wildenburger at Jan 27, 2008 at 6:16 pm

    Andr? wrote:
    Personally, I like the idea you suggest, with the modification that I
    would use "." instead of "@", as in

    class Server(object):
    def __init__(self, .host, .port, .protocol, .bufsize, .timeout):
    pass
    I like :)

    However, you can probably cook up a decorator for this (not certain, I'm
    not a decorator Guru), which is not that much worse.

    Still, I'd support that syntax (and the general idea.).

    /W
  • Diez B. Roggisch at Jan 27, 2008 at 6:32 pm

    Wildemar Wildenburger schrieb:
    Andr? wrote:
    Personally, I like the idea you suggest, with the modification that I
    would use "." instead of "@", as in

    class Server(object):
    def __init__(self, .host, .port, .protocol, .bufsize, .timeout):
    pass
    I like :)

    However, you can probably cook up a decorator for this (not certain, I'm
    not a decorator Guru), which is not that much worse.

    Still, I'd support that syntax (and the general idea.).
    Just for the fun of it, I implemented a decorator:

    from functools import *
    from inspect import *

    def autoassign(_init_):
    @wraps(_init_)
    def _autoassign(self, *args, **kwargs):
    argnames, _, _, _ = getargspec(_init_)
    for name, value in zip(argnames[1:], args):
    setattr(self, name, value)
    _init_(self, *args, **kwargs)

    return _autoassign

    class Test(object):
    @autoassign
    def __init__(self, foo, bar):
    pass



    t = Test(10, 20)

    print t.bar


    Diez
  • Wildemar Wildenburger at Jan 27, 2008 at 6:48 pm

    Diez B. Roggisch wrote:
    Just for the fun of it, I implemented a decorator:

    from functools import *
    from inspect import *

    def autoassign(_init_):
    @wraps(_init_)
    def _autoassign(self, *args, **kwargs):
    argnames, _, _, _ = getargspec(_init_)
    for name, value in zip(argnames[1:], args):
    setattr(self, name, value)
    _init_(self, *args, **kwargs)

    return _autoassign
    This is neat. :) Could that maybe be extended to only assign selected
    args to the instance and let others pass unchanged. So that, for instance:

    @autoassign("foo", "bar")
    def __init__(self, foo, bar, baz):
    super(baz)

    ?W
  • André at Jan 27, 2008 at 7:00 pm

    On Jan 27, 2:48 pm, Wildemar Wildenburger wrote:
    Diez B. Roggisch wrote:
    Just for the fun of it, I implemented a decorator:
    from functools import *
    from inspect import *
    def autoassign(_init_):
    @wraps(_init_)
    def _autoassign(self, *args, **kwargs):
    argnames, _, _, _ = getargspec(_init_)
    for name, value in zip(argnames[1:], args):
    setattr(self, name, value)
    _init_(self, *args, **kwargs)
    return _autoassign
    This is neat. :) Could that maybe be extended to only assign selected
    args to the instance and let others pass unchanged. So that, for instance:

    @autoassign("foo", "bar")
    def __init__(self, foo, bar, baz):
    super(baz)

    ?W
    If one goes back to the original idea instead, the decision of using
    automatic assignment should depend on the signature of the __init__
    function. Here's an implementation (using "_" instead of "." as it
    would lead to a syntax error):

    from functools import *
    from inspect import *

    def autoassign(_init_):
    @wraps(_init_)
    def _autoassign(self, *args, **kwargs):
    argnames, _, _, _ = getargspec(_init_)
    for name, value in zip(argnames[1:], args):
    if name.startswith("_"):
    setattr(self, name[1:], value)
    _init_(self, *args, **kwargs)

    return _autoassign

    class Test(object):
    @autoassign
    def __init__(self, _foo, _bar, baz):
    print 'baz =', baz

    t = Test(1, 2, 3)
    print t.foo
    print t.bar
    print t.baz

    #== the output is

    baz = 3
    1
    2
    Traceback (most recent call last):
    File "/Users/andre/CrunchySVN/branches/andre/src/tools_2k.py", line
    24, in exec_code
    exec code in local_dict
    File "User's code", line 23, in <module>
    AttributeError: 'Test' object has no attribute 'baz'

    #======
    Andr?
  • Terry Reedy at Jan 28, 2008 at 12:13 am
    "Andr?" <andre.roberge at gmail.com> wrote in message
    news:7dcc86da-6ed7-48ec-9a9e-ada5574ae06e at v17g2000hsa.googlegroups.com...
    If one goes back to the original idea instead, the decision of using
    automatic assignment should depend on the signature of the __init__
    function. Here's an implementation (using "_" instead of "." as it
    would lead to a syntax error):

    from functools import *
    from inspect import *

    def autoassign(_init_):
    @wraps(_init_)
    def _autoassign(self, *args, **kwargs):
    argnames, _, _, _ = getargspec(_init_)
    for name, value in zip(argnames[1:], args):
    if name.startswith("_"):
    setattr(self, name[1:], value)
    _init_(self, *args, **kwargs)

    return _autoassign

    class Test(object):
    @autoassign
    def __init__(self, _foo, _bar, baz):
    print 'baz =', baz

    t = Test(1, 2, 3)
    print t.foo
    print t.bar
    print t.baz

    #== the output is

    baz = 3
    1
    2
    Traceback (most recent call last):
    File "/Users/andre/CrunchySVN/branches/andre/src/tools_2k.py", line
    24, in exec_code
    exec code in local_dict
    File "User's code", line 23, in <module>
    AttributeError: 'Test' object has no attribute 'baz'
    =================================

    I think this version, with this name convention, is nice enough to possibly
    go in the stdlib if there were an appropriate place for it. Not sure where
    though. If there were a classtools module....

    tjr
  • Paul McGuire at Jan 28, 2008 at 1:17 am

    On Jan 27, 6:13?pm, "Terry Reedy" wrote:
    I think this version, with this name convention, is nice enough to possibly
    go in the stdlib if there were an appropriate place for it. ?Not sure where
    though. ?If there were a classtools module....

    tjr
    +1

    I thought at one time there was to be a "decorators" module in the
    stdlib for just this kind of useful item. At minimum, you could post
    this to the Python wiki at http://wiki.python.org/moin/PythonDecoratorLibrary.

    -- Paul
  • Christian Heimes at Jan 28, 2008 at 1:37 am

    Paul McGuire wrote:
    I thought at one time there was to be a "decorators" module in the
    stdlib for just this kind of useful item. At minimum, you could post
    this to the Python wiki at http://wiki.python.org/moin/PythonDecoratorLibrary.
    Please take the idea to the Python developer list. Several decorators
    are either already implemented (e.g. the first decorator is
    functools.wraps) and others are too special but some of the decorators
    including auto assignment seem useful.

    Christian
  • Steven D'Aprano at Jan 28, 2008 at 1:47 am
    On Sun, 27 Jan 2008 19:13:27 -0500, Terry Reedy wrote:

    [snip]
    class Test(object):
    @autoassign
    def __init__(self, _foo, _bar, baz):
    print 'baz =', baz [snip]
    I think this version, with this name convention, is nice enough to
    possibly go in the stdlib if there were an appropriate place for it.
    Not sure where though. If there were a classtools module....
    -1/2

    I don't like the name convention. _name already has a perfectly good
    convention: it's a private name, don't mess with it. That includes in
    function/method signatures. With your convention, _foo is public.

    I suppose you could write __foo for a private name, and ___foo for a
    *really* private name, relying on the decorator to strip one of the
    underscores. But counting all those underscores is a PITA, and what
    happens if you don't actually want that private name set as an instance
    attribute?

    As nice as this feature would be, and I vote +2 on the functionality, I
    wonder whether the amount of line noise in method definitions now will be
    approaching Perlish levels? We've got default values, type annotations
    (in Python3), *args and **kwargs, _ private names, and now we want to add
    auto-assignment.

    If we do get syntax support, I vote +1 on &foo, +1/2 on @foo, -1 on .foo
    and -1 on self.foo. (It's explicit, but it's long...).


    --
    Steven
  • Arnaud Delobelle at Jan 28, 2008 at 1:56 am

    On Jan 28, 1:47?am, Steven D'Aprano <st... at REMOVE-THIS- cybersource.com.au> wrote:
    [...]
    As nice as this feature would be, and I vote +2 on the functionality, I
    wonder whether the amount of line noise in method definitions now will be
    approaching Perlish levels? We've got default values, type annotations
    (in Python3), *args and **kwargs, _ private names, and now we want to add
    auto-assignment.
    Don't forget keyword only arguments! I find signatures too
    complicated already, please let's not clutter them even more.

    --
    Arnaud


    From http Mon Jan 28 02:56:46 2008
    From: http (Paul Rubin)
    Date: 27 Jan 2008 17:56:46 -0800
    Subject: optional static typing for Python
    References: <ae8bb60a-0e11-43d2-9275-63a031d474f3@i72g2000hsd.googlegroups.com>
    <0e963ca7-2525-4c74-817f-ed67a48aedf5@i3g2000hsf.googlegroups.com>
    Message-ID: <7xbq76pva9.fsf@ruckus.brouhaha.com>

    Paddy <paddy3118 at googlemail.com> writes:
    I would rather advocate such random test generation methods as being
    more appropriate for testing software in safety critical systems when
    the programming language is dynamic.
    That method totally failed to find the Pentium FDIV bug, and they use
    static proof checkers like ACL2 now.
  • André at Jan 28, 2008 at 2:02 am

    On Jan 27, 9:47 pm, Steven D'Aprano <st... at REMOVE-THIS- cybersource.com.au> wrote:
    On Sun, 27 Jan 2008 19:13:27 -0500, Terry Reedy wrote:

    [snip]
    class Test(object):
    @autoassign
    def __init__(self, _foo, _bar, baz):
    print 'baz =', baz [snip]
    I think this version, with this name convention, is nice enough to
    possibly go in the stdlib if there were an appropriate place for it.
    Not sure where though. If there were a classtools module....
    -1/2

    I don't like the name convention. _name already has a perfectly good
    convention: it's a private name, don't mess with it. That includes in
    function/method signatures. With your convention, _foo is public.

    I suppose you could write __foo for a private name, and ___foo for a
    *really* private name, relying on the decorator to strip one of the
    underscores. But counting all those underscores is a PITA, and what
    happens if you don't actually want that private name set as an instance
    attribute?

    As nice as this feature would be, and I vote +2 on the functionality, I
    wonder whether the amount of line noise in method definitions now will be
    approaching Perlish levels? We've got default values, type annotations
    (in Python3), *args and **kwargs, _ private names, and now we want to add
    auto-assignment.

    If we do get syntax support, I vote +1 on &foo, +1/2 on @foo, -1 on .foo
    and -1 on self.foo. (It's explicit, but it's long...).

    --
    Steven

    Here's a version that
    1. does not require new syntax
    2. does not *necessarily* override the "_" prefix convention
    3. follows the "Explicit is better than implicit" convention when
    being called.

    (Note: I do not necessarily recommend the "self_" choice)
    ========
    from functools import wraps
    from inspect import getargspec

    def autoassign(prefix):
    def _autoassign(_init_):
    @wraps(_init_)
    def __autoassign(self, *args, **kwargs):
    argnames, _, _, _ = getargspec(_init_)
    for name, value in zip(argnames[1:], args):
    if name.startswith(prefix):
    setattr(self, name[len(prefix):], value)
    _init_(self, *args, **kwargs)

    return __autoassign
    return _autoassign

    class Test(object):
    @autoassign('self_')
    def __init__(self, self_foo, self_bar, baz):
    print 'baz =', baz

    t = Test(1, 2, 3)
    print t.foo
    print t.bar
    print t.baz # raises an exception

    =============
    Andr?
  • Gabriel Genellina at Jan 28, 2008 at 4:47 am
    En Sun, 27 Jan 2008 23:51:28 -0200, Arnaud Delobelle
    <arnodel at googlemail.com> escribi?:
    Nice! I've got a slight variation without magic argument names:

    class Test(object):
    @autoassign('foo', 'bar')
    def __init__(self, baz):
    print 'baz =', baz
    En Mon, 28 Jan 2008 00:02:51 -0200, Andr? <andre.roberge at gmail.com>
    escribi?:
    Here's a version that
    1. does not require new syntax
    2. does not *necessarily* override the "_" prefix convention
    3. follows the "Explicit is better than implicit" convention when
    being called.

    class Test(object):
    @autoassign('self_')
    def __init__(self, self_foo, self_bar, baz):
    print 'baz =', baz
    I would like a signature-preserving version. The help system, pydoc, the
    inspect module, and likely any other introspection tool see those
    decorated methods with a different signature than the original one.
    Even if one writes a signature-preserving decorator (maybe along the lines
    of this article by M. Simionato [1]), names like "self_foo", "self_bar"
    are ugly. Furthermore, argument names are part of the public interfase,
    but here they're tied to the implementation: what if later I want to keep
    a reference to baz? I must change the argument name to self_baz, breaking
    all users of the code.

    [1] http://www.phyast.pitt.edu/~micheles/python/documentation.html

    --
    Gabriel Genellina
  • Arnaud Delobelle at Jan 28, 2008 at 12:09 pm

    On Jan 28, 4:47 am, "Gabriel Genellina" wrote:
    En Sun, 27 Jan 2008 23:51:28 -0200, Arnaud Delobelle
    <arno... at googlemail.com> escribi?:
    Nice! I've got a slight variation without magic argument names:
    class Test(object):
    @autoassign('foo', 'bar')
    def __init__(self, baz):
    print 'baz =', baz
    [...]
    I would like a signature-preserving version. The help system, pydoc, the
    inspect module, and likely any other introspection tool see those
    decorated methods with a different signature than the original one.
    Even if one writes a signature-preserving decorator (maybe along the lines
    of this article by M. Simionato [1]), names like "self_foo", "self_bar"
    are ugly. Furthermore, argument names are part of the public interfase,
    but here they're tied to the implementation: what if later I want to keep
    a reference to baz? I must change the argument name to self_baz, breaking
    all users of the code.
    Sligthly improved (not for performance! but signature-preserving and
    looks for default values)

    from functools import wraps
    from inspect import getargspec
    from itertools import izip, chain

    def autoassign(*names):
    def decorator(f):
    fargnames, _, _, fdefaults = getargspec(f)
    defaults = [(n,v) for (n,v)
    in izip(reversed(fargnames), reversed(fdefaults))
    if n in names]
    @wraps(f)
    def decorated(self, *args, **kwargs):
    self.__dict__.update(defaults)
    for name, arg in chain(izip(fargnames, args),
    kwargs.iteritems()):
    if name in names:
    setattr(self, name, arg)
    return f(self, *args, **kwargs)
    return decorated
    return decorator

    class Test(object):
    @autoassign('foo', 'bar')
    def __init__(self, foo, bar=3, baz=6):
    print 'baz =', baz

    t = Test(1, 2, 6)
    u = Test(foo=8)

    print t.foo # 1
    print t.bar # 2

    print u.foo # 8
    print u.bar # 3 (default)

    --
    Arnaud


    print t.baz # AttributeError
  • Steven Bethard at Jan 28, 2008 at 3:45 pm

    Arnaud Delobelle wrote:
    Sligthly improved (not for performance! but signature-preserving and
    looks for default values)

    from functools import wraps
    from inspect import getargspec
    from itertools import izip, chain

    def autoassign(*names):
    def decorator(f):
    fargnames, _, _, fdefaults = getargspec(f)
    defaults = [(n,v) for (n,v)
    in izip(reversed(fargnames), reversed(fdefaults))
    if n in names]
    @wraps(f)
    def decorated(self, *args, **kwargs):
    self.__dict__.update(defaults)
    for name, arg in chain(izip(fargnames, args),
    kwargs.iteritems()):
    if name in names:
    setattr(self, name, arg)
    return f(self, *args, **kwargs)
    return decorated
    return decorator

    class Test(object):
    @autoassign('foo', 'bar')
    def __init__(self, foo, bar=3, baz=6):
    print 'baz =', baz

    t = Test(1, 2, 6)
    u = Test(foo=8)

    print t.foo # 1
    print t.bar # 2

    print u.foo # 8
    print u.bar # 3 (default)
    You should definitely post this to the cookbook:

    http://aspn.activestate.com/ASPN/Cookbook/Python

    STeVe
  • André at Jan 28, 2008 at 4:08 pm

    On Jan 28, 11:45 am, Steven Bethard wrote:
    Arnaud Delobelle wrote:
    Sligthly improved (not for performance! but signature-preserving and
    looks for default values)
    from functools import wraps
    from inspect import getargspec
    from itertools import izip, chain
    def autoassign(*names):
    def decorator(f):
    fargnames, _, _, fdefaults = getargspec(f)
    defaults = [(n,v) for (n,v)
    in izip(reversed(fargnames), reversed(fdefaults))
    if n in names]
    @wraps(f)
    def decorated(self, *args, **kwargs):
    self.__dict__.update(defaults)
    for name, arg in chain(izip(fargnames, args),
    kwargs.iteritems()):
    if name in names:
    setattr(self, name, arg)
    return f(self, *args, **kwargs)
    return decorated
    return decorator
    class Test(object):
    @autoassign('foo', 'bar')
    def __init__(self, foo, bar=3, baz=6):
    print 'baz =', baz
    t = Test(1, 2, 6)
    u = Test(foo=8)
    print t.foo # 1
    print t.bar # 2
    print u.foo # 8
    print u.bar # 3 (default)
    You should definitely post this to the cookbook:

    http://aspn.activestate.com/ASPN/Cookbook/Python

    STeVe
    If I may suggest, I would extend this so that autoassign's signature
    would be as follows:

    autoassign(all=True, include_only=None, exclude=None)

    Either one of include_only or exclude could be a list of function to
    which the automatic assignment would apply (or not). I was planning
    to write this up and submit it to the cookbook later this evening, but
    since the suggestion has been made, someone else can jump on it. ;-)

    Andr?
  • Arnaud Delobelle at Jan 28, 2008 at 7:19 pm
    On Jan 28, 4:08?pm, "Andr?" wrote:
    [...]
    If I may suggest, I would extend this so that autoassign's signature
    would be as follows:

    autoassign(all=True, include_only=None, exclude=None)

    Either one of include_only or exclude could be a list of function to
    which the automatic assignment would apply (or not). ? I was planning
    to write this up and submit it to the cookbook later this evening, but
    since the suggestion has been made, someone else can jump on it. ;-)

    Andr?
    I've modified my little decorator (see Test1, Test2, Test3 for
    usage). I'll post it later on the cookbook if there seems to be no
    bugs and noone raises valid point against it:)

    from functools import wraps
    from inspect import getargspec, isfunction
    from itertools import izip, ifilter, starmap

    def autoassign(*names, **kwargs):
    if kwargs:
    exclude, f = set(kwargs['exclude']), None
    sieve = lambda l:ifilter(lambda nv: nv[0] not in exclude, l)
    elif len(names) == 1 and isfunction(names[0]):
    f = names[0]
    sieve = lambda l:l
    else:
    names, f = set(names), None
    sieve = lambda l: ifilter(lambda nv: nv[0] in names, l)
    def decorator(f):
    fargnames, _, _, fdefaults = getargspec(f)
    # Remove self for fargnames and make sure fdefaults is a tuple
    fargnames, fdefaults = fargnames[1:], fdefaults or ()
    defaults = list(sieve(izip(reversed(fargnames),
    reversed(fdefaults))))
    @wraps(f)
    def decorated(self, *args, **kwargs):
    assigned = dict(sieve(izip(fargnames, args)))
    assigned.update(sieve(kwargs.iteritems()))
    # It would be nice to have a builtin to exhaust iterators:
    for _ in starmap(assigned.setdefault, defaults): pass
    self.__dict__.update(assigned)
    return f(self, *args, **kwargs)
    return decorated
    return f and decorator(f) or decorator

    class Test(object):
    @autoassign('foo', 'bar')
    def __init__(self, foo, bar=3, baz=6):
    print 'baz =', baz

    class Test2(object):
    @autoassign
    def __init__(self, foo, bar): pass

    class Test3(object):
    @autoassign(exclude=('foo', 'bar'))
    def __init__(self, foo, bar, baz=5, **kwargs): pass

    t = Test(1, 2, 5)
    u = Test(foo=8)
    v = Test2(10, 11)
    w = Test3(100, 101, foobar2)

    print t.foo # 1
    print t.bar # 2

    print u.foo # 8
    print u.bar # 3 (default)

    print v.foo, v.bar # 10 11
    print w.baz, w.foobar # 5 102

    for obj, attr in ('w', 'foo'), ('w', 'bar'), ('t', 'baz'):
    try:
    getattr(globals()[obj], attr)
    except AttributeError:
    print '%s.%s raises AttributeError' % (obj, attr)

    ==== output ===baz = 5
    baz = 6
    1
    2
    8
    3
    10 11
    5 102
    w.foo raises AttributeError
    w.bar raises AttributeError
    t.baz raises AttributeError

    --
    Arnaud
  • Tim Chase at Jan 28, 2008 at 10:27 pm

    I've modified my little decorator (see Test1, Test2, Test3 for
    usage). I'll post it later on the cookbook if there seems to be no
    bugs and noone raises valid point against it:)
    One other area that was mentioned obliquely: preservation of
    docstrings (and other function attributes)

    I couldn't tell from your code if it attempted to publish
    function attributes:

    class Foo(object):
    @autoassign
    def __init__(self, alpha, beta, gamma):
    "Do something"
    pass

    f = Foo(3,1,4)
    print f.__init__.__doc__

    I can't say I use doc-strings in __init__ methods often, and I
    suspect the autoassign is only helpful most of the time for
    __init__ methods, but if it's slated for the cookbook,
    completeness would be worth aspiring to.

    -tkc
  • Arnaud Delobelle at Jan 28, 2008 at 10:44 pm

    On Jan 28, 10:27 pm, Tim Chase wrote:
    I've modified my little decorator (see Test1, Test2, Test3 for
    usage). I'll post it later on the cookbook if there seems to be no
    bugs and noone raises valid point against it:)
    One other area that was mentioned obliquely: preservation of
    docstrings (and other function attributes)
    I think @wraps(...) does this (definitely copies __doc__).

    --
    Arnaud
  • Terry Reedy at Jan 29, 2008 at 4:01 am
    "Andr?" <andre.roberge at gmail.com> wrote in message
    news:e82b9c41-935d-45c9-8d7b-6bd3fa7eaae5 at i3g2000hsf.googlegroups.com...
    Here's a version that
    1. does not require new syntax
    2. does not *necessarily* override the "_" prefix convention
    'self_' is way too bulky and intrusive. Putting '_' at the end of the word
    is nearly as easy to detect and conflicts with no convention I know of.

    tjr
  • Coldpizza at Jan 29, 2008 at 11:55 am
    Hi,

    I appreciate everyone's feedback on the topic.

    Having reflected on what has been said here, I now realize that
    creating more complexity is not the way to go. I would rather favor
    something that relies on existing language features, something like
    the default keyword argument assignment in functions.

    This is probably stupid but as a noob I would have liked something
    like:
    def __init__( self. = host, self. = port, self. = timeout, message =
    "Connected."):
    pass

    This is probably even more preposterous than @host, @port, but to me
    it would make more sense.

    I suppose the subject has exhausted itself and I am not going to
    follow it up. If anyone is interested in taking it on, then please do.

    Best,
    coldpizza

    On Jan 29, 6:01 am, "Terry Reedy" wrote:
    "Andr?" <andre.robe... at gmail.com> wrote in message

    news:e82b9c41-935d-45c9-8d7b-6bd3fa7eaae5 at i3g2000hsf.googlegroups.com...
    Here's a version that
    1. does not require new syntax
    2. does not *necessarily* override the "_" prefix convention
    'self_' is way too bulky and intrusive. Putting '_' at the end of the word
    is nearly as easy to detect and conflicts with no convention I know of.

    tjr
  • Terry Reedy at Jan 29, 2008 at 3:58 am
    "Steven D'Aprano" <steve at REMOVE-THIS-cybersource.com.au> wrote in message
    news:13pqd16n4o3rufe at corp.supernews.com...
    I don't like the name convention. _name already has a perfectly good
    convention: it's a private name, don't mess with it. That includes in
    function/method signatures. With your convention, _foo is public.
    Since local names, including params are inaccesible outside a function, I
    don't see how the convention applies. However, the underscore could just
    as well go at the end of the name. There no current convention I know of
    with that.

    tjr
  • Tim Chase at Jan 28, 2008 at 4:30 am

    This is neat. :) Could that maybe be extended to only assign selected
    args to the instance and let others pass unchanged. So that, for instance:

    @autoassign("foo", "bar")
    def __init__(self, foo, bar, baz):
    super(baz)
    I've seen some folks import inspect/functools, but from my
    testing, the __init__ method in question has a .func_code object
    that already has the varnames in it. However, as you suggest, a
    version below allows for named defaults, and letting others go
    un-defaulted. I'm not sure about naming conventions for
    class-style decorators--start with a cap, like a class should
    ("AutoAssign") or because it behaves like a function, use
    "auto_assign", or any of a number of other variants. Anyways...

    class auto_assign(object):
    def __init__(self, *varnames):
    self.args = set(varnames)
    def __call__(self, fn):
    autoassign = self
    def wrapper(self, *args, **kwargs):
    for argname, argvalue in zip(
    fn.func_code.co_varnames[1:],
    args):
    if argname in autoassign.args:
    setattr(self, argname, argvalue)
    for argname in autoassign.args:
    if argname in kwargs:
    setattr(self, argname, kwargs[argname])
    fn(self, *args, **kwargs)
    return wrapper

    class Foo(object):
    @auto_assign('foo', 'baz', 'fred')
    def __init__(self, foo, bar, baz, *args, **kwargs):
    pass

    f = Foo('hello', 42, 3.14, fred='wilma', barney='betty')
    try:
    print f.foo
    except AttributeError:
    print "Could not print f.foo"

    try:
    print f.bar
    except AttributeError:
    print "Could not print f.bar"

    try:
    print f.baz
    except AttributeError:
    print "Could not print f.baz"

    try:
    print f.fred
    except AttributeError:
    print "Could not print f.fred"

    try:
    print f.barney
    except AttributeError:
    print "Could not print f.barney"

    -tkc
  • Arnaud Delobelle at Jan 28, 2008 at 6:44 pm

    On Jan 28, 4:30?am, Tim Chase wrote:
    I've seen some folks import inspect/functools, but from my
    testing, the __init__ method in question has a .func_code object
    that already has the varnames in it.
    in py3k f.func_code gives way to f.__code__, this is why inspect may
    be preferable

    --
    Arnaud
  • Arnaud Delobelle at Jan 28, 2008 at 1:51 am

    On Jan 27, 6:32?pm, "Diez B. Roggisch" wrote:
    Wildemar Wildenburger schrieb:
    Andr? wrote:
    Personally, I like the idea you suggest, with the modification that I
    would use "." instead of "@", as in
    class Server(object):
    ? ? def __init__(self, .host, .port, .protocol, .bufsize, .timeout):
    ? ? ? ? pass
    I like :)
    However, you can probably cook up a decorator for this (not certain, I'm
    not a decorator Guru), which is not that much worse.
    Still, I'd support that syntax (and the general idea.).
    Just for the fun of it, I implemented a decorator:

    from functools import *
    from inspect import *

    def autoassign(_init_):
    ? ? ?@wraps(_init_)
    ? ? ?def _autoassign(self, *args, **kwargs):
    ? ? ? ? ?argnames, _, _, _ = getargspec(_init_)
    ? ? ? ? ?for name, value in zip(argnames[1:], args):
    ? ? ? ? ? ? ?setattr(self, name, value)
    ? ? ? ? ?_init_(self, *args, **kwargs)

    ? ? ?return _autoassign
    Nice! I've got a slight variation without magic argument names:

    def autoassign(*names):
    def decorator(f):
    def decorated(self, *args, **kwargs):
    for name in names:
    setattr(self, name, kwargs.pop(name))
    return f(self, *args, **kwargs)
    return decorated
    return decorator

    class Test(object):
    @autoassign('foo', 'bar')
    def __init__(self, baz):
    print 'baz =', baz

    t = Test(foo=1, bar=2, baz=6)
    # or Test(6, foo=1, bar=2)

    print t.foo
    print t.bar
    print t.baz

    --
    Arnaud
  • Torsten Bronger at Jan 27, 2008 at 6:41 pm
    Hall?chen!

    Wildemar Wildenburger writes:
    Andr? wrote:
    Personally, I like the idea you suggest, with the modification
    that I would use "." instead of "@", as in

    class Server(object):
    def __init__(self, .host, .port, .protocol, .bufsize, .timeout):
    pass
    I like :)

    However, you can probably cook up a decorator for this (not
    certain, I'm not a decorator Guru), which is not that much worse.

    Still, I'd support that syntax (and the general idea.).
    Well, you save one or two lines per class. Not enough in my
    opinion.

    Tsch?,
    Torsten.

    --
    Torsten Bronger, aquisgrana, europa vetus
    Jabber ID: bronger at jabber.org
    (See http://ime.webhop.org for further contact info.)
  • Dustan at Jan 27, 2008 at 11:26 pm

    On Jan 27, 12:41 pm, Torsten Bronger wrote:
    Hall?chen!



    Wildemar Wildenburger writes:
    Andr? wrote:
    Personally, I like the idea you suggest, with the modification
    that I would use "." instead of "@", as in
    class Server(object):
    def __init__(self, .host, .port, .protocol, .bufsize, .timeout):
    pass
    I like :)
    However, you can probably cook up a decorator for this (not
    certain, I'm not a decorator Guru), which is not that much worse.
    Still, I'd support that syntax (and the general idea.).
    Well, you save one or two lines per class. Not enough in my
    opinion.
    Are you referring to the alternate syntax or to the decorator? Either
    way, you could be saving 4 or 5 or more lines, if you have enough
    arguments.
  • Wildemar Wildenburger at Jan 27, 2008 at 11:39 pm

    Dustan wrote:
    Well, you save one or two lines per class. Not enough in my
    opinion.
    Are you referring to the alternate syntax or to the decorator? Either
    way, you could be saving 4 or 5 or more lines, if you have enough
    arguments.
    OK, but then again, every decent IDE should give you the tools to write
    an automation for that. Not that I don't like the idea of
    auto-assignment, but, you know ...

    /W
  • Steven D'Aprano at Jan 28, 2008 at 1:01 am

    On Mon, 28 Jan 2008 00:39:02 +0100, Wildemar Wildenburger wrote:

    Dustan wrote:
    Well, you save one or two lines per class. Not enough in my opinion.
    Are you referring to the alternate syntax or to the decorator? Either
    way, you could be saving 4 or 5 or more lines, if you have enough
    arguments.
    OK, but then again, every decent IDE should give you the tools to write
    an automation for that. Not that I don't like the idea of
    auto-assignment, but, you know ...
    You know, not everybody uses a "decent IDE", by choice or necessity, and
    even if they did, having what is essentially a macro to type for you
    doesn't solve the essential problem that you're writing the same thing
    THREE TIMES instead of once. And then you have to keep it all in sync
    through who knows how many code revisions and refactorings.

    class Parrot(object): # after many revisions...
    def __init__(self, genus, species, variety, name, age, colours,
    wingspan, beaksize, healthstate, language, vocabulary):
    self.wingspan = wingspan
    self.beaksize = beaksize
    self.name = name
    self.age = age
    self.binomial_name = (genus, species)
    self.breed = variety
    self.colour = colour
    self.language = language
    self.state = get_state(healthstate)
    self.words = vocabulary
    self.colors = colours


    What IDE will spot the error(s) in the above?


    Here's another version, assuming syntax support for auto-assignment for
    names starting with an ampersand:

    class Parrot(object): # after many revisions...
    def __init__(self, genus, species, variety, &name, &age, &colours,
    &wingspan, &beaksize, healthstate, &language, vocabulary):
    self.binomial_name = (genus, species)
    self.breed = variety
    self.state = get_state(healthstate)
    self.words = vocabulary

    See how much easier it is to keep the attributes synced with the
    arguments? Don't Repeat Yourself in action.


    I think the biggest minus on this proposal is that it creates new syntax
    that is only meaningful in the __init__ method of a class. "Special cases
    aren't special enough to break the rules." I'd vote for it, but
    conditionally. What should this do?

    def foo(x, y, &z):
    pass

    Create foo.z perhaps?

    --
    Steven
  • MRAB at Jan 28, 2008 at 1:28 am

    On Jan 28, 1:01 am, Steven D'Aprano <st... at REMOVE-THIS- cybersource.com.au> wrote:
    On Mon, 28 Jan 2008 00:39:02 +0100, Wildemar Wildenburger wrote:
    Dustan wrote:
    Well, you save one or two lines per class. Not enough in my opinion.
    Are you referring to the alternate syntax or to the decorator? Either
    way, you could be saving 4 or 5 or more lines, if you have enough
    arguments.
    OK, but then again, every decent IDE should give you the tools to write
    an automation for that. Not that I don't like the idea of
    auto-assignment, but, you know ...
    You know, not everybody uses a "decent IDE", by choice or necessity, and
    even if they did, having what is essentially a macro to type for you
    doesn't solve the essential problem that you're writing the same thing
    THREE TIMES instead of once. And then you have to keep it all in sync
    through who knows how many code revisions and refactorings.

    class Parrot(object): # after many revisions...
    def __init__(self, genus, species, variety, name, age, colours,
    wingspan, beaksize, healthstate, language, vocabulary):
    self.wingspan = wingspan
    self.beaksize = beaksize
    self.name = name
    self.age = age
    self.binomial_name = (genus, species)
    self.breed = variety
    self.colour = colour
    self.language = language
    self.state = get_state(healthstate)
    self.words = vocabulary
    self.colors = colours

    What IDE will spot the error(s) in the above?

    Here's another version, assuming syntax support for auto-assignment for
    names starting with an ampersand:

    class Parrot(object): # after many revisions...
    def __init__(self, genus, species, variety, &name, &age, &colours,
    &wingspan, &beaksize, healthstate, &language, vocabulary):
    self.binomial_name = (genus, species)
    self.breed = variety
    self.state = get_state(healthstate)
    self.words = vocabulary

    See how much easier it is to keep the attributes synced with the
    arguments? Don't Repeat Yourself in action.

    I think the biggest minus on this proposal is that it creates new syntax
    that is only meaningful in the __init__ method of a class. "Special cases
    aren't special enough to break the rules." I'd vote for it, but
    conditionally. What should this do?

    def foo(x, y, &z):
    pass

    Create foo.z perhaps?
    Well, if:

    def __init__(self, &foo):
    pass

    does:

    def __init__(self, foo):
    self.foo = foo

    then:

    def foo(x, y, &z):
    pass

    does:

    def foo(x, y, &z):
    x.z = z

    Don't think that's useful, though...
  • Torsten Bronger at Jan 28, 2008 at 7:04 am
    Hall?chen!

    Dustan writes:
    On Jan 27, 12:41 pm, Torsten Bronger wrote:

    [...]

    Well, you save one or two lines per class. Not enough in my
    opinion.
    Are you referring to the alternate syntax or to the decorator?
    Either way, you could be saving 4 or 5 or more lines, if you have
    enough arguments.
    Mostly, I write them in one or two lines, e.g.

    def __init__(self, id, kind, person, feedname):
    self.id, self.kind, self.person = id, kind, person

    (Sometimes I break after the "=".) Still, I don't think that this
    at-most-once-per-class use case justifies a special syntax (whether
    within the current language or not) that everyone else has to learn,
    too.

    Tsch?,
    Torsten.

    --
    Torsten Bronger, aquisgrana, europa vetus
    Jabber ID: bronger at jabber.org
    (See http://ime.webhop.org for further contact info.)
  • Steven D'Aprano at Jan 28, 2008 at 7:47 am

    On Mon, 28 Jan 2008 08:04:05 +0100, Torsten Bronger wrote:

    Are you referring to the alternate syntax or to the decorator? Either
    way, you could be saving 4 or 5 or more lines, if you have enough
    arguments.
    Mostly, I write them in one or two lines, e.g.

    def __init__(self, id, kind, person, feedname):
    self.id, self.kind, self.person = id, kind, person

    It's not the number of lines that is important, but the amount of
    redundant code, and the amount of redundant code is identical whether you
    write it in one line or three.

    The problem is that instance initialization frequently and regularly
    breaks the principle "Don't Repeat Yourself". Whether you initialize your
    code like this:

    self.id = id
    self.kind = kind
    self.person person

    or like this:

    self.id = id; self.kind = kind; self.person = person

    or like this:

    self.id, self.kind, self.person = id, kind, person

    you are repeating yourself.

    Unfortunately, without syntactical support, I don't think there is any
    easy way to tell the compiler which arguments to auto-initialize and
    which to skip. And Guido rightly is reluctant to create special syntax
    for special cases, and something which happens only in __init__ (and
    maybe __new__?) is certainly a special case.

    That leaves a decorator solution, married with a convention for names.

    Here's a thought... why assume that the convention is a prefix? What
    about a suffix?

    @autoassign
    def __init__(self, spam_, ham_, eggs):
    pass

    A trailing underscore doesn't conflict with the conventions for leading
    underscores. The only conflict is with the convention that if you want a
    name that looks like a reserved word you put an underscore after it.
    Since Python has very few reserved words, and they rarely make good
    argument names, there should be far fewer conflicts with an underscore
    suffix rather than a prefix.


    I'd still prefer compiler support, preferably with a leading & as syntax.
    Since all the work would happen at compile time, it wouldn't effect the
    runtime speed, and it wouldn't lead to any confusion with function
    signatures. The class you get would be exactly the same as if you had
    done the attribute initialization by hand, except the compiler did it.

    That's the ideal solution, but failing that, a decorator solution with a
    trailing _ gets my vote.



    --
    Steven
  • Russ P. at Jan 28, 2008 at 7:56 am

    On Jan 27, 11:47 pm, Steven D'Aprano <st... at REMOVE-THIS- cybersource.com.au> wrote:
    On Mon, 28 Jan 2008 08:04:05 +0100, Torsten Bronger wrote:
    Are you referring to the alternate syntax or to the decorator? Either
    way, you could be saving 4 or 5 or more lines, if you have enough
    arguments.
    Mostly, I write them in one or two lines, e.g.
    def __init__(self, id, kind, person, feedname):
    self.id, self.kind, self.person = id, kind, person
    It's not the number of lines that is important, but the amount of
    redundant code, and the amount of redundant code is identical whether you
    write it in one line or three.

    The problem is that instance initialization frequently and regularly
    breaks the principle "Don't Repeat Yourself". Whether you initialize your
    code like this:

    self.id = id
    self.kind = kind
    self.person person

    or like this:

    self.id = id; self.kind = kind; self.person = person

    or like this:

    self.id, self.kind, self.person = id, kind, person

    you are repeating yourself.

    Unfortunately, without syntactical support, I don't think there is any
    easy way to tell the compiler which arguments to auto-initialize and
    which to skip. And Guido rightly is reluctant to create special syntax
    for special cases, and something which happens only in __init__ (and
    maybe __new__?) is certainly a special case.

    That leaves a decorator solution, married with a convention for names.

    Here's a thought... why assume that the convention is a prefix? What
    about a suffix?

    @autoassign
    def __init__(self, spam_, ham_, eggs):
    pass

    A trailing underscore doesn't conflict with the conventions for leading
    underscores. The only conflict is with the convention that if you want a
    name that looks like a reserved word you put an underscore after it.
    Since Python has very few reserved words, and they rarely make good
    argument names, there should be far fewer conflicts with an underscore
    suffix rather than a prefix.

    I'd still prefer compiler support, preferably with a leading & as syntax.
    Since all the work would happen at compile time, it wouldn't effect the
    runtime speed, and it wouldn't lead to any confusion with function
    signatures. The class you get would be exactly the same as if you had
    done the attribute initialization by hand, except the compiler did it.

    That's the ideal solution, but failing that, a decorator solution with a
    trailing _ gets my vote.

    --
    Steven
    The problem with a trailing underscore is that it creates another
    valid name, so if someone used the name foo_, it would conflict with
    your convention. You need a character that is not part of a valid
    Python identifier or operator, such as &, $, %, @, !, ~, or ^.
  • Torsten Bronger at Jan 28, 2008 at 8:40 am
    Hall?chen!

    Steven D'Aprano writes:
    On Mon, 28 Jan 2008 08:04:05 +0100, Torsten Bronger wrote:

    Are you referring to the alternate syntax or to the decorator? Either
    way, you could be saving 4 or 5 or more lines, if you have enough
    arguments.
    Mostly, I write them in one or two lines, e.g.

    def __init__(self, id, kind, person, feedname):
    self.id, self.kind, self.person = id, kind, person
    It's not the number of lines that is important, but the amount of
    redundant code, and the amount of redundant code is identical
    whether you write it in one line or three.
    I doubt that there is redunancy. Don't be misled by the fact that
    the string "id" appears twice. The expession is minimal in both
    cases. The only difference is that in one case you have the string
    "id" twice, and in the other case you have a special syntax or even
    a new identifier. The information contents is the same.
    The problem is that instance initialization frequently and
    regularly breaks the principle "Don't Repeat Yourself". [...]
    I don't see why. It say "I want *this* parameter be turned into an
    instance variable of the same name". Why is this repeating myself?

    In my opinon, it would be repeating yourself if in *all* __init__s
    you want to have *all* parameters turned into instance variables of
    the same name. However, we all know that sometimes the names should
    be different, or you want to do some trivial transformation before
    the assignment.

    Granted that it's a frequent use case which may justify syntactic
    sugar, but the straightforward solution is so simple that I think a
    new syntax would make the language just slightly more complicated
    without simplifying anything really.
    [...]

    Here's a thought... why assume that the convention is a prefix? What
    about a suffix?

    @autoassign
    def __init__(self, spam_, ham_, eggs):
    pass

    [...] Since Python has very few reserved words, and they rarely
    make good argument names, there should be far fewer conflicts with
    an underscore suffix rather than a prefix.
    I use them rather frequently, and I see them regularly in the
    stdlib, so I think this would cause confusion.
    I'd still prefer compiler support, preferably with a leading & as
    syntax.
    Please, no! ;-) I like that Python tries to avoid hacker
    characters in the code in favour of english words.

    Please bear in mind that it is a frequent use case, so you will have
    it in virtually every __init__ in fresh Python code. I prefer to
    see instance variables be defined in an brain-friendly explicit way
    rather than single characters that hide it.

    Tsch?,
    Torsten.

    --
    Torsten Bronger, aquisgrana, europa vetus
    Jabber ID: bronger at jabber.org
    (See http://ime.webhop.org for further contact info.)
  • Ben Finney at Jan 28, 2008 at 12:49 am

    "Andr?" <andre.roberge at gmail.com> writes:

    Personally, I like the idea you suggest, with the modification that I
    would use "." instead of "@", as in

    class Server(object):
    def __init__(self, .host, .port, .protocol, .bufsize, .timeout):
    pass
    -1.

    That leading dot is too easy to miss when looking over the code.

    --
    \ "Intellectual property is to the 21st century what the slave |
    `\ trade was to the 16th." ?David Mertz |
    _o__) |
    Ben Finney
  • Wildemar Wildenburger at Jan 28, 2008 at 1:13 am

    Ben Finney wrote:
    "Andr?" <andre.roberge at gmail.com> writes:
    Personally, I like the idea you suggest, with the modification that I
    would use "." instead of "@", as in

    class Server(object):
    def __init__(self, .host, .port, .protocol, .bufsize, .timeout):
    pass
    -1.

    That leading dot is too easy to miss when looking over the code.
    class Server(object):
    def __init__(self, self.host, self.port,
    self.protocol, self.bufsize, self.timeout):
    pass

    ?

    /W
  • Russ P. at Jan 28, 2008 at 2:50 am

    On Jan 27, 5:13 pm, Wildemar Wildenburger wrote:
    Ben Finney wrote:
    "Andr?" <andre.robe... at gmail.com> writes:
    Personally, I like the idea you suggest, with the modification that I
    would use "." instead of "@", as in
    class Server(object):
    def __init__(self, .host, .port, .protocol, .bufsize, .timeout):
    pass
    -1.
    That leading dot is too easy to miss when looking over the code.
    class Server(object):
    def __init__(self, self.host, self.port,
    self.protocol, self.bufsize, self.timeout):
    pass

    ?

    /W
    That makes sense to me.

    Come to think of it, why restrict this convention to the constructor?
    Or am I just opening a can of worms?



    From http Mon Jan 28 03:57:53 2008
    From: http (Paul Rubin)
    Date: 27 Jan 2008 18:57:53 -0800
    Subject: py3k feature proposal: field auto-assignment in constructors
    References: <b9df85be-e63a-474c-90f8-06276f5d3c68@d21g2000prf.googlegroups.com>
    <0ebb27f8-eada-489f-b656-99a98c4df143@s8g2000prg.googlegroups.com>
    <87d4rm93l1.fsf@benfinney.id.au>
    <479d2c23$0$25372$9b4e6d93@newsspool4.arcor-online.net>
    Message-ID: <7xhcgyodvy.fsf@ruckus.brouhaha.com>

    Wildemar Wildenburger <lasses_weil at klapptsowieso.net> writes:
    class Server(object):
    def __init__(self, self.host, self.port,
    self.protocol, self.bufsize, self.timeout):
    pass
    ?
    That could temporarily bind those attributes but it shouldn't
    persistently mutate the object.

    How about:

    class Server(object):
    def __init__(self, host, port, protocol, bufsize, timeout):
    self.(host, port, protocol, bufsize, timeout) = \
    host, port, protocol, bufsize, timeout

    That's fairly explicit yet cuts down the total amount of boilerplate.
  • Ben Finney at Jan 28, 2008 at 3:33 am

    "Russ P." <Russ.Paielli at gmail.com> writes:

    On Jan 27, 5:13 pm, Wildemar Wildenburger
    wrote:
    class Server(object):
    def __init__(self, self.host, self.port,
    self.protocol, self.bufsize, self.timeout):
    pass

    ?
    That makes sense to me.
    Not to me. 'self' is a name that doesn't exist until *after* that
    'def' statement is completed; in any other statement, that would mean
    'self.foo' in the same statement would raise a NameError.

    Special-casing it for a function declaration complicates the language
    for little gain: the rules of what is valid when become more
    complicated. Special cases aren't special enough to break the rules.

    --
    \ "I took a course in speed waiting. Now I can wait an hour in |
    `\ only ten minutes." -- Steven Wright |
    _o__) |
    Ben Finney
  • Russ P. at Jan 28, 2008 at 6:31 am

    On Jan 27, 7:33 pm, Ben Finney wrote:
    "Russ P." <Russ.Paie... at gmail.com> writes:
    On Jan 27, 5:13 pm, Wildemar Wildenburger
    wrote:
    class Server(object):
    def __init__(self, self.host, self.port,
    self.protocol, self.bufsize, self.timeout):
    pass
    ?
    That makes sense to me.
    Not to me. 'self' is a name that doesn't exist until *after* that
    'def' statement is completed; in any other statement, that would mean
    'self.foo' in the same statement would raise a NameError.

    Special-casing it for a function declaration complicates the language
    for little gain: the rules of what is valid when become more
    complicated. Special cases aren't special enough to break the rules.

    --
    \ "I took a course in speed waiting. Now I can wait an hour in |
    `\ only ten minutes." -- Steven Wright |
    _o__) |
    Ben Finney
    OK, then how about a special function that could be called from inside
    the constructor (or anywhere else for that matter) to initialize a
    list of data members. For example,

    self.__set__(host, port, protocol, bufsize,
    timeout)

    This would be equivalent to

    self.host = host
    self.port = port
    # etc.

    I'm not sure if that is technically feasible, but it would cut down on
    repetition of names.
  • Ben Finney at Jan 28, 2008 at 8:21 am

    "Russ P." <Russ.Paielli at gmail.com> writes:

    OK, then how about a special function that could be called from
    inside the constructor (or anywhere else for that matter) to
    initialize a list of data members. For example,

    self.__set__(host, port, protocol, bufsize,
    timeout)

    This would be equivalent to

    self.host = host
    self.port = port
    # etc.

    I'm not sure if that is technically feasible, but it would cut down
    on repetition of names.
    It's much more attractive, because it doesn't change the function
    signature. In fact, here's a variation that doesn't even need a
    language change::
    class Foo(object):
    ... def __init__(self, spam, eggs, beans):
    ... self.__dict__.update(dict(
    ... (name, value) for (name, value) in vars().items()
    ... if name in ['spam', 'beans']))
    ...
    foo = Foo("some spam", "more eggs", "other beans")
    foo.spam
    'some spam'
    foo.eggs
    Traceback (most recent call last):
    File "<stdin>", line 1, in ?
    AttributeError: 'Foo' object has no attribute 'eggs'
    foo.beans
    'other beans'

    --
    \ "If consumers even know there's a DRM, what it is, and how it |
    `\ works, we've already failed." ?Peter Lee, Disney corporation, |
    _o__) 2005 |
    Ben Finney
  • Russ P. at Jan 28, 2008 at 9:06 am

    On Jan 28, 12:21 am, Ben Finney wrote:
    "Russ P." <Russ.Paie... at gmail.com> writes:
    OK, then how about a special function that could be called from
    inside the constructor (or anywhere else for that matter) to
    initialize a list of data members. For example,
    self.__set__(host, port, protocol, bufsize,
    timeout)
    This would be equivalent to
    self.host = host
    self.port = port
    # etc.
    I'm not sure if that is technically feasible, but it would cut down
    on repetition of names.
    It's much more attractive, because it doesn't change the function
    signature. In fact, here's a variation that doesn't even need a
    language change::
    class Foo(object):
    ... def __init__(self, spam, eggs, beans):
    ... self.__dict__.update(dict(
    ... (name, value) for (name, value) in vars().items()
    ... if name in ['spam', 'beans']))
    ...
    foo = Foo("some spam", "more eggs", "other beans")
    foo.spam
    'some spam'
    foo.eggs
    Traceback (most recent call last):
    File "<stdin>", line 1, in ?
    AttributeError: 'Foo' object has no attribute 'eggs'
    foo.beans
    'other beans'

    --
    \ "If consumers even know there's a DRM, what it is, and how it |
    `\ works, we've already failed." --Peter Lee, Disney corporation, |
    _o__) 2005 |
    Ben Finney
    If you can wrap that in a clean function that works for every class
    you might have something.
  • Steven D'Aprano at Jan 28, 2008 at 9:06 am

    On Mon, 28 Jan 2008 19:21:48 +1100, Ben Finney wrote:

    In fact, here's a variation that doesn't even need a language
    change::
    class Foo(object):
    ... def __init__(self, spam, eggs, beans):
    ... self.__dict__.update(dict(
    ... (name, value) for (name, value) in \
    ... vars().items() if name in ['spam', 'beans']))
    ...

    You still need to repeat yourself twice. That's 33% better than repeating
    yourself three times, but 100% worse than repeating yourself once.

    Other problems:

    (1) Readability suffers greatly.

    (2) Performance takes a big hit.

    class Parrot(object):
    ... def __init__(self, name, colour, breed):
    ... self.name = name
    ... self.colour = colour
    ... self.breed = breed
    ...
    class Parrot2(object):
    ... def __init__(self, name, colour, breed):
    ... self.__dict__.update(dict((name, value) for
    ... (name, value) in vars().items()
    ... if name in ['name', 'colour', 'breed']))
    ...

    import timeit
    timeit.Timer("Parrot(1, 2, 3)",
    ... "from __main__ import Parrot").repeat()
    [3.3467490673065186, 2.2820541858673096, 2.2934978008270264]
    timeit.Timer("Parrot2(1, 2, 3)",
    ... "from __main__ import Parrot2").repeat()
    [13.148159027099609, 13.015455961227417, 11.936856985092163]



    --
    Steven
  • André at Jan 28, 2008 at 3:18 am

    On Jan 27, 10:57 pm, Paul Rubin wrote:
    Wildemar Wildenburger <lasses_w... at klapptsowieso.net> writes:
    class Server(object):
    def __init__(self, self.host, self.port,
    self.protocol, self.bufsize, self.timeout):
    pass
    ?
    That could temporarily bind those attributes but it shouldn't
    persistently mutate the object.

    How about:

    class Server(object):
    def __init__(self, host, port, protocol, bufsize, timeout):
    self.(host, port, protocol, bufsize, timeout) = \
    host, port, protocol, bufsize, timeout

    That's fairly explicit yet cuts down the total amount of boilerplate.
    Not much; you're still repeating each variable name 3 times. I prefer
    the standard way of one definition per line over this notation
    myself.

    Andr?
  • Paddy at Jan 28, 2008 at 7:13 am

    On Jan 27, 5:06 pm, coldpizza wrote:
    There is a pattern that occurs fairly often in constructors in Python
    and other OOP languages.

    Let's take an example:

    class Server(object):
    def __init__(self, host, port, protocol, bufsize, timeout):
    self.host = host
    self.port = port
    self.protocol = protocol
    self.bufsize = bufsize
    self.maxthreads = maxthreads
    self.timeout = timeout

    Imho, in the class above the assignment to instance fields does not
    contain much programming logic and therefore can be safely 'abstracted
    away' by the language itself with a syntax which would look something
    like this:

    class Server(object):
    def __init__(self, @host, @port, @protocol, @bufsize, @timeout):
    pass

    This would be equivalent to the first example above, yet it does not
    obfuscate the code in any way. Or does it? It does look much cleaner
    to me.

    Of course, the ampersand is just an arbitrary choice and might have
    bad connotations for those who read it as 'take address of' but @ has
    some allusion to delegates which maybe is ok.

    I am not an experienced programmer and I am not sure if this is
    necessarily a good idea, so I wanted to get some feedback from more
    experienced Pythonistas before submitting it elsewhere.
    Is it not possible to write a function that queries its call stack
    when run to find the name of all arguments and locals() of the level
    above so you could write:

    class test(object):
    def __init__(self, x, y):
    arg2inst()

    and automatically assign self.x=x; self.y=y ?

    It could be extended so that...

    class test(object):
    def __init__(self, x, y):
    arg2inst("x")

    ... then only assigns x.


    Has anyone seen something like this in the cookbook?

    - Paddy.

    From http Mon Jan 28 08:21:58 2008
    From: http (Paul Rubin)
    Date: 27 Jan 2008 23:21:58 -0800
    Subject: optional static typing for Python
    References: <ae8bb60a-0e11-43d2-9275-63a031d474f3@i72g2000hsd.googlegroups.com>
    <0e963ca7-2525-4c74-817f-ed67a48aedf5@i3g2000hsf.googlegroups.com>
    <7xbq76pva9.fsf@ruckus.brouhaha.com>
    <f1ae16e3-f9fb-4560-9611-605fa2525a65@e6g2000prf.googlegroups.com>
    <7x1w82xymd.fsf@ruckus.brouhaha.com>
    <aeb1afb2-652f-44df-92a6-85c4ddb254a6@d21g2000prf.googlegroups.com>
    Message-ID: <7xsl0iwh2h.fsf@ruckus.brouhaha.com>

    Paddy <paddy3118 at googlemail.com> writes:
    Fair enough. My main issue was against the notion that random testing
    is the only thing necessary.
    Sorry Paul if I may have given that impression, its just that when you
    bring in random testing to a design that until then had only directed
    tests you can see the bug rate jump up!
    Sure, I agree with that as well, what I should have said was I have an
    issue with the notion that testing (of any sort) is all that is needed
    to reach high assurance. Directed and random tests BOTH failed to
    catch the FDIV bug. You need methods that demonstrate the absence of
    defects, not just fail to demonstrate their presence.
  • Bruno Desthuilliers at Jan 28, 2008 at 5:19 pm
    Paddy a ?crit :
    (snip)
    Is it not possible to write a function that queries its call stack
    when run to find the name of all arguments and locals() of the level
    above
    so you could write:

    class test(object):
    def __init__(self, x, y):
    arg2inst()

    and automatically assign self.x=x; self.y=y ?
    Might be possible using the inspect module. But as far as I'm concerned,
    I'm not sure I really like the idea that much - no rationale here, just
    a feeling...

Related Discussions

People

Translate

site design / logo © 2022 Grokbase