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.
> 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:
> 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
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)
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'
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 ...
"André" <andre.robe...@gmail.com> wrote in message
news:7dcc86da-6ed7-48ec-9a9e-ada5574ae06e@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)
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....
"André" <andre.robe...@gmail.com> writes: > Personally, I like the idea you suggest, with the modification that I > would use "." instead of "@", as in
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:
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?
On Jan 27, 6:13 pm, "Terry Reedy" <tjre...@udel.edu> 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.
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.
> 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?
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.
> 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...).
On Jan 28, 1:47 am, Steven D'Aprano <st...@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.
> > 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)
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
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"