Proposal: reducing self.x=x; self.y=y; self.z=z boilerplate code

Rob Williscroft rtw at freenet.co.uk
Mon Jul 11 23:28:12 CEST 2005


Ralf W. Grosse-Kunstleve wrote in
news:mailman.1616.1121111515.10512.python-list at python.org in
comp.lang.python: 

> --- Robert Williscroft <rtw at freenet.co.uk> wrote:
> 
>> My apologies for having to resort to email but for some reason I
>> can't post this message to comp.lang.python. I've tried about 4 times
>> including starting a
>> new thread, but for some reason it doesn't turn up, though I've
>> followed up on
>> another thread without problem.
> 
> Very strange. I hope it is not a conspiracy! :)
> You can email to the list directly (that's what I am doing):
> 
>   python-list at python.org
> 

I'll follow up and post this, and then see what happens :).

>>  > Is there a way out with Python as-is?
>>  > -------------------------------------
>>  >
>>  > Yes. If you take the time to look at the file in the CVS you'll
>>  > find that I was cheating a bit. To reduce the terrible clutter
>>  > above, I am actually using a simple trick::
>>  >
>>  >     adopt_init_args(self, locals())
>>  >
>> 
>> Also there is a decorator solution:
>> 
>> def init_self( init ):
>>     vn = init.func_code.co_varnames[ 1 : init.func_code.co_argcount ]
>>    
>>     def decorated_init(self, *args, **kw):
>>         off = 0
>>         for name in vn:
>>             if not name.startswith('_'):
>>                 if name in kw:
>>                     value = kw[name]
>>                 else:
>>                     value = args[off]
>>                     off += 1
>>                    
>>                 setattr( self, name, value )
>>            
>>         init( self, *args, **kw )
>>     return decorated_init
>>                
>> 
>> class MyClass(object):
>>     __slots__ = ['x', 'z']
>> 
>>     @init_self
>>     def __init__( self, x, _y, z ):
>>         pass
>> 
>>     def show( self ):
>>         for i in self.__slots__:
>>             print 'self.%s = %d' %(i,eval('self.%s' % (i,)))
>> 
>> MyClass( 1, 2, 3 ).show()
>> 
>> MyClass( z = 1, x = 2, _y = 3 ).show()
>> 
>> The __slots__ is in the test just because you mentioned you like it,
>> the decorator doesn't need a "slots" class.
>> 
>> AFAICT this differs from your proposal in that in your proposal you
>> want to use '.' as an include prefix the above uses '_' as an exclude
>> prefix.
>> 
>> Rob.
> 
> I like the looks of the decorator approach a lot. Could this somehow
> be enhanced such that the user doesn't have to know about the
> underscore? 

The underscore is just there so there is a way of having arguments
that aren't added as attributes to the first object, so if that isn't
required it could just be omited.

Also AIUI (the above is my first attempt to write a decorator), 
decorators can have arguments so the decorator could take an
"omit_prefix" argument, so the user could specify there own prefix.

Or maybe have an include prefix, say "self_", if thats what you prefer.

Personaly I'm happy with the underscore, 1 leading underscore at
module scope means hide the name, 2 at class scope means hide the
name, so I kinda like that an undersore is used to omit an argument.

> Thinking about runtime efficiency, could the decorator
> approach somehow achieve that the attribute-to-be arguments are never
> added to locals()? 
> 

Again AIUI, locals() is an inbuild that constructs a dict of the local
arguments and variables, IOW the dict doesn't exist *until* you call
locals().

Wether or not the fact the decorator doesn't call locals() makes any
difference though I don't know, the real arguments will get passed
to decorated_init() in some way and then setattr()'d to the self object.

But then again there is a loop, 2 if's and a lookup of the keyword 
dictionary in there, using this as it stands is going to hurt compared
to doing the asignments manually inside __init__(), though
as I haven't timed it, I could be wrong ;-).

Rob.
-- 
http://www.victim-prime.dsl.pipex.com/



More information about the Python-list mailing list