I'm trying to create a class which must be superclass of others, tracing their attribute requests. I thought of using "getattribute" which gets all attribute requests, but it generates recursion:
class Mixin(object):
def __getattribute__ (self, attr):
print self, "getting", attr
return self.__dict__[attr]
I know why I get recursion: it's for the self.dict call which recalls getattribute recursively. I've tryied to change last line in "return object.__getattribute__(self,attr)" like suggested in other posts but recursion is recalled.
Try this:
class Mixin(object):
def __getattribute__ (self, attr):
print self, "getting", attr
return object.__getattribute__(self, attr)
If you are still getting recursion problems, it is caused by code you haven't shown us
>>> class Mixin(object):
... def __getattribute__ (self, attr):
... print self, "getting", attr
... return object.__getattribute__(self, attr)
...
>>> Mixin().__str__
<__main__.Mixin object at 0x00B47870> getting __str__
<method-wrapper '__str__' of Mixin object at 0x00B47870>
>>> Mixin().foobar
<__main__.Mixin object at 0x00B47670> getting foobar
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 4, in __getattribute__
AttributeError: 'Mixin' object has no attribute 'foobar'
>>>
And here is the result when combined with Bob's Mylist
>>> class Mylist(Mixin):
... def __init__ (self, lista):
... if not type (lista) == type (""):
... self.value = lista[:]
... def __add__ (self,some):
... return self.value + some
... def __getitem__ (self,item):
... return self.value[item]
... def __getslice__ (self, beg, end):
... return self.value[beg:end]
...
>>> a=Mylist([1,2])
>>> a.value
<__main__.Mylist object at 0x00B47A90> getting value
[1, 2]
This is the code:
from Es123 import Mixin
class Mylist(Mixin):
def __init__ (self, lista):
if not type (lista) == type (""):
self.value = lista[:]
def __add__ (self,some):
return self.value + some
def __getitem__ (self,item):
return self.value[item]
def __getslice__ (self, beg, end):
return self.value[beg:end]
a = Mylist ([1,2])
a.value
Then python returns "RuntimeError: maximum recursion depth exceeded"
Related
Take a look at this code:
class SomeClass:
def __init__(self):
self._value = 'Hello, World!'
def func(self):
return self._value
instance = SomeClass()
print(instance.func())
def new_func(self):
return self._value + '!!!!!'
instance.func = new_func
print(instance.func())
This code creates an instance of SomeClass, calls original func, then overrides this function and calls it again.
I want to override a function in a single instance of a class, but not in the entire class so all the instances got the function overrided.
I expect this code to print:
Hello, World!
Hello, World!!!!!
But it prints:
Hello, World!
Traceback (most recent call last):
File "test.py", line 17, in <module>
print(instance.func())
TypeError: new_func() missing 1 required positional argument: 'self'
The self argument is not passed to the overrided function. Why? Aren't SomeClass.func(instance) and instance.func() the same?
How to override the function correctly so I can access the self argument in the overrided function?
Well let's see
The func of the original instance has type bound method
SomeClass().func
# <bound method SomeClass.func of <__main__.SomeClass object at 0x7f293e1cb3d0>>
and your func has type function
instance.func
# <function __main__.new_func(self)>
The idea is to get a new method of some new class like this:
class SomeNewClass:
def new_func(self):
return self._value + '!!!!!'
instance.func = SomeNewClass().new_func
instance.func
# <bound method SomeNewClass.new_func of <__main__.SomeNewClass object at 0x7f293e2825d0>>
But as you see, this is a method of the new class :(
By the way, if you don't initialize the class, the type will change to function:
class SomeNewClass:
def new_func(self):
return self._value + '!!!!!'
instance.func = SomeNewClass.new_func
instance.func
# <function __main__.SomeNewClass.new_func(self)>
So the next idea is to change the method before the initialization of a class:
SomeClass.func = new_func
instance = SomeClass()
instance.func
# <bound method new_func of <__main__.SomeClass object at 0x7f29441e4350>>
Seems good. The result based on your code:
class SomeClass:
def __init__(self):
self._value = 'Hello, World!'
def func(self):
return self._value
instance = SomeClass()
print(instance.func())
def new_func(self):
return self._value + '!!!!!'
SomeClass.func = new_func
instance = SomeClass()
print(instance.func())
# Hello, World!
# Hello, World!!!!!!
If you need to change the method of an instance and not of the class. There is also a way to do that using types.MethodType:
import types
class SomeClass:
def __init__(self):
self._value = 'Hello, World!'
def func(self):
return self._value
instance = SomeClass()
print(instance.func())
def new_func(self):
return self._value + '!!!!!'
instance.func = types.MethodType(new_func, instance)
print(instance.func())
# Hello, World!
# Hello, World!!!!!!
I know that functions are just descriptors, like this:
def func(self):
print(self.name)
class C:
def __init__(self, name):
self.name = name
C.func = func
c = C("foo")
c.func()
I thought at first that c.func equals C.func.__get__(c),yes,C.func.__get__(c) return a bound method. But when I set the __get__ of func to None, c.func still returns a bound method.
def func(self):
print(self.name)
class C:
def __init__(self, name):
self.name = name
func.__get__ = None
C.func = func
c = C("foo")
c.func
output:
<bound method func of <__main__.C object at 0x0000027EB23BF088>>
So I'm confused. Moreover, I found that when calling a function from an instance, Python actually calls the class's ___getAttribute__ method, which returns a bound method.
def func(self):
print(self.name)
func.__get__ = None
class C:
def __getattribute__(self, name):
r = super().__getattribute__(name)
print(r) # r is a bound method already
return r
def __init__(self, name):
self.name = name
C.func = func
c = C("foo")
c.func
output:
<bound method func of <__main__.C object at 0x0000027EB243D1C8>>
func.__get__ doesn't seem to have any effect. So, What happended in __getattribute__? How does Python turn a function into a method? I've Googled and done some research, but I still can't find the answer.
Maybe I'm making things complicated, In my understanding, function is itself a descriptor, but just like the code below, I set the func to None, it works normally:
class C:
def func(self):
print('hello world')
func.__get__ = None
c = C()
c.func()
but if it's a descriptor, it will raise TypeError:
class C:
class D:
def __get__(self, inst, cls):
if inst is None:
return self
return 'hello world'
D.__get__ = None
func = D()
c = C()
c.func
Well, if I understand correctly from what I found. (Since I didn't know the descriptors, that's exactly why I like to help, still learning)
First, let's look at __getattr__ and __getattribute__.
Let's have an empty class A
class A:
pass
If I initialize an object and try to call a property, because there is none at the moment, we get AttributeError.
a = A()
a.some_property
The following occurs:
Simple check of flow:
class FlowDemo:
def __init__(self):
self.inited_property = True
def __getattribute__(self, item):
if item in ('__class__', '__len__') : # For less spam of getting this attribute, if you want, you can remove condition.
print('Get Attribute', item)
# Call default behavior
return super().__getattribute__(item)
def __getattr__(self, item):
print('Get Attr', item)
if item == 'some_magic_name':
return "It's magic!"
raise AttributeError
fd = FlowDemo()
fd.inited_property
# Get Attribute inited_property
# True
fd.some_magic_property
# Get Attribute some_magic_name
# Get Attr some_magic_name
# "It's magic!"
fd.some_property
# Get Attribute some_property
# Get Attr some_property
# Traceback (most recent call last):
# File "<input>", line 1, in <module>
# File "stack-class-property-and-descriptors.py", line 67, in # __getattr__
# raise AttributeError
# AttributeError
This is probably understandable, including the use. But to be sure, I'll give an example. This logic is used as a dynamic representation of the result from the databases (mapping of attributes to ordinary dict, list, etc.).
But it can also be just logic for accessing an attribute (property), such as an access counter or validation (but this applies to __setattr__ and __setattribute__)
And what about descriptors?
First let's look at data-descriptors, they are easier for me to understand.
This is a class or decoder that has __get__ and one or both of __set__ and __delete__.
Once this is defined, python, when used in the property definition with it and then does not return a class but the value it obtains through __get__, does not overwrite an already declared class when declaring a value, but uses its __set__.
Example:
class WeekDayDescriptor:
def __init__(self):
self.__week_day = 0
def __get__(self, instance, owner=None):
return self.__week_day
def __set__(self, instance, value):
if not isinstance(value, int):
raise TypeError('Value must be int')
if not (0 <= value < 6):
raise ValueError('Value must be in range 0 - 6')
self.__week_day = value
class Calendar:
week_day = WeekDayDescriptor()
def __init__(self, week_day):
self.week_day = week_day
Demo:
c = Calendar(9)
# ValueError: Value must be in range 0-6
c = Calendar('6')
# TypeError: Value must be int
c = Calendar(3)
c.week_day = 6
c.week_day = 10
# ValueError: Value must be in range 0-6
c.week_day = 'monday'
# TypeError: Value must be int
Decorator descriptor:
class Calendar:
#property
def week_day(self):
return self.__week_day
#week_day.setter
def week_day(self, week_day):
if not isinstance(week_day, int):
raise TypeError('Value must be int')
if not (0 <= week_day < 6):
raise ValueError('Value must be in range 0 - 6')
self.__week_day = week_day
def __init__(self, week_day):
self.week_day = week_day
pass
And now for non-data descriptors...
A non-data descriptor is one that has only __get__.
As I understand it, each method automatically has its own descriptor, thanks to which the functions get references to the object - self.
We can write our own descriptor for a function / method, but it's not that straightforward, we have to help ourselves and get around it a bit.
def function_as_method(self, value):
print(self, value)
class HelperDescriptor:
def __get__(self, instance, owner):
def wrapper(*args, **kwargs):
return function_as_method(instance, *args, **kwargs)
return wrapper
class Foo:
baz = HelperDescriptor()
>>> bar = Foo()
>>> bar.baz(1)
<__main__.Foo object at 0x7f64f7768b70> 1
Source of last code block, but in czech lang.
And finally, your mentioned problem, when we set __get__ to None and you still get a reference to the function.
It's simple, python doesn't directly distinguish between primitive data types and functions, it's all a variable (or attribute / property) that has a value. Whether it's just value or it's callable is a different matter.
def f(): return True
print(type(f), f())
# <class 'function'> True
f = 123
print(type(f), f)
# <class 'int'> 123
Therefore, when we ask for the obj.func method or call it obj.func() directly, the first two changed magic is called first - __getattribute__ and __getattr__.
And if we call a method, it is called only after we get a reference to a function in memory.
Again a simple example:
def func(self, value):
print('Printing:', value)
class PrintDescriptor:
def __init__(self, name):
self.name = name
def __get__(self, instance, owner):
def wrapper(*args, **kwargs):
print(f"Calling '{self.name}' method")
return func(instance, *args, **kwargs)
return wrapper
class B:
foo = PrintDescriptor('foo')
bar = PrintDescriptor('bar')
def __getattribute__(self, item):
if item not in ('__len__', '__class__', '__dict__'):
print('Get Attribute', item)
return super().__getattribute__(item)
Demo:
b = B()
b.foo
# Get Attribute foo
# <function PrintDescriptor.__get__.<locals>.wrapper at 0x7f774a782ee0>
b.foo(2)
# Get Attribute foo
# Calling 'foo' method
# Printing: 2
b.bar(4)
# Get Attribute bar
# Calling 'bar' method
# Printing: 4
Sources:
https://www.datacamp.com/community/tutorials/python-descriptors#above1
https://blog.milde.cz/post/319-pokrocile-techniky-v-pythonu-deskriptory/
Python Doc, __get__
Python Docs, __getattribute__
Python Docs, __getattr__
In this example code, I would like to determine if x is an instance of TestProperty:
class TestProperty(object):
def __init__(self, name):
self._name = name
def __get__(self, instance, cls):
return getattr(instance, self._name)
def __set_(self, instance, value):
setattr(instance, self._name, value)
class Test(object):
x = TestProperty("x")
print isinstance(Test.x, TestProperty)
However, I get the following exception:
Traceback (most recent call last):
File "/home/zenoss/testproperties.py", line 14, in <module>
print isinstance(Test.x, TestProperty)
File "/home/zenoss/testproperties.py", line 6, in __get__
return getattr(instance, self._name)
AttributeError: 'NoneType' object has no attribute 'x'
Is there anyway to tell if an attribute is an instance of a class when it is a descriptor?
With the current __get__, Test.x causes the AttributeError because when the code accessing the descriptor using class, instance is passed None; (=> getattr(None, 'x') => None.x)
You should modify __get__ to handle such case:
>>> class TestProperty(object):
... def __init__(self, name):
... self._name = name
... def __get__(self, instance, cls):
... if instance is None: # To handle access through class, not instance
... return self # returns the TestProperty instance itself.
... return getattr(instance, self._name)
... def __set_(self, instance, value):
... setattr(instance, self._name, value)
...
>>> class Test(object):
... x = TestProperty("x")
...
>>> isinstance(Test.x, TestProperty)
True
BTW, as you may know, with x = TestProperty("x"), accessing x attribute through an instance will cause another exception, because it will call the __get__ (-> getattr(..) -> __get__ -> getattr(..) -> ...) recursively until stack overflow.
The best way to implement a property is with the #property decorator:
class TestProperty(object):
def __init__(self, name):
self._name = name
#property
def name(self):
"""Getter for '_name'."""
return self._name
#name.setter
def name(self, value):
"""Setter for '_name'."""
self._name = value
class Test(object):
x = TestProperty("x")
print(isinstance(Test.x, TestProperty))
It returns True when I run it.
See the documentation for #property at https://docs.python.org/3/library/functions.html#property.
class A():
...
I want class A that is initialized with any object as parameter, but when __init__ goes with A type, it should leave/return old A object, dont create wrapper A(A()).
I guess that overwrite __new__ method is solution, but how there stop creating object creator and return given parameter as a result.
My workaround now is just recommendation:
def ToA(it):
if type(it) == A:
return it
else:
return A(it)
But I need block somehow A to prevent direct use of A(A()).
I am not at all sure I understand what you want, but something like this may be it. You can't have an __init__ with this technique, because if you do, it will be called regardless of whether __new__ returned a new object.
class A(object):
def __new__(cls, obj):
if isinstance(obj, cls):
return obj
rv = object.__new__(cls)
# everything you would normally put in __init__
# goes here instead
rv._obj = obj
return rv
# for instance:
def __repr__(self):
return "A({})".format(repr(self._obj))
>>> A()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: __new__() takes exactly 2 arguments (1 given)
>>> A(1)
A(1)
>>> A(A(1))
A(1)
Not being able to use __init__ is troublesome, particularly if you need to subclass A. Here's a way to work around that:
class A(object):
def __new__(cls, obj):
if isinstance(obj, cls):
return obj
rv = object.__new__(cls)
rv._initialized = False
return rv
def __init__(self, obj):
if self._initialized: return
self._obj = obj
self._initialized = True
class B(A):
def __init__(self, obj):
if self._initialized: return
A.__init__(self, obj)
self._otherthing = "foo"
You have to check self._initialized in every subclass's __init__ method, unfortunately.
I have a class A that is callable. I also have a subclass of A called B that I want to make not callable. It should raise the normal "not callable" TypeError when I try to call it.
class A():
def __call__(self):
print "I did it"
class B(A):
def __call__(self):
raise TypeError("'B' object is not callable")
As you can see, my solution right now is to raise a duplicate of the normal TypeError. This feels wrong, since I'm just copying the text of a standard python exception. It would be better (in my opinion) if there was a way to mark a subclass as not callable and then have python handle that attribute.
What is the best way to make class B not callable, given that it's a subclass of the callable class A?
You can override type creation with Python metaclasses. Here after object creation, I replace parent's __call__ method with another one throwing an exception:
>>> class A(object):
def __call__(self):
print 'Called !'
>>> class MetaNotCallable(type):
#staticmethod
def call_ex(*args, **kwargs):
raise NotImplementedError()
def __new__(mcs, name, bases, dict):
obj = super(MetaNotCallable, mcs).__new__(mcs, name, bases, dict)
obj.__call__ = MetaNotCallable.call_ex # Change method !
return obj
>>> class B(A):
__metaclass__ = MetaNotCallable
>>> a = A()
>>> a()
Called !
>>> b = B()
>>> b()
Traceback (most recent call last):
File "<pyshell#131>", line 1, in <module>
b()
File "<pyshell#125>", line 4, in call_ex
raise NotImplementedError()
NotImplementedError