Understanding __getattribute__ - python

class Shadow(object):
pass
class Test(object):
a = 1
b = 2
_shadow = Shadow()
def __getattribute__(self, name):
try:
return object.__getattribute__(self._shadow, name)
except: print "not shadowed"
return object.__getattribute__(self, name)
With the above piece of code I would like to implement the following behavior:
>>>t = Test()
>>>t.a
1
>>>t._shadow.a = 17
>>>t.a
17
>>>t.b
2
The code works, but it will print "not shadowed" M-times (until recursion depth is reached). The question is why, there shouldn't be any recursion involved, I'm calling object.__getattribute__ and not self.__getattribute__.

__getattribute__ is called for all attribute access, including for self._shadow. But since you have __getattribute__ overridden, self._shadow triggers an infinite recursion.
The only work-around for that is to use object.__getattribute__, or better, super(Test, self).__getattribute__, to retrieve the _shadow attribute:
class Test(object):
a = 1
b = 2
_shadow = Shadow()
def __getattribute__(self, name):
shadow = super(Test, self).__getattribute__('_shadow')
try:
return getattr(shadow, name)
except AttributeError:
print "not shadowed"
return super(Test, self).__getattribute__(name)
There is no need to use object.__getattribute__ for the attribute access on the shadow object. Don't use Pokemon-style exception handling (you don't want to catch them all); catch only the specific AttributeError exception here.
Demo:
>>> t = Test()
>>> t.a
not shadowed
1
>>> t._shadow.a = 42
not shadowed
>>> t.a
42
Note that here too, accessing t._shadow triggers the 'not shadowed' message as it goes through the __getattribute__ handler.

Related

Non-inheritable method in python

Suppose I have two classes, one inheriting from the other :
class A():
def __init__(self):
pass
def doSomething(self):
print('It Works !') # Insert actual code here
class B(A):
pass
How do I make the doSomething method impossible to inherit, so that :
( I want to make the error happen )
>>> a = A()
>>> a.doSomething()
'It Works !'
>>> b = B()
>>> b.doSomething()
Traceback (most recent call last):
File "<pyshell#132>", line 1, in <module>
b.doSomething()
AttributeError: 'B' object has no attribute 'doSomething'
To the best of my knowledge, there is no builtin way to do this in Python, because it is not really considered part of the Python philosophy. There can define "protected" and "private" methods in Python by prepending a single _ or double __, but you can still call those, it's just discouraged.
One very hacky way to achieve something similar might be to make the method itself "private" and have __getattr__ redirect to that method, but only if the object is really an A.
class A():
def __init__(self):
pass
def __doSomething(self):
print('It Works !')
def __getattr__(self, attr):
if attr == "doSomething":
if type(self) == A:
return self.__doSomething
else:
raise TypeError("Nope")
return super(A).__getattr__(self, attr)
But this could still be circumvented by calling the "private" method directly as _A__doSomething or overwriting __getattr__ in B.
Alternatively, possibly safer and probably simpler (but still pretty hacky IMHO), you could also add that check to doSomething itself.
def doSomething(self):
if type(self) != A:
raise TypeError("Nope")
print('It Works !')
You should question whether you want to have a non-inheritable part in the first place. It would be more typical to abstract out the common parts of A and B into a common parent, or use a mixin pattern.
class Parent
def doCommonThing1
def doCommonThing2
/ \
/ \
/ \
/ \
class A class B
def doSomething def doOtherThing
If you insist that B must be a subclass of A, then the only way to "uninherit" a method is to override it to do something else. For example, a property which raises attribute error is for all practical purposes the same as a missing attribute:
>>> class A:
... def doSomething(self):
... print("it works")
...
>>> class B(A):
... #property
... def doSomething(self):
... msg = "{!r} object has no attribute 'doSomething'"
... raise AttributeError(msg.format(type(self).__name__))
...
>>> A().doSomething()
it works
>>> hasattr(B(), "doSomething")
False
>>> B().doSomething()
...
AttributeError: 'B' object has no attribute 'doSomething'

Python __getattribute__ fallbacks to __getattr__

