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

Bengt Richter bokr at oz.net
Mon Jul 4 04:50:07 CEST 2005


On Sun, 03 Jul 2005 22:07:30 GMT, Ron Adam <rrr at ronadam.com> wrote:

>Bengt Richter wrote:
>
>> What if parameter name syntax were expanded to allow dotted names as binding
>> targets in the local scope for the argument or default values? E.g.,
>> 
>>     def foometh(self, self.x=0, self.y=0): pass
>> 
>> would have the same effect as
>> 
>>     def foometh(self, self.y=0, self.x=0): pass
>> 
>> and there would be a persistent effect in the attributes of self
>> (whatever object that was), even with a body of pass.
>> 
>> I'm not sure about foo(self, **{'self.x':0, 'self.y':0}), but if
>> you didn't capture the dict with a **kw formal parameter, IWT you'd
>> have to be consistent and effect the attribute bindings implied.
>> 
>> (Just a non-thought-out bf here, not too serious ;-)
>> 
>> Regards,
>> Bengt Richter
>
>Well it works the other way around to some degree.
>
>def foo(self, x=x, y=y):pass
>
>x=x binds the class variables to the arguments without the self. if no 
>value is given.

>
>Which is kind of strange, since x by it self gives an error if no value 
>is given.  The strange part is x=x is not the same as just x.  I 
>understand why, but it still looks odd.
ISTM you are comparing apples to oranges, execution-wise. The def in the
context of a class definition is executed as soon as you get to the end
of the class suite. The execution happens in a special name space similar
to what happens when you execute a function suite by calling the function,
except the class definition body is executed automatically.

When you write def foo(self, x=x): ... the second x is looked up
starting in the local excution namespace of the class body, so it finds
class variables, if they are defined, otherwise it looks for an outer
scope x for the value.

Note that order counts:

 >>> class Foo(object):
 ...     def foo(self, x=x): print x
 ...     x = 123
 ...
 Traceback (most recent call last):
   File "<stdin>", line 1, in ?
   File "<stdin>", line 2, in Foo
 NameError: name 'x' is not defined
 >>> class Foo(object):
 ...     x = 123
 ...     def foo(self, x=x): print x
 ...
 >>> Foo().foo()
 123

Note that self.x is a different access mechanism, and would access the
same Foo.x that became a default value, but the value is the only thing
they have in common. You could extract the function from the class,
and the plain function would still have the default value:

 >>> bar = Foo.foo.im_func
 >>> bar('ignored self param')
 123
 >>> import dis
 >>> dis.dis(bar)
   3           0 LOAD_FAST                1 (x)
               3 PRINT_ITEM
               4 PRINT_NEWLINE
               5 LOAD_CONST               0 (None)
               8 RETURN_VALUE
 >>> import inspect
 >>> inspect.getargspec(bar)
 (['self', 'x'], None, None, (123,))

There's where the default value is. It's put there when x=x is evaluated
during the def execution for the function, which happens to have happened
courtesy of a class body execution defining the class, but that's
the only connection the 123 has.

>
>
>Why isn't there a dict method to get a sub dict from a key list? 
>Fromkeys doesn't quite do it.
>
>    sub-dict = dict.subdict(key_list)
>
>Or have dict.copy() take a key list. (?)
>
><Just a thought.>
sub_dict = dict([(key, srcdct[key]) for key in srcdct]) #untested, should work
(if you don't use 'dict' for a variable ;-)
>
>
>
>The following works and doesn't seem too obscure, although the x=x, 
>etc.. could be annoying if they were a lot of long names.
>
>Seems like mutable default arguments is what's needed to make it work, 
>not that it's needed IMO.  But it's an interesting problem.
>
>
>def subdict(dict, keys):
>     d = {}
>     for k in keys:
>         d[k] = dict[k]
>     return d
>
>class foo(object):
>     x = 1
>     y = 2
>     z = 3
>     def __init__(self,x=x,y=y,z=z):
>         save_these = subdict(locals(),['x','y'])
>         self.__dict__.update(save_these)
          self.__dict__.update({'x':x, 'y':y, 'z':z}) # should work without save_these
>
>         # rest of code
>         print self.x, self.y, self.z
>
>f = foo()
>f = foo(5,6,7)
>
>

Regards,
Bengt Richter



More information about the Python-list mailing list