Accessing parent class attribute from sub-class body - python

I have a class Klass with a class attribute my_list. I have a subclass of it SubKlass, in which i want to have a class attribute my_list which is a modified version of the same attribute from parent class:
class Klass():
my_list = [1, 2, 3]
class SubKlass(Klass):
my_list = Klass.my_list + [4, 5] # this works, but i must specify parent class explicitly
#my_list = super().my_list + [4, 5] # SystemError: super(): __class__ cell not found
#my_list = my_list + [4, 5] # NameError: name 'my_list' is not defined
print(Klass.my_list)
print(SubKlass.my_list)
So, is there a way to access parent class attribute without specifying its name?
UPDATE:
There is a bug on Python issue tracker: http://bugs.python.org/issue11339 . Let's hope it will be solved at some point.

You can't.
A class definition works in Python works as follows.
The interpreter sees a class statement followed by a block of code.
It creates a new namespace and executes that code in the namespace.
It calls the type builtin with the resulting namespace, the class name, the base classes, and the metaclass (if applicable).
It assigns the result to the name of the class.
While running the code inside the class definition, you don't know what the base classes are, so you can't get their attributes.
What you can do is modify the class immediately after defining it.
EDIT: here's a little class decorator that you can use to update the attribute. The idea is that you give it a name and a function. It looks through all the base classes of your class, and gets their attributes with that name. Then it calls the function with the list of values inherited from the base class and the value you defined in the subclass. The result of this call is bound to the name.
Code might make more sense:
>>> def inherit_attribute(name, f):
... def decorator(cls):
... old_value = getattr(cls, name)
... new_value = f([getattr(base, name) for base in cls.__bases__], old_value)
... setattr(cls, name, new_value)
... return cls
... return decorator
...
>>> def update_x(base_values, my_value):
... return sum(base_values + [my_value], tuple())
...
>>> class Foo: x = (1,)
...
>>> #inherit_attribute('x', update_x)
... class Bar(Foo): x = (2,)
...
>>> Bar.x
(1, 2)
The idea is that you define x to be (2,) in Bar. The decorator will then go and look through the subclasses of Bar, find all their xs, and call update_x with them. So it will call
update_x([(1,)], (2,))
It combines them by concatenating them, then binds that back to x again. Does that make sense?

As answered by #katrielalex, my_list is not in the namespace by default before the class has been created. What you could do however in Python 3, if you want to dive into metaclasses, is to add my_list to the namespace manually:
class Meta(type):
def __prepare__(name, bases, **kwds):
print("preparing {}".format(name), kwds)
my_list = []
for b in bases:
if hasattr(b, 'my_list'):
my_list.extend(b.my_list)
return {'my_list': my_list}
class A(metaclass=Meta):
my_list = ["a"]
class B(A):
my_list.append(2)
print(A().my_list)
print(B().my_list)
Note that this example probably does not yet handle diamond-shaped inheritance structures well.
The new __prepare__ attribute is defined in PEP 3115.

You could use a metaclass or a class decorator. Here's how you would use a metaclass in Python 2.x:
class Klass(object):
my_list = [1, 2, 3]
class KlassMeta(type):
def __new__(cls, name, bases, attrs):
# grab last base class, which in this case is Klass
attrs['my_list'] = bases[-1].my_list + [4, 5]
return super(KlassMeta, cls).__new__(cls, name, bases, attrs)
class SubKlass(Klass):
__metaclass__ = KlassMeta
With Python 3 you'd declare the metaclass using the newer syntax:
class SubKlass(Klass, metaclass=KlassMeta):
pass

There is no way from the body of the class; from a context in which self is available (or the class itself), you can examine __bases__.

As you've seen from the other responses such as katriealex's: No, you can't. At least not easily.
Q: What are you actually trying to do?
Q: Why do you want to do this?

Related

How to access subcclass attributes in super class methods, without passing them in

