How can I access attributes of a lazy variable class? - python

I've made myself a lazy variable class, and used it in another class. How can I then access the attributes of the lazy variable class? I have tried __getattr__ without luck. Here's an example:
class lazyobject(object):
def __init__(self,varname,something='This is the something I want to access'):
self.varname = varname
self.something = something
def __get__(self, obj, type=None):
if obj.__dict__.has_key(self.varname):
print "Already computed %s" % self.varname
return obj.__dict__[self.varname]
else:
print "computing %s" % self.varname
obj.__dict__[self.varname] = "something else"
return obj.__dict__[self.varname]
class lazyobject2(lazyobject):
def __getattr__(self):
return self.something
class dummy(object):
def __init__(self):
setattr(self.__class__, 'lazy', lazyobject('lazy'))
class dummy2(object):
def __init__(self):
setattr(self.__class__, 'lazy', lazyobject2('lazy'))
d1 = dummy()
d2 = dummy2()
try:
print "d1.lazy.something - no getattr: ",d1.lazy.something
except:
print "d2.lazy is already computed - can't get its .something because it's now a string!"
print "d1.lazy - no getattr: ",d1.lazy
try:
print "d2.lazy.something - has getattr: ",d2.lazy.something
except:
print "d2.lazy is already computed - can't get its .something because it's now a string!"
print "d2.lazy - no getattr: ",d2.lazy
This prints:
d1.lazy.something - no getattr: computing lazy
d2.lazy is already computed - can't get its .something because it's now a string!
d1.lazy - no getattr: something else
d2.lazy.something - has getattr: computing lazy
d2.lazy is already computed - can't get its .something because it's now a string!
d2.lazy - no getattr: something else
What I would like it to print:
d1.lazy.something - no getattr: This is the something I want to access
computing lazy
d1.lazy - no getattr: something else
The above example is contrived but I hope gets the point across. Another way to phrase my question is: How can I bypass the __get__ method when accessing a class attribute?

The way to bypass __get__ when accessing a class attribute is to look it up via the class dictionary rather than using dotted access.
This is easy to demonstrate using function objects. For example:
>>> class A(object):
def f(self):
pass
>>> A.f # dotted access calls f.__get__
<unbound method A.f>
>>> vars(A)['f'] # dict access bypasses f.__get__
<function f at 0x101723500>
>>> a = A()
>>> a.f # dotted access calls f.__get__
<bound method A.f of <__main__.A object at 0x10171e810>>
>>> vars(a.__class__)['f'] # dict access bypasses f.__get__
<function f at 0x101723500>
The other piece of information you were missing is that the inherited __get__ runs before the __getattr__ which only runs if no attribute is found. This logic is controlled by __getattribute__ which is inherited from object. So, if you want to bypass __get__ you will either need to write a new __get__ in the subclass or change the lookup logic by defining __getattribute__ in the subclass.
To fix the lazyobject2 class, replace the __getattr__ with:
class lazyobject2(lazyobject):
def __getattribute__(self, key):
# bypass __get__
return object.__getattribute__(self, '__dict__')[key]
In summary, the key pieces of knowledge used to solve this problem are:
object.__getattribute__ controls the lookup logic.
It first looks for __get__ whether defined in the current class or inherited.
Only if nothing is found, does it attempt to call object.__getattr__.
The above three steps only happen for dotted lookup.
Those step can be bypassed by directly accessing the dict via __dict__ or vars().
The full details of descriptor logic can be found in this writeup or in this presentation.

Related

Python: why visiting an existing attribute triggered "__getattr__"?

I knew that python's __getattr__ is triggered when visiting a non-existing attribute.
But in my example below, inside c1's __init__, I created a self attribute called name. When visiting it, both access ways triggered __getattr__ and thus printed "None".
This is weird to me. I suppose either my understanding or my code has some issue?
$ cat n.py
class c1(object):
def __init__(s):
print 'init c1'
s.name='abc'
def __getattr__(s,name):
print "__getattr__:"+name
return None
def __setattr__(s,name,value):
print "__setattr__:"+value
def __get__(s,inst,owner):
print "__get__"
class d:
def __init__(s):
s.c=c1()
c=c1()
print c.name
o=d()
print o.c.name
$ python n.py
init c1
__setattr__:abc
__getattr__:name
None
init c1
__setattr__:abc
__getattr__:name
None
You can see I've defined s.name='abc' inside __init__, but it is not recognized when calling it.
You also implemented __setattr__, and it is always called when trying to set an attribute. Your version only prints the attribute:
def __setattr__(s,name,value):
print "__setattr__:"+value
and nothing else, which means the attribute is not actually set. The above is called for the s.name='abc' expression, the name attribute is never set, so any future access to the name attribute is sent to __getattr__ again.
Have __setattr__ set the value in __dict__ directly:
def __setattr__(self, name, value):
print "__setattr__:" + value
self.__dict__[name] = value
or make your class a new-style class (inherit from object), and you can re-use the base implementation with super(c1, self).__setattr__(name, value).
As a side note: you implemented c1.__get__, presumably in an attempt to make the class a descriptor object. However, the descriptor protocol only applies to class attributes, not to instance attributes, and then only on new-style classes. Your class d is not a new-style class, and you used an instance attribute c to store the c1 instance.