I have a situation, where getattribute fallbacks to getattr and then again getattribute gets called.
How current getattribute gets called again? I am confused.
class Count(object):
def __init__(self,mymin,mymax):
self.mymin=mymin
self.mymax=mymax
self.current=None
def __getattr__(self, item):
print("akhjhd")
self.__dict__[item]=0
return 0
def __getattribute__(self, item):
print("this is called first")
if item.startswith('cur'):
print("this raised an error")
raise AttributeError
print("This will execute as well")
return object.__getattribute__(self,item)
obj1 = Count(1,10)
print(obj1.mymin)
print(obj1.mymax)
print(obj1.current)
Console Output:
this is called first
This will execute as well
1
this is called first
This will execute as well
10
this is called first
this raised an error
akhjhd
this is called first
This will execute as well
0
getattr is called because getattribute raises AttributeError
self.__dict__ invokes the "second" call to getattribute
Clean the code and add print(item) to make this clearer:
class Count(object):
def __init__(self):
self.current = None
def __getattr__(self, item):
print("in getattr")
self.__dict__[item] = 0
return 0
def __getattribute__(self, item):
print(item)
print("in __getattribute__ 1")
if item.startswith('cur'):
print("starts with 'cur'")
raise AttributeError
print("in __getattribute__ 2")
return object.__getattribute__(self, item)
obj1 = Count()
print(obj1.current)
Outputs
current
in __getattribute__ 1
starts with 'cur'
in getattr
__dict__
in __getattribute__ 1
in __getattribute__ 2
0
You need to consult with python Data model
Excerpts for __getattribute__:
Called unconditionally to implement attribute accesses for instances of the class. If the class also defines __getattr__(), the latter will not be called unless __getattribute__() either calls it explicitly or raises an AttributeError.
I see in your code:
if item.startswith('cur'):
print("this raised an error")
raise AttributeError
So I think you did it intentionally

How to prevent AttributeError for undeclared variables and methods and fix __getattr__ method call multiple times?

class Foo(object):
def __init__(self):
self.a = 1
self.c = 0
def __getattr__(self, name):
self.c += 1
print('getattribute')
if hasattr(self, name) is False:
print("No")
return None
return super(Foo, self).__getattr__(self, name)
fo = Foo()
print(fo.a)
print(fo.b)
print(fo.c)
Running the above programs prints "getattribute" and "no" multiple times. __getattr__ is called multiple times. 333 to be exact. self.c prints 333.
What I want to achieve is to have a class that doesn't raise an error if a class variable or method is not declared in the class.
Whats the possible reason for this?
hasattr just tries to get the attribute and returns False if it can’t. Whether it can’t is determined in Python 3 by an attempt throwing an AttributeError, and in Python 2 by an attempt throwing any error. (This includes RecursionErrors and is why it fails silently after 333 calls. Python 2 is not a sane language; upgrade to 3 if possible.)
Instead, you can return the alternative value on an AttributeError yourself:
def __getattr__(self, name):
try:
return super(Foo, self).__getattr__(self, name)
except AttributeError:
return None
This can potentially hide other AttributeErrors, but it’s difficult to avoid doing that just by the nature of Python.
hasattr is a shortcut to call getattr and see if it raises an exception (which means attribute does not exist) or not (which means it exists)
cf : https://docs.python.org/3/library/functions.html#hasattr
getattr calls __getattr__ so you are doing a recursive call
I think a possible workaround would be to use:
name in self.__dict__
instead of:
hasattr(self, name)
This is because running hasattr(self, name) calls self.__getattr__(name) (aka getattr(self, name)) - reference.
So when doing hasattr(self, name) within __getattr__ it calls self.__getattr__(name), here comes the unwanted recursion.
I would fix it with:
class Foo(object):
def __init__(self):
self.a = 1
self.c = 0
def __getattr__(self, name):
self.__dict__['c'] += 1
print('getattribute')
try:
return self.__dict__[name]
except KeyError:
print('No')
return None
fo = Foo()
print(fo.a)
print(fo.b)
print(fo.c)
The problem comes from print(fo.b).
Since b is not defined as a member of Foo, fo.b results in a call to fo.__getattr__('b').
Then, hasattr(self, name), which is tantamount to hasattr(fo, 'b') calls itself gettatr(fo, 'b'), as stated in hte documentation.
Hence an infinite recursion, resulting in a RecursionError in Python 3.
Since getting fo.b does not really make sense if you know that Foo does not have a b member, a first fix I would suggest is to define that member.
class Foo(object):
def __init__(self):
...
self.b = 1
...
Your code then outputs
1
1
0
A more clever fix would be to check if the name argument passed to __getattr__ is 'b', or depending to your needs, different from 'a' and 'c'.
In this situation, you can force __getattr__ to define the requested unfound member.
class Foo(object):
...
def __getattr__(self, name):
if name == 'b':
self.b = 2
return self.b
else:
...
Alternatively:
class Foo(object):
...
def __getattr__(self, name):
if name not in ('a', 'c'):
self.b = 2
return self.b
else:
...

Can Python classes have members that are accessible, but not from an instance of the class?