How does one access a derived class'es property (static variable in other languages), in its base classes method?
I.e.
class Base:
#classmethod
def get_list(cls):
return [1, 2, cls.x]
class Derived(Base):
x = 3
foo = Base.get_list()
Derived.foo # Hope to have it set to [1, 2, 3]
I wish to not pass x directly to the base class, i.e. foo = Base.get_list(x) because I have a lot of methods to be called with the same variables.
EDIT
The comments have asked for context. I tried to make a minimum reproducible example to spare you guys the details.
Here's the full context: So its actually to do with Django Admin.
I have a abstract model. Then I have various admin interfaces for the various concrete implementation of the abstract model. As you can guess I created an abstract admin model to handle the common logic. A part of handling the common admin logic, e.g. generating properties on the derived admin model.
So for example the list display, here's the logic to create the list display:
class FactAdmin(admin.ModelAdmin):
#classmethod
def build_list_display(cls, *custom):
return (
'created_utc',
*custom,
'foo__bar__abbreviation',
'foo__baz__name',
'foo__caz__name',
'foo__daz__description',
'foo__eaz__code',
)
#admin.register(FooEntry)
class FoopEntryAdmin(FactAdmin):
fieldsets = FactAdmin.build_list_display('cannon_ball', 'pogo_stick')
So in the base admin class, it keeps reusing a list of custom fields, custom models, and other things. So instead of passing them in each time, for each property, it seemed more DRY to set them as static attributes. Hence I wished to set them as static member fields on the derived class, and access them in the base class.
Accessing subclass attributes in a superclass classmethod called on the subclass isn't a problem. This works as expected:
class Base:
#classmethod
def get_list(cls):
return [1, 2, cls.x]
class Derived(Base):
x = 3
assert Derived.get_list() == [1, 2, 3]
However, you can't easily call that classmethod right in the subclass's class body, as at that time, the class object for Derived and indeed the name Derived don't exist yet. (You could call it in methods, classmethods and staticmathods, because their body is evaluated when they are invoked, and not already when they are defined. But that doesn't help here.) And if called on Base, it obviously lacks x. (And being a Python classmethod, get_list has to be explicitly called on something. We can't just make an unqualified call as in Java.)
So
class Derived(Base):
x = 3
foo = get_list()
results in NameError: name 'get_list' is not defined,
class Derived(Base):
x = 3
foo = Base.get_list()
results in AttributeError: type object 'Base' has no attribute 'x' and
class Derived(Base):
x = 3
foo = Derived.get_list()
results in NameError: name 'Derived' is not defined.
But all is not lost. Let's not forget that Python allows us to create and set class attributes from outside the class. So this works:
class Base:
#classmethod
def get_list(cls):
return [1, 2, cls.x]
class Derived(Base):
x = 3
Derived.foo = Derived.get_list()
assert Derived.foo == [1, 2, 3]
You shouldn't be using class attributes and methods. You should be defining classes that you create instances of, and use instance methods and attributes, so that normal inheritance works the way it was intended to be used in the language.
Then you need to take advantage of the fact that instance methods can be overridden by subclasses. Here, to let the parent class get at the child class's x, you define a get_x method in the parent class that you expect to have overridden in the child class. That's how the child class's x gets used by the parent without it ever being passed to it.
Here's an example:
class Base:
def set_foo(self):
return [1, 2, self.get_x()]
def get_x(self):
return 0
class Sub(Base):
def __init__(self):
self.x = 3
self.foo = super().set_foo()
def get_x(self):
return self.x
print(Sub().foo)
Result:
[1, 2, 3]
If you want super to access the property of a derived class, it's probably because this property is shared by all derived subclasses (you don't make any check on the derived class type anyway). In such case, the most logical thing to do is to implement the property in super instead, and that solves the problem :
class Base:
x = 3
#classmethod
def get_foo():
return [1, 2, self.x]

Possible to hijack class definition with decorators?