Instance of Python class that responds to all method calls

Is there a way to create a class which instances respond to arbitrary method calls?
I know there is a the special method __getattr__(self, attr) which would be called when someone is trying to access an attribute of an instance. I am searching for something similar that enables me to intercept method calls, too. The desired behavior would look something like this:
class A(object):
def __methodintercept__(self, method, *args, **kwargs): # is there a special method like this??
print(str(method))
>>> a = A()
>>> a.foomatic()
foomatic
EDIT
The other suggested questions do not address my case: I do not want to wrap another class or change the metaclass of a second class or similar. I just want to have a class that responds to arbitrary method calls.
Thanks to jonrshape I now know that __getattr__(self, attr) will also be called when a method is called in the same way as it would be when an attribute is accessed. But how do i distinguish in __getattr__ if attr comes from a method call or an attribute access and how to get the parameters of a potential method call?
This is something I came up with, which will behave exactly as if the method exists.
First let's establish one thing: You cannot distinguish in __getattr__ if attr comes from a function call or an "attribute access", because a class method is an attribute of your class. So someone can access that method even if they don't intend to call it, as in:
class Test:
def method(self):
print "Hi, I am method"
>> t = Test()
>> t.method # just access the method "as an attribute"
<bound method Test.method of <__main__.Test instance at 0x10a970c68>>
>> t.method() # actually call the method
Hi, I am method
Therefore, the closest thing I could think of is this behavior:
Create a class A, such that:
When we try to access an attribute / method, which already exists in that class, act normal and just return the requested attribute / method.
When we try to access something that doesn't exist in the class definition, treat it as a class method and have 1 global handler for all such methods.
I will first write the class definition and then show how accessing a method that doesn't exist behaves exactly like accessing one that exists, whether you are just accessing it, or actually calling it.
Class definition:
class A(object):
def __init__(self):
self.x = 1 # set some attribute
def __getattr__(self,attr):
try:
return super(A, self).__getattr__(attr)
except AttributeError:
return self.__get_global_handler(attr)
def __get_global_handler(self, name):
# Do anything that you need to do before simulating the method call
handler = self.__global_handler
handler.im_func.func_name = name # Change the method's name
return handler
def __global_handler(self, *args, **kwargs):
# Do something with these arguments
print "I am an imaginary method with name %s" % self.__global_handler.im_func.func_name
print "My arguments are: " + str(args)
print "My keyword arguments are: " + str(kwargs)
def real_method(self, *args, **kwargs):
print "I am a method that you actually defined"
print "My name is %s" % self.real_method.im_func.func_name
print "My arguments are: " + str(args)
print "My keyword arguments are: " + str(kwargs)
I added the method real_method just so I have something that actually exists in the class to compare its behavior with that of an 'imaginary method'
Here's the result:
>> a = A()
>> # First let's try simple access (no method call)
>> a.real_method # The method that is actually defined in the class
<bound method A.real_method of <test.A object at 0x10a9784d0>>
>> a.imaginary_method # Some method that is not defined
<bound method A.imaginary_method of <test.A object at 0x10a9784d0>>
>> # Now let's try to call each of these methods
>> a.real_method(1, 2, x=3, y=4)
I am a method that you actually defined
My name is real_method
My arguments are: (1, 2)
My keyword arguments are: {'y': 4, 'x': 3}
>> a.imaginary_method(1, 2, x=3, y=4)
I am an imaginary method with name imaginary_method
My arguments are: (1, 2)
My keyword arguments are: {'y': 4, 'x': 3}
>> # Now let's try to access the x attribute, just to make sure that 'regular' attribute access works fine as well
>> a.x
1
unittest.mock.Mock does this by default.
from unittest.mock import Mock
a = Mock()
a.arbitrary_method() # No error
a.arbitrary_method.called # True
a.new_method
a.new_method.called # False
a.new_method("some", "args")
a.new_method.called # True
a.new_method.assert_called_with("some", "args") # No error
a.new_method_assert_called_with("other", "args") # AssertionError
This is the solution I was looking for when coming across this question:
class Wrapper:
def __init__(self):
self._inner = [] # or whatever type you want to wrap
def foo(self, x):
print(x)
def __getattr__(self, attr):
if attr in self.__class__.__dict__:
return getattr(self, attr)
else:
return getattr(self._inner, attr)
t = Test()
t.foo('abc') # prints 'abc'
t.append('x') # appends 'x' to t._inner
Criticisms very welcome. I wanted to add methods to the Browser class in the Splinter package, but it only exposes a function to return an instance, not the class itself. This approach permitted pseudo-inheritance, which meant I could declaratively decouple DOM code from website-specific code. (A better approach in hindsight might have been to use Selenium directly.)
Method calls aren't any different from attribute access. __getattr__() or __getattribute__() is the way to respond to arbitrary attribute requests.
You cannot know if the access comes from "just retrieval" or "method call".
It works like this: first, attribute retrieval, then, call on the retrieved object (in Python, call is just another operator: anything can be called and will throw an exception if it isn't callable). One doesn't, and shouldn't, know about the other (well, you can analyze the code up the call stack, but that's totally not the thing to do here).
One of the reasons is - functions are first-class objects in Python, i.e. a function (or, rather, a reference to it) is no different from any other data type: I can get the reference, save it and pass it around. I.e. there's completely no difference between requesting a data field and a method.
Elaborate on what you need this for for us to suggest a better solution.
E.g., if you need the "method" to be able to be called with different signatures, *args and **kwargs is the way to go.
The follow will respond to all undefined method calls:
class Mock:
def __init__(self, *args, **kwargs):
pass
def __getattr__(self, attr):
def func(*args, **kwargs):
pass
return func
Or just use unittest.mock.Mock.