So I don't come from a computer science background and I am having trouble googling/SO searching on the right terms to answer this question. If I have a Python class with a class variable objects like so:
class MyClass(object):
objects = None
pass
MyClass.objects = 'test'
print MyClass.objects # outputs 'test'
a = MyClass()
print a.objects # also outputs 'test'
both the class and instances of the class will have access to the objects variable. I understand that I can change the instance value like so:
a.objects = 'bar'
print a.objects # outputs 'bar'
print MyClass.objects # outputs 'test'
but is it possible to have a class variable in Python that is accessible to users of the class (i.e. not just from within the class) but not accessible to the instances of that class? I think this is called a private member or static member in other languages?
Python is designed to allow instances of a class to access that class's attributes through the instance.
This only goes one level deep, so you can use a metaclass:
class T(type):
x = 5
class A(object):
__metaclass__ = T
Note that the metaclass syntax is different in Python 3. This works:
>>> A.x
5
>>> A().x
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'A' object has no attribute 'x'
It doesn't prevent you setting the attribute on instances of the class, though; to prevent that you'd have to play with __setattr__ magic method:
class A(object):
x = 1
def __getattribute__(self, name):
if name == 'x':
raise AttributeError
return super(A, self).__getattribute__(name)
def __setattr__(self, name, value):
if name == 'x':
raise AttributeError
return super(A, self).__setattr__(name, value)
def __delattr__(self, name):
if name == 'x':
raise AttributeError
return super(A, self).__delattr__(name)
The simplest way of achieving it is to use a descriptor. Descriptors are the thing meant for giving a higher level of control over attribute access. For example:
class ClassOnly(object):
def __init__(self, name, value):
self.name = name
self.value = value
def __get__(self, inst, cls):
if inst is not None:
msg = 'Cannot access class attribute {} from an instance'.format(self.name)
raise AttributeError(msg)
return self.value
class A(object):
objects = ClassOnly('objects', [])
Used as:
In [11]: a = A()
In [12]: a.objects
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-12-24afc67fd0ba> in <module>()
----> 1 a.objects
<ipython-input-9-db6510cd313b> in __get__(self, inst, cls)
5 def __get__(self, inst, cls):
6 if inst is not None:
----> 7 raise AttributeError('Cannot access class attribute {} from an instance'.format(self.name))
8 return self.value
AttributeError: Cannot access class attribute objects from an instance
In [13]: A.objects
Out[13]: []
If you want there to be a "single source of truth" for objects, you could make it a mutable type:
class MyClass(object):
objects = []
With immutable types, the fact that each instance starts out with the same reference from MyClass is irrelevant, as the first time that attribute is changed for the instance, it becomes "disconnected" from the class's value.
However, if the attribute is mutable, changing it in an instance changes it for the class and all other instances of the class:
>>> MyClass.objects.append(1)
>>> MyClass.objects
[1]
>>> a = MyClass()
>>> a.objects
[1]
>>> a.objects.append(2)
>>> a.objects
[1, 2]
>>> MyClass.objects
[1, 2]
In Python, nothing is really "private", so you can't really prevent the instances from accessing or altering objects (in that case, is it an appropriate class attribute?), but it is conventional to prepend names with an underscore if you don't ordinarily want them to be accessed directly: _objects.
One way to actually protect objects from instance access would be to override __getattribute__:
def __getattribute__(self, name):
if name == "objects":
raise AttributeError("Do not access 'objects' though MyClass instances.")
return super(MyClass, self).__getattribute__(name)
>>> MyClass.objects
[1]
>>> a.objects
...
AttributeError: Do not access 'objects' though MyClass instances.
No, you can't (EDIT: you can't in a way that is completely unaccessible, like in Java or C++).
You can do this, if you like:
class MyClass(object):
objects = None
pass
MyClass_objects = 'test'
print MyClass_objects # outputs 'test'
a = MyClass()
print a.objects # outputs 'None'
or this:
in your_module.py:
objects = 'test'
class MyClass(object):
objects = None
pass
in yourapp.py:
import your_module
print your_module.objects # outputs 'test'
a = your_module.MyClass()
print a.objects # outputs 'None'
the reason is:
When you create an instance of some class there is nothing to prevent
you from poking around inside and using various internal, private
methods that are (a) necessary for the class to function, BUT (b) not
intended for direct use/access.
Nothing is really private in python. No class or class instance can
keep you away from all what's inside (this makes introspection
possible and powerful). Python trusts you. It says "hey, if you want
to go poking around in dark places, I'm gonna trust that you've got a
good reason and you're not making trouble."
Karl Fast

Built-in function to read __slots__