Say I have a
class A:
def __init__(self, *args):
pass
and I want an decorator that copies A's definition and extend it with the new class.
def decorator(cls): # some decorator here
# make a new class which inherits from A
# return it while preserving the original A
Is that possible? (PS: This is to avoid maintainence problems.)
When you invoke a function using decorator syntax:
#my_decorator_function
class A:
pass
The decorator function's return value will replace the existing definition of A. So if you want it to create a new class and "return it while preserving the original A", you've got a tricky challenge. What you return will replace A, so you need to decide if that should be the original A or the new class. You can put the other one somewhere else.
For instance, this decorator would replace A with a subclass, and the subclass will make the original A class available as a class attribute named _orig:
def class_decorator(cls):
class SubClass(cls):
_orig = cls
# add other stuff here?
return SubClass
You can add extra logic to copy the original class's __name__ and __doc__ into the new class if you want to. You could also turn the logic around, and add SubClass as an attribute of cls before returning the otherwise unmodified cls.
Using #decorator is not the only possible syntax. You can put B = decorator(A) after the class definition.
class A:
...
B = decorator(A)
Now you still have a reference on the undecorated A, and you have a decorated version B.
The other answers have done a good job, but to make it crystal clear why you don't want to do this:
def dec(cls):
new_cls = type(cls.__name__, (cls,), {})
return new_cls
#dec
class A():
pass
Now inspect the method resolution order class A:
>>> A.__mro__
(<class '__main__.A'>, <class '__main__.A'>, <class 'object'>)
>>> classes = A.__mro__
>>> classes[0].__name__
'A'
>>> classes[1].__name__
'A'
TWO class As! Are they the same?
>>> classes[0] is classes[1]
False
Nope; different. The current variable A is pointing to the lowest one of course:
>>> A is classes[0]
True
But now you've lost name-access to the parent. That's usually not optimal.
In short: you are creating a metric ton of confusion and ambiguity for yourself a few months from now when you have forgotten all about what you did. Do something else.
If you really want to, here is an idea for spinning out new subclasses:
def add_babymaker(cls):
'''Adds a method for making new child classes.'''
def babymaker(name=None):
'''Creates a new child class based on the parent class.'''
name = name if name is not None else cls.__name__
new_cls = type(name, (cls,), {})
return new_cls
cls.babymaker = babymaker
return cls
#add_babymaker
class A():
pass
B = A.babymaker('B')
C = A.babymaker('C')
ANew = A.babymaker()
I think I have worked it out. That's not really a good idea.
def make_variant(cls):
suffix='VARIANT'
new = type(cls.__name__+suffix, (cls, ), {})
# new.__repr__ = lambda self: 'HELLO' # Just do whatever needed here
assert cls.__name__ + suffix not in globals()
globals()[cls.__name__+suffix] = new # Think twice about this line
return cls
#make_variant
class A:
def __init__(self):
pass
print(AVARIANT(), A())

How to share same method on two different classes in python

