Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python lazy attributes that don't eval on hasattr()

Is it possible to make a decorator that makes attributes lazy that do not eval when you try to access it with hasattr()? I worked out how to make it lazy, but hasattr() makes it evaluate prematurely. E.g.,

class lazyattribute:
    # Magic.

class A:
    @lazyattribute
    def bar(self):
      print("Computing")
      return 5

>>> a = A()
>>> print(a.bar)
'Computing'
5
>>> print(a.bar)
5
>>> b = A()
>>> hasattr(b, 'bar') 
'Computing'
5
# Wanted output: 5
like image 861
Tim Dumol Avatar asked Aug 17 '09 07:08

Tim Dumol


2 Answers

It may be difficult to do. From the hasattr documentation:

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.)

Since attributes may be generated dynamically by a __getattr__ method, there's no other way to reliably check for their presence. For your special situation, maybe testing the dictionaries explicitly would be enough:

any('bar' in d for d in (b.__dict__, b.__class__.__dict__))
like image 116
orip Avatar answered Nov 19 '22 14:11

orip


What nobody seems to have addressed so far is that perhaps the best thing to do is not to use hasattr(). Instead, go for EAFP (Easier to Ask Forgiveness than Permission).

try:
    x = foo.bar
except AttributeError:
    # what went in your else-block
    ...
else:
    # what went in your if hasattr(foo, "bar") block
    ...

This is obviously not a drop-in replacement, and you might have to move stuff around a bit, but it's possibly the "nicest" solution (subjectively, of course).

like image 30
Devin Jeanpierre Avatar answered Nov 19 '22 15:11

Devin Jeanpierre