Difference between calling a method and accessing an attribute

I'm very new to Python, and I'm using Python 3.3.1.
class Parent: # define parent class
parentAttr = 100
age = 55
def __init__(self):
print ("Calling parent constructor")
def setAttr(self, attr):
Parent.parentAttr = attr
class Child(Parent):
def childMethod(self):
print ('Calling child method')
Now I'll create
c=child
c.[here every thing will appear methods and attr (age,setAttr)]
How can I distinguish between methods and atrributes? I mean, when do I use c.SetAtrr(Argument), and c.SetAtrr=value?
Methods are attributes too. They just happen to be callable objects.
You can detect if an object is callable by using the callable() function:
>>> def foo(): pass
...
>>> callable(foo)
True
>>> callable(1)
False
When you call a method, you look up the attribute (a getattr() operation) and then call the result:
c.setAttr(newvalue)
is two steps; finding the attribute (which in this case looks up the attribute on the class, and treats it as a descriptor), then calls the resulting object, a method.
When you assign to an attribute, you rebind that name to a new value:
c.setAttr = 'something else'
would be a setattr() operation.
If you wanted to intercept getting and setting attributes on instances of your class, you could provide the attribute access hooks, __getattr__, __setattr__ and __delattr__.
If you wanted to add a method to an instance, you would have to treat the function as a descriptor object, which produces a method object:
>>> class Foo: pass
...
>>> foo = Foo() # instance
>>> def bar(self): pass
...
>>> bar
<function bar at 0x10b85a320>
>>> bar.__get__(foo, Foo)
<bound method Foo.bar of <__main__.Foo instance at 0x10b85b830>>
The return value of function.__get__(), when given an instance and a class, is a bound method. Calling that method will call the underlying function with self bound to the instance.
And speaking of descriptors, the property() function returns a descriptor too, making it possible to have functions that behave like attributes; they can intercept the getattr(), setattr() and delattr() operations for just that attribute and turn it into a function call:
>>> class Foo:
... #property
... def bar(self):
... return "Hello World!"
...
>>> foo = Foo()
>>> foo.bar
"Hello World!"
Accessing .bar invoked the bar property get hook, which then calls the original bar method.
In almost all situations, you are not going to need the callable() function; you document your API, and provide methods and attributes and the user of your API will figure it out without testing each and every attribute to see if it is callable. With properties, you have the flexibility of providing attributes that are really callables in any case.

Why is getattr() not working like I think it should? I think this code should print 'sss'