I have class:
class A(object):
def do_computing(self):
print "do_computing"
Then I have:
new_class = type('B', (object,), {'a': '#A', 'b': '#B'})
What I want to achieve is to make all methods and properties on class A a member of class B. Class A can have from 0 to N such elements. I want to make them all a member of class B.
So far I get to:
methods = {}
for el in dir(A):
if el.startswith('_'):
continue
tmp = getattr(A, el)
if isinstance(tmp, property):
methods[el] = tmp
if isinstance(tmp, types.MethodType):
methods[el] = tmp
instance_class = type('B', (object,), {'a': '#A', 'b': '#B'})
for name, func in methods.items():
new_method = types.MethodType(func, None, instance_class)
setattr(instance_class, name, new_method)
But then when I run:
instance().do_computing()
I get an error:
TypeError: unbound method do_computing() must be called with A instance as first argument (got B instance instead)
Why I had to do that? We have a lot of legacy code and I need fancy objects that will pretend they are old objects but really.
One more important thing. I cannot use inheritance, to much magic happens in the background.
If you do it like this, it will work:
import types
class A(object):
def do_computing(self):
print "do_computing"
methods = {name:value for name, value in A.__dict__.iteritems()
if not name.startswith('_')}
instance_class = type('B', (object,), {'a': '#A', 'b': '#B'})
for name, func in methods.iteritems():
new_method = types.MethodType(func, None, instance_class)
setattr(instance_class, name, new_method)
instance_class().do_computing()
Unless I'm missing something, you can do this with inheritance:
class B(A):
def __init__(self):
super(B, self).__init__()
Then:
>>> b = B()
>>> b.do_computing()
do_computing
Edit: cms_mgr said the same in the comments, also fixed indentation
are you creating a facade? maybe you want something like this:
Making a facade in Python 2.5
http://en.wikipedia.org/wiki/Facade_pattern
you could also use delegators. here's an example from the wxpython AGW:
_methods = ["GetIndent", "SetIndent", "GetSpacing", "SetSpacing", "GetImageList", "GetStateImageList",
"GetButtonsImageList", "AssignImageList", "AssignStateImageList", "AssignButtonsImageList",
"SetImageList", "SetButtonsImageList", "SetStateImageList", 'other_methods']
def create_delegator_for(method):
"""
Creates a method that forwards calls to `self._main_win` (an instance of :class:`TreeListMainWindow`).
:param `method`: one method inside the :class:`TreeListMainWindow` local scope.
"""
def delegate(self, *args, **kwargs):
return getattr(self._main_win, method)(*args, **kwargs)
return delegate
# Create methods that delegate to self._main_win. This approach allows for
# overriding these methods in possible subclasses of HyperTreeList
for method in _methods:
setattr(HyperTreeList, method, create_delegator_for(method))
Note that these wrap class methods... i.e both functions take a signature like def func(self, some, other, args) and are intended to be called like self.func(some, args). If you want to delegate a class function to a non-class function, you'll need to modify the delegator.
You can inherit from a parent class as such:
class Awesome():
def method_a():
return "blee"
class Beauty(Awesome):
def __init__(self):
self.x = self.method_a()
b = Beauty()
print(b.x)
>>> "blee"
This was freely typed, but the logic is the same none the less and should work.
You can also do fun things with setattr like so:
#as you can see this class is worthless and is nothing
class blee():
pass
b = blee()
setattr(b, "variable_1", "123456")
print(b.variable_1)
>>> 123456
essentially you can assign any object, method to a class instance with setattr.
EDIT: Just realized that you did use setattr, woops ;)
Hope this helps!

Does a metaclass instantiate the class's attributes first?

From this answer to "what is a metaclass?" I got this:
You write class Foo(object) first, but the class object Foo is not created in memory yet.
Python will look for metaclass in the class definition. If it finds it, it will use it to create the object class Foo. If it doesn't, it will use type to create the class.
Having tested it, it seems that the attributes of the class are instantiated before the constructor of the class is run. What am I misunderstanding?
Test code:
class meta(type):
def __init__(cls, name, bases, dic):
type.__init__(cls, name, bases, dic)
print hasattr(cls, "a")
cls.a = "1"
class A(object):
a = "a"
__metaclass__ = meta
class B(object):
__metaclass__ = meta
class C(object):
__metaclass__ = meta
a = "a"
print A.a
print B.a
print C.a
Output:
True
False
True
1
1
1
The class body is run before the class is constructed, yes.
The body of the class provides a temporary namespace, and all local names in that namespace are given as a dictionary to construct the class object, together with the base classes and a name for the class.
You can do this with the type() constructor too:
>>> Foo = type('Foo', (), {'a': 1})
>>> Foo.a
1
The class body is basically executed as a function, with the local namespace of that function being used to create the class attributes, the 3rd argument to type() above.
In python 3 you have a little more influence on that process with the __prepare__ hook on a metaclass. __prepare__ should be a class method that returns a initial namespace for the class body; use it to inject extra names into the generated class body before the class body is executed:
class MyMeta(type):
#classmethod
def __prepare__(mcl, name, bases):
return {'a': 1}

How can I intercept calls to python's "magic" methods in new style classes?

