hasattr + __getattr__: I think this is Python bug

Discussion in 'Python' started by dmitrey, Jul 20, 2010.

  1. dmitrey

    dmitrey Guest

    hi all,
    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, when I invoke in other code part "hasattr(myObject, 'size')",
    instead o returning True/False it goes to __getattr__ and starts
    constructor for another one oofun, that wasn't intended behaviour.
    Thus "hasattr(myObject, 'size')" always returns True. It prevents me
    of some bonuses and new features to be done in FuncDesigner.

    >>> 'size' in dir(b)

    False
    >>> hasattr(b,'size')

    True
    >>> 'size' in dir(b)

    True

    Could you fix it?
     
    dmitrey, Jul 20, 2010
    #1
    1. Advertising

  2. dmitrey

    Chris Rebert Guest

    On Tue, Jul 20, 2010 at 3:10 AM, dmitrey <> wrote:
    > hi all,
    > 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, when I invoke in other code part "hasattr(myObject, 'size')",
    > instead o returning True/False it goes to __getattr__ and starts
    > constructor for another one oofun, that wasn't intended behaviour.
    > Thus "hasattr(myObject, 'size')" always returns True. It prevents me
    > of some bonuses and new features to be done in FuncDesigner.
    >
    >>>> 'size' in dir(b)

    > False
    >>>> hasattr(b,'size')

    > True
    >>>> 'size' in dir(b)

    > True
    >
    > Could you fix it?


    There's probably some hackery you could do to check whether hasattr()
    is in the call stack, and then not dynamically create the attribute in
    __getattr__ if that's the case, but that's obviously quite kludgey.

    /Slightly/ less hackish: Replace hasattr() in the __builtin__ module
    with your own implementation that treats instances of FuncDesigner
    specially.

    Least ugly suggestion: Just don't use hasattr(); use your `x in
    dir(y)` trick instead.

    > Subject: [...] I think this is Python bug

    Nope, that's just how hasattr() works. See
    http://docs.python.org/library/functions.html#hasattr (emphasis mine):
    """
    hasattr(object, name)
    The arguments are an object and a string. The result is True if
    the string is the name of one of the object’s attributes, False if
    not. (***This is implemented by calling getattr(object, name)*** and
    seeing whether it raises an exception or not.)
    """

    I suppose you could argue for the addition of a __hasattr__ special
    method, but this seems like a really rare use case to justify adding
    such a method (not to mention the language change moratorium is still
    currently in effect).

    Cheers,
    Chris
    --
    http://blog.rebertia.com
     
    Chris Rebert, Jul 20, 2010
    #2
    1. Advertising

  3. dmitrey

    dmitrey Guest

    On Jul 20, 1:37 pm, Chris Rebert <> wrote:
    > On Tue, Jul 20, 2010 at 3:10 AM, dmitrey <> wrote:
    > > hi all,
    > > 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, when I invoke in other code part "hasattr(myObject, 'size')",
    > > instead o returning True/False it goes to __getattr__ and starts
    > > constructor for another one oofun, that wasn't intended behaviour.
    > > Thus "hasattr(myObject, 'size')" always returns True. It prevents me
    > > of some bonuses and new features to be done in FuncDesigner.

    >
    > >>>> 'size' in dir(b)

    > > False
    > >>>> hasattr(b,'size')

    > > True
    > >>>> 'size' in dir(b)

    > > True

    >
    > > Could you fix it?

    >
    > There's probably some hackery you could do to check whether hasattr()
    > is in the call stack, and then not dynamically create the attribute in
    > __getattr__ if that's the case, but that's obviously quite kludgey.


    It's too unreliable solution, hasattr may or may not appear in stack
    wrt different cases

    > /Slightly/ less hackish: Replace hasattr() in the __builtin__ module
    > with your own implementation that treats instances of FuncDesigner
    > specially.


    It's too unreliable as well

    > Least ugly suggestion: Just don't use hasattr(); use your `x in
    > dir(y)` trick instead.


    something in dir() consumes O(n) operations for lookup, while hasattr
    or getattr() require O(log(n)). It matters for me, because it's inside
    deeply nested mathematical computations FuncDesigner is made for.

    >
    > > Subject: [...] I think this is Python bug

    >
    > Nope, that's just how hasattr() works. Seehttp://docs.python.org/library/functions.html#hasattr(emphasis mine):
    > """
    > hasattr(object, name)
    >     The arguments are an object and a string. The result is True if
    > the string is the name of one of the object’s attributes, False if
    > not. (***This is implemented by calling getattr(object, name)*** and
    > seeing whether it raises an exception or not.)
    > """


    Thus I believe this is very ugly implementation. Some code implemented
    via "__getattr__" can start to execute arbitrary Python code, that is
    certainly not desired behaviour "hasattr" was designed for (to perform
    a check only), and it's too hard to reveal the situations, that makes
    a potential holes for viruses etc.

    Moreover, the implementation via "try getattr(object, name)" slowers
    code evaluation, I wonder why it is implemented so.

    >
    > I suppose you could argue for the addition of a __hasattr__ special
    > method, but this seems like a really rare use case to justify adding
    > such a method (not to mention the language change moratorium is still
    > currently in effect).


    I think much more easier solution would be to implement an additional
    argument to hasattr, e.g. hasattr(obj, field,
    onlyLookupInExistingFields = {True/False}). I think by default it's
    better set to True, now it behaves like False.

    D.
     
    dmitrey, Jul 20, 2010
    #3
  4. dmitrey wrote:
    > hi all,
    > 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, when I invoke in other code part "hasattr(myObject, 'size')",
    > instead o returning True/False it goes to __getattr__ and starts
    > constructor for another one oofun, that wasn't intended behaviour.
    > Thus "hasattr(myObject, 'size')" always returns True. It prevents me
    > of some bonuses and new features to be done in FuncDesigner.
    >
    >
    >>>> 'size' in dir(b)
    >>>>

    > False
    >
    >>>> hasattr(b,'size')
    >>>>

    > True
    >
    >>>> 'size' in dir(b)
    >>>>

    > True
    >
    > Could you fix it?
    >


    Quite simple, when calling b.size, return the computed value but do not
    set it as attribute, the value will be computed on each b.size call, and
    hasattr w. If you don't want to compute it each time, cause there no
    reason for it to change, use a private dummy attribute to record the
    value instead of size (__size for instance) and return the value of
    __size when getting the value of size.


    class Foo(object):
    def __init__(self):
    self.__size = None

    def __getattr__(self, name):
    if name == "size":
    if self.__size is None:
    self.__size = 5 # compute the value
    return self.__size
    raise AttributeError(name)

    b = Foo()
    print 'size' in dir(b)
    print hasattr(b, 'size')
    print 'size' in dir(b)

    False
    True
    False

    JM
     
    Jean-Michel Pichavant, Jul 20, 2010
    #4
  5. dmitrey

    dmitrey Guest

    On 20 июл, 15:00, Jean-Michel Pichavant <>
    wrote:
    > dmitrey wrote:
    > > hi all,
    > > 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, when I invoke in other code part "hasattr(myObject, 'size')",
    > > instead o returning True/False it goes to __getattr__ and starts
    > > constructor for another one oofun, that wasn't intended behaviour.
    > > Thus "hasattr(myObject, 'size')" always returns True. It prevents me
    > > of some bonuses and new features to be done in FuncDesigner.

    >
    > >>>> 'size' in dir(b)

    >
    > > False

    >
    > >>>> hasattr(b,'size')

    >
    > > True

    >
    > >>>> 'size' in dir(b)

    >
    > > True

    >
    > > Could you fix it?

    >
    > Quite simple, when calling b.size, return the computed value but do not
    > set it as attribute, the value will be computed on each b.size call, and
    > hasattr w. If you don't want to compute it each time, cause there no
    > reason for it to change, use a private dummy attribute to record the
    > value instead of size (__size for instance) and return the value of
    > __size when getting the value of size.
    >
    > class Foo(object):
    >     def __init__(self):
    >         self.__size = None
    >
    >     def __getattr__(self, name):
    >         if name == "size":
    >             if self.__size is None:
    >                 self.__size = 5 # compute the value
    >             return self.__size
    >         raise AttributeError(name)
    >
    > b = Foo()
    > print 'size' in dir(b)
    > print hasattr(b, 'size')
    > print 'size' in dir(b)
    >
    > False
    > True
    > False
    >
    > JM


    This doesn't stack with the following issue: sometimes user can write
    in code "myObject.size = (some integer value)" and then it will be
    involved in future calculations as ordinary fixed value; if user
    doesn't supply it, but myObject.size is involved in calculations, then
    the oofun is created to behave like similar numpy.array attribute.
     
    dmitrey, Jul 20, 2010
    #5
  6. dmitrey

    dmitrey Guest

    > e.g. one that just looks in the object's dictionary so as to avoid returning true for properties or other such fancy attributes.

    So can anyone explain me how to look into object's dict? As I have
    wrote, "something in dir(...)" requires O(numOfFields) while I would
    like to use o(log(n))

    >How about using a property instead of the __getattr__() hook? A property is a computed attribute that (among other things) plays much nicer with hasattr.


    Could anyone provide an example of it to be implemented, taking into
    account that a user can manually set "myObject.size" to an integer
    value?
     
    dmitrey, Jul 20, 2010
    #6
  7. dmitrey

    Neil Cerutti Guest

    On 2010-07-20, dmitrey <> wrote:
    > This doesn't stack with the following issue: sometimes user can
    > write in code "myObject.size = (some integer value)" and then
    > it will be involved in future calculations as ordinary fixed
    > value; if user doesn't supply it, but myObject.size is involved
    > in calculations, then the oofun is created to behave like
    > similar numpy.array attribute.


    Telling them, "Don't do that," is a good solution in Python.

    --
    Neil Cerutti
     
    Neil Cerutti, Jul 20, 2010
    #7
  8. dmitrey

    dmitrey Guest

    On 20 июл, 18:39, Neil Cerutti <> wrote:
    > On 2010-07-20, dmitrey <> wrote:
    >
    > > This doesn't stack with the following issue: sometimes user can
    > > write in code "myObject.size = (some integer value)" and then
    > > it will be involved in future calculations as ordinary fixed
    > > value; if user doesn't supply it, but myObject.size is involved
    > > in calculations, then the oofun is created to behave like
    > > similar numpy.array attribute.

    >
    > Telling them, "Don't do that," is a good solution in Python.
    >
    > --
    > Neil Cerutti


    But this is already documented feature, and it works as intended, so
    moving it into something like "myObject._size" will bring backward
    incompatibility and break all FuncDesigner user API and style, where
    no underlines are present, it will seem like a hack that it really
    is.

    Sometimes apriory knowing size value as fixed integer brings some code
    speedup, also, if a user supplies the value, a check for computed
    value wrt the provided size is performed each time.
     
    dmitrey, Jul 20, 2010
    #8
  9. dmitrey wrote:
    > On 20 июл, 15:00, Jean-Michel Pichavant <>
    > wrote:
    >
    >> dmitrey wrote:
    >>
    >>> hi all,
    >>> 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, when I invoke in other code part "hasattr(myObject, 'size')",
    >>> instead o returning True/False it goes to __getattr__ and starts
    >>> constructor for another one oofun, that wasn't intended behaviour.
    >>> Thus "hasattr(myObject, 'size')" always returns True. It prevents me
    >>> of some bonuses and new features to be done in FuncDesigner.
    >>>
    >>>>>> 'size' in dir(b)
    >>>>>>
    >>> False
    >>>
    >>>>>> hasattr(b,'size')
    >>>>>>
    >>> True
    >>>
    >>>>>> 'size' in dir(b)
    >>>>>>
    >>> True
    >>>
    >>> Could you fix it?
    >>>

    >> Quite simple, when calling b.size, return the computed value but do not
    >> set it as attribute, the value will be computed on each b.size call, and
    >> hasattr w. If you don't want to compute it each time, cause there no
    >> reason for it to change, use a private dummy attribute to record the
    >> value instead of size (__size for instance) and return the value of
    >> __size when getting the value of size.
    >>
    >> class Foo(object):
    >> def __init__(self):
    >> self.__size = None
    >>
    >> def __getattr__(self, name):
    >> if name == "size":
    >> if self.__size is None:
    >> self.__size = 5 # compute the value
    >> return self.__size
    >> raise AttributeError(name)
    >>
    >> b = Foo()
    >> print 'size' in dir(b)
    >> print hasattr(b, 'size')
    >> print 'size' in dir(b)
    >>
    >> False
    >> True
    >> False
    >>
    >> JM
    >>

    >
    > This doesn't stack with the following issue: sometimes user can write
    > in code "myObject.size = (some integer value)" and then it will be
    > involved in future calculations as ordinary fixed value; if user
    > doesn't supply it, but myObject.size is involved in calculations, then
    > the oofun is created to behave like similar numpy.array attribute.
    >

    Here are some solutions in my humble order of preference:
    1/ ask the user to always fill the size field
    2/ ask the user to never fill the size filed (you can override
    __setattr__ to make sure...)
    3/ override __setattr__ to set __size instead of size

    JM
     
    Jean-Michel Pichavant, Jul 20, 2010
    #9
  10. dmitrey

    Robert Kern Guest

    On 7/20/10 6:59 AM, dmitrey wrote:
    > On Jul 20, 1:37 pm, Chris Rebert<> wrote:


    >> Least ugly suggestion: Just don't use hasattr(); use your `x in
    >> dir(y)` trick instead.

    >
    > something in dir() consumes O(n) operations for lookup, while hasattr
    > or getattr() require O(log(n)). It matters for me, because it's inside
    > deeply nested mathematical computations FuncDesigner is made for.


    I'm not sure where you are getting log(n) from, but regardless, if you have so
    many attributes that the O() matters more than the constant, you have more
    problems than this.

    --
    Robert Kern

    "I have come to believe that the whole world is an enigma, a harmless enigma
    that is made terrible by our own mad attempt to interpret it as though it had
    an underlying truth."
    -- Umberto Eco
     
    Robert Kern, Jul 20, 2010
    #10
  11. dmitrey

    Robert Kern Guest

    On 7/20/10 11:39 AM, dmitrey wrote:
    >> e.g. one that just looks in the object's dictionary so as to avoid returning true for properties or other such fancy attributes.

    >
    > So can anyone explain me how to look into object's dict? As I have
    > wrote, "something in dir(...)" requires O(numOfFields) while I would
    > like to use o(log(n))


    ('size' in obj.__dict__) is O(1) with a pretty low constant.

    --
    Robert Kern

    "I have come to believe that the whole world is an enigma, a harmless enigma
    that is made terrible by our own mad attempt to interpret it as though it had
    an underlying truth."
    -- Umberto Eco
     
    Robert Kern, Jul 20, 2010
    #11
  12. dmitrey a écrit :
    (snip)

    > This doesn't stack with the following issue: sometimes user can write
    > in code "myObject.size = (some integer value)" and then it will be
    > involved in future calculations as ordinary fixed value; if user
    > doesn't supply it, but myObject.size is involved in calculations, then
    > the oofun is created to behave like similar numpy.array attribute.


    IOW, you want a default value for the size if it has not been specified
    by the user, so you can safely use this attribute in computations. The
    more straightforward solution is to define this attribute (with the
    default value) in the initialiser, ie:


    class MyClass(object):
    def __init__(self, x, y):
    self.x = x
    self.y = y
    self.size = Whatever()


    If you don't want to create as many Whatever instances as MyClass
    instances, you can create a single Whatever instance before defining
    your class:

    DEFAULT_WHATEVER = Whathever()

    class MyClass(object):
    def __init__(self, x, y):
    self.x = x
    self.y = y
    self.size = DEFAULT_WHATEVER


    HTH
     
    Bruno Desthuilliers, Jul 26, 2010
    #12
  13. Duncan Booth a écrit :
    > Bruno Desthuilliers <> wrote:
    >
    >> If you don't want to create as many Whatever instances as MyClass
    >> instances, you can create a single Whatever instance before defining
    >> your class:
    >>
    >> DEFAULT_WHATEVER = Whathever()
    >>
    >> class MyClass(object):
    >> def __init__(self, x, y):
    >> self.x = x
    >> self.y = y
    >> self.size = DEFAULT_WHATEVER
    >>
    >>

    >
    > 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.
     
    Bruno Desthuilliers, Jul 26, 2010
    #13
  14. dmitrey

    Ethan Furman Guest

    Bruno Desthuilliers wrote:
    > Duncan Booth a écrit :
    >> Bruno Desthuilliers <> wrote:
    >>
    >>> If you don't want to create as many Whatever instances as MyClass
    >>> instances, you can create a single Whatever instance before defining
    >>> your class:
    >>>
    >>> DEFAULT_WHATEVER = Whathever()
    >>>
    >>> class MyClass(object):
    >>> def __init__(self, x, y):
    >>> self.x = x
    >>> self.y = y
    >>> self.size = DEFAULT_WHATEVER
    >>>
    >>>

    >>
    >> 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?

    ~Ethan~
     
    Ethan Furman, Jul 26, 2010
    #14
  15. 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?



    Now it's Tuesday !-)


    Ok, let's see:

    Python 2.6.2 (release26-maint, Apr 19 2009, 01:56:41)
    [GCC 4.3.3] on linux2
    Type "help", "copyright", "credits" or "license" for more information.
    >>> class Foo(object):

    .... whatever = Foo()
    ....
    Traceback (most recent call last):
    File "<stdin>", line 1, in <module>
    File "<stdin>", line 2, in Foo
    NameError: name 'Foo' is not defined
    >>>
     
    Bruno Desthuilliers, Jul 27, 2010
    #15
  16. 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.
     
    Bruno Desthuilliers, Jul 27, 2010
    #16
  17. dmitrey

    Ethan Furman Guest

    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.

    To phrase it another way, why does your solution (Bruno) work, but
    Duncan's "obviously won't"?

    ~Ethan~
     
    Ethan Furman, Jul 27, 2010
    #17
  18. 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.
     
    Bruno Desthuilliers, Jul 28, 2010
    #18
  19. dmitrey

    Ethan Furman Guest

    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~
     
    Ethan Furman, Jul 28, 2010
    #19
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Dragos Chirila

    private class members and hasattr

    Dragos Chirila, Jan 23, 2004, in forum: Python
    Replies:
    2
    Views:
    362
    Erik Max Francis
    Jan 23, 2004
  2. Brian Roberts

    Confused about hasattr/getattr/namespaces

    Brian Roberts, Feb 29, 2004, in forum: Python
    Replies:
    2
    Views:
    318
    Bob Ippolito
    Feb 29, 2004
  3. Gil Tal
    Replies:
    0
    Views:
    484
    Gil Tal
    Aug 24, 2005
  4. Replies:
    0
    Views:
    647
  5. ian

    style question - hasattr

    ian, Apr 9, 2008, in forum: Python
    Replies:
    2
    Views:
    551
    Miles
    Apr 9, 2008
Loading...

Share This Page