Let's say I have a class like this:
class Test(object):
prop = property(lambda self: "property")
The descriptor takes priority whenever I try to access Test().prop. So that will return 'property'. If I want to access the object's instance storage, I can do:
x = Test()
x.__dict__["prop"] = 12
print(x.__dict__["prop"])
However if I change my class to:
class Test(object):
__slots__ = ("prop",)
prop = property(lambda self: "property")
How do I do the same, and access the internal storage of x, to write 12 and read it back, since x.__dict__ no longer exist?
I am fairly new with Python, but I understand the Python philosophy is to give complete control, so why is an implementation detail preventing me from doing that?
Isn't Python missing a built-in function that could read from an instance internal storage, something like:
instance_vars(x)["prop"] = 12
print(instance_vars(x)["prop"])
which would work like vars, except it also works with __slots__, and with built-in types that don't have a __dict__?
Short answer, You can't
The problem is that slots are themselves implemented in terms of descriptors. Given:
class Test(object):
__slots__ = ("prop",)
t = Test()
the phrase:
t.prop
Is translated, approximately to:
Test.prop.__get__(t, Test)
where Test.prop is a <type 'member_descriptor'> crafted by the run-time specifically to load prop values out of Test instances from their reserved space.
If you add another descriptor to the class body definition, it masks out the member_descriptor that would let you get to the slotted attribute; there's no way to ask for it, it's just not there anymore. It's effectively like saying:
class Test(object):
#property
def prop(self):
return self.__dict__['prop']
#property
def prop(self):
return "property"
You've defined it twice. there's no way to "get at" the first prop definition.
but:
Long answer, you can't in a general way. You can
You can still abuse the python type system to get at it using another class definition. You can change the type of a python object, so long as it has the exact same class layout, which roughly means that it has all of the same slots:
>>> class Test1(object):
... __slots__ = ["prop"]
... prop = property(lambda self: "property")
...
>>> class Test2(object):
... __slots__ = ["prop"]
...
>>> t = Test1()
>>> t.prop
'property'
>>> t.__class__ = Test2
>>> t.prop = 5
>>> t.prop
5
>>> t.__class__ = Test1
>>> t.prop
'property'
But there's no general way to introspect an instance to work out its class layout; you just have to know from context. You could look at it's __slots__ class attribute, but that won't tell you about the slots provided in the superclass (if any) nor will it give you any hint if that attribute has changed for some reason after the class was defined.
I don't quite understand what and why you want to do this, but does this help you?
>>> class Test(object):
__slots__ = ("prop",)
prop = property(lambda self: "property")
>>> a = Test()
>>> b = Test()
>>> a.prop
'property'
>>> tmp = Test.prop
>>> Test.prop = 23
>>> a.prop
23
>>> Test.prop = tmp; del tmp
>>> b.prop
'property'
of course, you cannot overwrite the property on a per-instance basis, that's the whole point of slotted descriptors.
Note that subclasses of a class with __slots__ do have a __dict__ unless you manually define __slots__, so you can do:
>>> class Test2(Test):pass
>>> t = Test2()
>>> t.prop
'property'
>>> t.__dict__['prop'] = 5
>>> t.__dict__['prop']
5
>>> Test2.prop
<property object at 0x00000000032C4278>
but still:
>>> t.prop
'property'
and that's not because of __slots__, it's the way descriptors work.
your __dict__ is bypassed on attribute lookup, you are just abusing it as data structure that happens to be there for storing a state.
it is equivalent to do this:
>>> class Test(object):
__slots__ = ("prop", "state")
prop = property(lambda self: "property")
state = {"prop": prop}
>>> t.prop
'property'
>>> t.state["prop"] = 5
>>> t.state["prop"]
5
>>> t.prop
'property'
If you really ever want to do something like that, and you REALL REALLY need something like that, you can always override __getattribute__ and __setattribute__, it's just as stupid... This is just to prove it to you:
class Test(object):
__slots__ = ("prop",)
prop = property(lambda self: "property")
__internal__ = {}
def __getattribute__(self, k):
if k == "__dict__":
return self.__internal__
else:
try:
return object.__getattribute__(self, k)
except AttributeError, e:
try:
return self.__internal__[k]
except KeyError:
raise e
def __setattribute__(self, k, v):
self.__internal__[k] = v
object.__setattribute__(self, k, v)
t = Test()
print t.prop
t.__dict__["prop"] = "test"
print "from dict", t.__dict__["prop"]
print "from getattr", t.prop
import traceback
# These won't work: raise AttributeError
try:
t.prop2 = "something"
except AttributeError:
print "see? I told you!"
traceback.print_exc()
try:
print t.prop2
except AttributeError:
print "Haha! Again!"
traceback.print_exc()
(Tried it on Python 2.7)
It's exactly what you expect I guess. Don't do this, it's useless.

Categories

Resources