string formatting with mapping & '*'... is this a bug?
Bengt Richter
bokr at oz.net
Sat Sep 11 00:15:32 EDT 2004
On Fri, 10 Sep 2004 23:39:26 +0200, aleaxit at yahoo.com (Alex Martelli) wrote:
>Pierre Fortin <pfortin at pfortin.com> wrote:
> ...
>> > > self.__dict__.update(locals())
>> >
>> > Ah, sorry, my favourite idiom to avoid the boilerplate of
>> >
>> > def __init__(self, fee, fie, foo, fum):
>> > self.fee = fee
>> > self.fie = fie
>> > self.foo = foo
>> > self.fum = fum
>> >
>> > Boilerplate is bad, and I'm keen on "Once, and ONLY once!" as a
>> > programming practice, so having to mention each of those names three
>> > times in totally repetitive ways makes me shiver. My favourite idiom
>>
>> I fully agree with "once and ONLY once"... but you've pointed out that
>> "not-at-all is better than once"... :^)
>
>Well, there is 'once' here -- the names of the attributes are listed
>once, in the argument list of 'def __init__'
>
>> > does, per se, leave a silly self.self around (which means a silly
>> > reference loop) so I should remember to 'del self.self' after it...
>>
>> Since "self" is a convention (could use "this"), t'would be nice if Python
>> could avoid foo.foo ref. loops in a future release...
>
>I don't see how to do that cleanly, simply and within general rules.
>"Special cases are not special enough to break the rules"...
>
You could use a helper function to strip out the name, which you know
anyway if you know to write this.__dict__ or self.__dict__, e.g.,
>>> def updd(firstname, locd):
... sansfirst = locd.copy()
... del sansfirst[firstname]
... locd[firstname].__dict__.update(sansfirst)
...
>>> class C(object):
... def __init__(a1,a2,a3): updd('a1',locals())
...
>>> c=C(2,3)
>>> vars(c)
{'a3': 3, 'a2': 2}
The locd.copy etc could be replaced by not using update. Actually, you could
probably inherit from a class with a metaclass that would let you write
just def __init__(a1, a2, a3): pass and have all the methods' __init__s
appropriately modified.
BTW, do you know offhand why somedict.update(obj) seems to use obj.keys() and
obj.__getitem__ if obj has object as base, but not if it has dict as base?
Ran into that trying to wrap locals() to filter out self or whatever:
>>> class D(dict):
... def keys(self): return [1,2,3]
... def __getitem__(self, key): return 2*key
...
>>> dd = D({'a':123})
>>> dd.keys()
[1, 2, 3]
>>> dd[5]
10
>>> dd
{'a': 123}
>>> d={}
>>> d.update(dd)
>>> d
{'a': 123}
Ok, now this:
>>> class E(object):
... def keys(self): return [1,2,3]
... def __getitem__(self, key): return 2*key
... def __init__(self, *a): print a
...
>>> ee = E({'a':123})
({'a': 123},)
>>> ee.keys()
[1, 2, 3]
>>> ee[3]
6
>>> ee
<__main__.E object at 0x009C72F0>
>>> e={}
>>> e.update(ee)
>>> e
{1: 2, 2: 4, 3: 6}
The methods are there and do override the keys and __getitem__ of dict:
>>> dd.keys(), ee.keys()
([1, 2, 3], [1, 2, 3])
>>> dd[5], ee[5]
(10, 10)
But that d.update(dd) doesn't match what you'd think from
----
>>> help({}.update)
Help on built-in function update:
update(...)
D.update(E) -> None. Update D from E: for k in E.keys(): D[k] = E[k]
----
I see
>>> D.mro()
[<class '__main__.D'>, <type 'dict'>, <type 'object'>]
>>> E.mro()
[<class '__main__.E'>, <type 'object'>]
Is there another method that update looks for first that serves update better
than keys() and __getitem__ so it ignores the latter? Presumably a method that
dict would have but not object?
ISTM I recall a similar problem with some builtin functions not calling overriding
subclass methods as one might expect?
Regards,
Bengt Richter
More information about the Python-list
mailing list