I'm trying to intercept calls to python's double underscore magic methods in new style classes. This is a trivial example but it show's the intent:
class ShowMeList(object):
def __init__(self, it):
self._data = list(it)
def __getattr__(self, name):
attr = object.__getattribute__(self._data, name)
if callable(attr):
def wrapper(*a, **kw):
print "before the call"
result = attr(*a, **kw)
print "after the call"
return result
return wrapper
return attr
If I use that proxy object around list I get the expected behavior for non-magic methods but my wrapper function is never called for magic methods.
>>> l = ShowMeList(range(8))
>>> l #call to __repr__
<__main__.ShowMeList object at 0x9640eac>
>>> l.append(9)
before the call
after the call
>> len(l._data)
9
If I don't inherit from object (first line class ShowMeList:) everything works as expected:
>>> l = ShowMeList(range(8))
>>> l #call to __repr__
before the call
after the call
[0, 1, 2, 3, 4, 5, 6, 7]
>>> l.append(9)
before the call
after the call
>> len(l._data)
9
How do I accomplish this intercept with new style classes?
For performance reasons, Python always looks in the class (and parent classes') __dict__ for magic methods and does not use the normal attribute lookup mechanism. A workaround is to use a metaclass to automatically add proxies for magic methods at the time of class creation; I've used this technique to avoid having to write boilerplate call-through methods for wrapper classes, for example.
class Wrapper(object):
"""Wrapper class that provides proxy access to some internal instance."""
__wraps__ = None
__ignore__ = "class mro new init setattr getattr getattribute"
def __init__(self, obj):
if self.__wraps__ is None:
raise TypeError("base class Wrapper may not be instantiated")
elif isinstance(obj, self.__wraps__):
self._obj = obj
else:
raise ValueError("wrapped object must be of %s" % self.__wraps__)
# provide proxy access to regular attributes of wrapped object
def __getattr__(self, name):
return getattr(self._obj, name)
# create proxies for wrapped object's double-underscore attributes
class __metaclass__(type):
def __init__(cls, name, bases, dct):
def make_proxy(name):
def proxy(self, *args):
return getattr(self._obj, name)
return proxy
type.__init__(cls, name, bases, dct)
if cls.__wraps__:
ignore = set("__%s__" % n for n in cls.__ignore__.split())
for name in dir(cls.__wraps__):
if name.startswith("__"):
if name not in ignore and name not in dct:
setattr(cls, name, property(make_proxy(name)))
Usage:
class DictWrapper(Wrapper):
__wraps__ = dict
wrapped_dict = DictWrapper(dict(a=1, b=2, c=3))
# make sure it worked....
assert "b" in wrapped_dict # __contains__
assert wrapped_dict == dict(a=1, b=2, c=3) # __eq__
assert "'a': 1" in str(wrapped_dict) # __str__
assert wrapped_dict.__doc__.startswith("dict()") # __doc__
Using __getattr__ and __getattribute__ are the last resources of a class to respond to getting an attribute.
Consider the following:
>>> class C:
x = 1
def __init__(self):
self.y = 2
def __getattr__(self, attr):
print(attr)
>>> c = C()
>>> c.x
1
>>> c.y
2
>>> c.z
z
The __getattr__ method is only called when nothing else works (It will not work on operators, and you can read about that here).
On your example, the __repr__ and many other magic methods are already defined in the object class.
One thing can be done, thought, and it is to define those magic methods and make then call the __getattr__ method. Check this other question by me and its answers (link) to see some code doing that.
As of the answers to Asymmetric behavior for __getattr__, newstyle vs oldstyle classes (see also the Python docs), modifying access to "magic" methods with __getattr__ or __getattribute__ is just not possible with new-style classes. This restriction makes the interpreter much faster.
Cut and copy from the documentation:
For old-style classes, special methods are always looked up in exactly the same way as any other method or attribute.
For new-style classes, implicit invocations of special methods are only guaranteed to work correctly if defined on an object’s type, not in the object’s instance dictionary.

Categories