hasattr + __getattr__: I think this is Python bug

Ethan Furman ethan at stoneleaf.us
Wed Jul 28 12:59:01 EDT 2010


Bruno Desthuilliers wrote:
> Ethan Furman a écrit :
>> Bruno Desthuilliers wrote:
>>> Bruno Desthuilliers a écrit :
>>>> Ethan Furman a écrit :
>>>>> Bruno Desthuilliers wrote:
>>>>>> Duncan Booth a écrit :
>>>> (snip)
>>>>
>>>>>>> Or you could create the default as a class attribute 
>>>>>>
>>>>>> from the OP:
>>>>>> """
>>>>>> I have a class (FuncDesigner oofun) that has no attribute "size", but
>>>>>> it is overloaded in __getattr__, so if someone invokes
>>>>>> "myObject.size", it is generated (as another oofun) and connected to
>>>>>> myObject as attribute.
>>>>>> """
>>>>>>
>>>>>> so this solution won't obviously work in this case !-)
>>>>>>
>>>>>> Also and FWIW, I wouldn't advocate this solution if the "default" 
>>>>>> class attribute is of a mutable type.
>>>>>
>>>>> Well, it is Monday, so I may be missing something obvious, but what 
>>>>> is the effective difference between these two solutions?
>>>>
>>>
>>> If you meant "what is the difference between creating the "whatever" 
>>> attribute with a default value in the initializer and creating it on 
>>> demand in the __getattr__ hook", the main difference is that in the 
>>> first case, the instance is garanteed to have this attribute, so you 
>>> get rid of "hasattr" checks (and the unwanted side effects) or, 
>>> worse, direct check of the instance __dict__. Except for a couple of 
>>> corner case, client code shouldn't have to worry about this kind of 
>>> things - this breaks encapsulation.
>>
>> Yay Tuesday!  :D
>>
>> What I meant was what is the difference between:
>>
>> [Bruno Desthuilliers]
>>  > DEFAULT_WHATEVER = Whathever()
>>  > class MyClass(object):
>>  >      def __init__(self, x, y):
>>  >          self.size = DEFAULT_WHATEVER
>>
>> and
>>
>> [Duncan Booth]
>>  > class MyClass(object):
>>  >     size = Whatever()
>>  >     def __init__(self, x, y):
>>  >         ...
>>
>> in both cases the object ends up with a size attribute and no further 
>> need of __getattr__. Of course, the warning about having a mutable 
>> object as a class attribute stands.
> 
> Indeed.
> 
>> To phrase it another way, why does your solution (Bruno) work, but 
>> Duncan's "obviously won't"?
> 
> As it is written (and assuming the name "Whatever" is bound to a 
> callable !-)), Duncan's code would work, even if it might not be the 
> safest solution in the case of a mutable type.
> 
> The problem here is that the OP stated that the "size" attribute was to 
> be of the same type as the host class, so the code would look something 
> like:
> 
> class MyClass(object):
>     size = MyClass()
> 
> which will raise a NameError, since MyClass is not yet defined when 
> "size=MyClass()" is executed.

Ah ha!  I *knew* I was missing something.  Thank you for the 
explanation.  So the correct methods, then, would be to either include 
the size attribute in the __init__, or add it to the class /after/ the 
class was defined.

I feel much better now... slightly silly, but better.  ;)

~Ethan~



More information about the Python-list mailing list