the next is my code:
class foo:
def __init__(self):
self.a = "a"
def __getattr__(self,x,defalut):
if x in self:
return x
else:return defalut
a=foo()
print getattr(a,'b','sss')
i know the __getattr__ must be 2 argument,but i want to get a default attribute if the attribute is no being.
how can i get it, thanks
and
i found if defined __setattr__,my next code is also can't run
class foo:
def __init__(self):
self.a={}
def __setattr__(self,name,value):
self.a[name]=value
a=foo()#error ,why
hi alex,
i changed your example:
class foo(object):
def __init__(self):
self.a = {'a': 'boh'}
def __getattr__(self, x):
if x in self.a:
return self.a[x]
raise AttributeError
a=foo()
print getattr(a,'a','sss')
it print {'a': 'boh'},not 'boh'
i think it will print self.a not self.a['a'], This is obviously not want to see
why ,and Is there any way to avoid it
Your problem number one: you're defining an old-style class (we know you're on Python 2.something, even though you don't tell us, because you're using print as a keyword;-). In Python 2:
class foo:
means you're defining an old-style, aka legacy, class, whose behavior can be rather quirky at times. Never do that -- there's no good reason! The old-style classes exist only for compatibility with old legacy code that relies on their quirks (and were finally abolished in Python 3). Use new style classes instead:
class foo(object):
and then the check if x in self: will not cause a recursive __getattr__ call. It will however cause a failure anyway, because your class does not define a __contains__ method and therefore you cannot check if x is contained in an instance of that class.
If what you're trying to do is whether x is defined in the instance dict of self, don't bother: __getattr__ doesn't even get called in that case -- it's only called when the attribute is not otherwise found in self.
To support three-arguments calls to the getattr built-in, just raise AttributeError in your __getattr__ method if necessary (just as would happen if you had no __getattr__ method at all), and the built-in will do its job (it's the built-in's job to intercept such cases and return the default if provided). That's the reason one never ever calls special methods such as __getattr__ directly but rather uses built-ins and operators which internally call them -- the built-ins and operators provide substantial added value.
So to give an example which makes somewhat sense:
class foo(object):
def __init__(self):
self.blah = {'a': 'boh'}
def __getattr__(self, x):
if x in self.blah:
return self.blah[x]
raise AttributeError
a=foo()
print getattr(a,'b','sss')
This prints sss, as desired.
If you add a __setattr__ method, that one intercepts every attempt to set attributes on self -- including self.blah = whatever. So -- when you need to bypass the very __setattr__ you're defining -- you must use a different approach. For example:
class foo(object):
def __init__(self):
self.__dict__['blah'] = {}
def __setattr__(self, name, value):
self.blah[name] = value
def __getattr__(self, x):
if x in self.blah:
return self.blah[x]
raise AttributeError
a=foo()
print getattr(a,'b','sss')
This also prints sss. Instead of
self.__dict__['blah'] = {}
you could also use
object.__setattr__(self, 'blah', {})
Such "upcalls to the superclass's implementation" (which you could also obtain via the super built-in) are one of the rare exceptions to the rules "don't call special methods directly, call the built-in or use the operator instead" -- here, you want to specifically bypass the normal behavior, so the explicit special-method call is a possibility.
You are confusing the getattr built-in function, which retrieves some attribute binding of an object dynamically (by name), at runtime, and the __getattr__ method, which is invoked when you access some missing attribute of an object.
You can't ask
if x in self:
from within __getattr__, because the in operator will cause __getattr__ to be invoked, leading to infinite recursion.
If you simply want to have undefined attributes all be defined as some value, then
def __getattr__(self, ignored):
return "Bob Dobbs"

storing classmethod reference in tuple does not work as in variable

#!/usr/bin/python
class Bar(object):
#staticmethod
def ruleOn(rule):
if isinstance(rule, tuple):
print rule[0]
print rule[0].__get__(None, Foo)
else:
print rule
class Foo(object):
#classmethod
def callRule(cls):
Bar.ruleOn(cls.RULE1)
Bar.ruleOn(cls.RULE2)
#classmethod
def check(cls):
print "I am check"
RULE1 = check
RULE2 = (check,)
Foo.callRule()
Output:
<bound method type.check of <class '__main__.Foo'>>
<classmethod object at 0xb7d313a4>
<bound method type.check of <class '__main__.Foo'>>
As you can see I'm trying to store a reference to a classmethod function in a tuple for future use.
However, it seems to store the object itself rather then reference to the bound function.
As you see it works for a variable reference.
The only way to get it is to use __get__, which requires the name of the class it belongs to, which is not available at the time of the RULE variable assignment.
Any ideas anyone?
This is because method are actually functions in Python. They only become bound methods when you look them up on the constructed class instance. See my answer to this question for more details. The non-tuple variant works because it is conceptually the same as accessing a classmethod.
If you want to assign bound classmethods to class attributes you'll have to do that after you construct the class:
class Foo(object):
#classmethod
def callRule(cls):
Bar.ruleOn(cls.RULE1)
Bar.ruleOn(cls.RULE2)
#classmethod
def check(cls):
print "I am check"
Foo.RULE1 = Foo.check
Foo.RULE2 = (Foo.check,)

Categories

Resources