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}
Related
With a boring class, object instance attribute shadow class attributes:
class C(object):
a="class_a"
def __init__(self, a):
self.a = a
c = C(a="obja")
print c.a # obja
But if my class attributes are declared in a named_tuple base:
class C(collections.namedtuple("CBase", ['a', ])):
a="class_a"
c = C(a="obja")
print c.a # class_a !!??!
... so, declaring my instance attribute through the name tuple causes that attribute to be shadowed by the class attribute ... which not what you'd expect.
Why is this?
namedtuple "attributes" are implemented as descriptors (specifically, propertys) on the class itself, not attributes in the traditional sense (all the actual data is stored in unnamed indices of the tuple). In this case, the namedtuple (roughly) defines:
#property
def a(self):
return self[0]
Since the property is a class level attribute, when you define a on the subclass, it shadows equivalent definitions in the parent class.
I am trying to create a class that returns the class name together with the attribute. This needs to work both with instance attributes and class attributes
class TestClass:
obj1 = 'hi'
I.e. I want the following (note: both with and without class instantiation)
>>> TestClass.obj1
('TestClass', 'hi')
>>> TestClass().obj1
('TestClass', 'hi')
A similar effect is obtained when using the Enum package in python, but if I inherit from Enum, I cannot create an __init__ function, which I want to do as well
If I use Enum I would get:
from enum import Enum
class TestClass2(Enum):
obj1 = 'hi'
>>> TestClass2.obj1
<TestClass2.obj1: 'hi'>
I've already tried overriding the __getattribute__ magic method in a meta class as suggested here: How can I override class attribute access in python. However, this breaks the __dir__ magic method, which then wont return anything, and furthermore it seems to return name of the meta class, rather than the child class. Example below:
class BooType(type):
def __getattribute__(self, attr):
if attr == '__class__':
return super().__getattribute__(attr)
else:
return self.__class__.__name__, attr
class Boo(metaclass=BooType):
asd = 'hi'
>>> print(Boo.asd)
('BooType', 'asd')
>>> print(dir(Boo))
AttributeError: 'tuple' object has no attribute 'keys'
I have also tried overriding the __setattr__ magic method, but this seems to only affect instance attributes, and not class attributes.
I should state that I am looking for a general solution. Not something where I need to write a #property or #classmethod function or something similar for each attribute
I got help from a colleague for defining meta classes, and came up with the following solution
class MyMeta(type):
def __new__(mcs, name, bases, dct):
c = super(MyMeta, mcs).__new__(mcs, name, bases, dct)
c._member_names = []
for key, value in c.__dict__.items():
if type(value) is str and not key.startswith("__"):
c._member_names.append(key)
setattr(c, key, (c.__name__, value))
return c
def __dir__(cls):
return cls._member_names
class TestClass(metaclass=MyMeta):
a = 'hi'
b = 'hi again'
print(TestClass.a)
# ('TestClass', 'hi')
print(TestClass.b)
# ('TestClass', 'hi again')
print(dir(TestClass))
# ['a', 'b']
Way 1
You can use classmethod decorator to define methods callable at the whole class:
class TestClass:
_obj1 = 'hi'
#classmethod
def obj1(cls):
return cls.__name__, cls._obj1
class TestSubClass(TestClass):
pass
print(TestClass.obj1())
# ('TestClass', 'hi')
print(TestSubClass.obj1())
# ('TestSubClass', 'hi')
Way 2
Maybe you should use property decorator so the disered output will be accessible by instances of a certain class instead of the class itself:
class TestClass:
_obj1 = 'hi'
#property
def obj1(self):
return self.__class__.__name__, self._obj1
class TestSubClass(TestClass):
pass
a = TestClass()
b = TestSubClass()
print(a.obj1)
# ('TestClass', 'hi')
print(b.obj1)
# ('TestSubClass', 'hi')
If I have the following code:
class Foo(object):
bar = 1
def bah(self):
print(bar)
f = Foo()
f.bah()
It complains
NameError: global name 'bar' is not defined
How can I access class/static variable bar within method bah?
Instead of bar use self.bar or Foo.bar. Assigning to Foo.bar will create a static variable, and assigning to self.bar will create an instance variable.
Define class method:
class Foo(object):
bar = 1
#classmethod
def bah(cls):
print cls.bar
Now if bah() has to be instance method (i.e. have access to self), you can still directly access the class variable.
class Foo(object):
bar = 1
def bah(self):
print self.bar
As with all good examples, you've simplified what you're actually trying to do. This is good, but it is worth noting that python has a lot of flexibility when it comes to class versus instance variables. The same can be said of methods. For a good list of possibilities, I recommend reading Michael Fötsch' new-style classes introduction, especially sections 2 through 6.
One thing that takes a lot of work to remember when getting started is that python is not java. More than just a cliche. In java, an entire class is compiled, making the namespace resolution real simple: any variables declared outside a method (anywhere) are instance (or, if static, class) variables and are implicitly accessible within methods.
With python, the grand rule of thumb is that there are three namespaces that are searched, in order, for variables:
The function/method
The current module
Builtins
{begin pedagogy}
There are limited exceptions to this. The main one that occurs to me is that, when a class definition is being loaded, the class definition is its own implicit namespace. But this lasts only as long as the module is being loaded, and is entirely bypassed when within a method. Thus:
>>> class A(object):
foo = 'foo'
bar = foo
>>> A.foo
'foo'
>>> A.bar
'foo'
but:
>>> class B(object):
foo = 'foo'
def get_foo():
return foo
bar = get_foo()
Traceback (most recent call last):
File "<pyshell#11>", line 1, in <module>
class B(object):
File "<pyshell#11>", line 5, in B
bar = get_foo()
File "<pyshell#11>", line 4, in get_foo
return foo
NameError: global name 'foo' is not defined
{end pedagogy}
In the end, the thing to remember is that you do have access to any of the variables you want to access, but probably not implicitly. If your goals are simple and straightforward, then going for Foo.bar or self.bar will probably be sufficient. If your example is getting more complicated, or you want to do fancy things like inheritance (you can inherit static/class methods!), or the idea of referring to the name of your class within the class itself seems wrong to you, check out the intro I linked.
class Foo(object):
bar = 1
def bah(self):
print Foo.bar
f = Foo()
f.bah()
bar is your static variable and you can access it using Foo.bar.
Basically, you need to qualify your static variable with Class name.
You can access class variables by object and directly by class name from the outside or inside of class and basically, you should access class variables directly by class name because if there are the same name class and instance variables, the same name instance variable is prioritized while the same name instance variable is ignored when accessed by object. So, using class name is safer than using object to access class variables.
For example, you can access the class variable by object and directly by class name from the outside of the class as shown below:
class Person:
name = "John" # Class variable
obj = Person()
print(obj.name) # By object
print(Person.name) # By class name
Output:
John
John
But, if you add the same name instance variable as the class variable by object:
class Person:
name = "John" # Class variable
obj = Person()
obj.name = "Tom" # Adds the same name instance variable as class variable
print(obj.name) # By object
print(Person.name) # By class name
Or, if you add the same name instance variable as the class variable by self in __init__():
class Person:
name = "John" # Class variable
def __init__(self, name):
self.name = name # Adds the same name instance variable as class variable
obj = Person("Tom")
print(obj.name) # By object
print(Person.name) # By class name
The same name instance variable is prioritized when accessed by object:
Tom # By object
John # By class name
And, you can also access the class variable by self and directly by class name from the inside of the instance method as shown below:
class Person:
name = "John" # Class variable
def test(self): # Instance method
print(self.name) # By "self"
print(Person.name) # By class name
obj = Person()
obj.test()
Output:
John
John
But, if you add the same name instance variable as the class variable by object:
class Person:
name = "John" # Class variable
def test(self): # Instance method
print(self.name) # By "self"
print(Person.name) # By class name
obj = Person()
obj.name = "Tom" # Adds the same name instance variable as the class variable
obj.test()
Or, if you add the same name instance variable as the class variable by self in __init__():
class Person:
name = "John" # Class variable
def __init__(self, name):
self.name = name # Adds the same name instance variable as the class variable
def test(self): # Instance method
print(self.name) # By "self"
print(Person.name) # Directly by class name
obj = Person("Tom")
obj.test()
The same name instance variable is prioritized when accessed by self:
Tom # By "self"
John # By class name
I need to make a mixin that knows the name of the class who is using it. Sort of like:
class FooMixin(...):
bar = self.__class__
Except that self is not defined at attribute definition time. Is there a clean way to achieve this so it's transparent for the class who inherits the mixin?
At the time of definition of your mixin, nobody knows in which classes your mixin is used. You can only get the name dynamically in class methods by using self.__class__.__name__:
class FooMixin(object):
def some_method(self):
print "I'm in class %s" % self.__class__.__name__
class Main(FooMixin):
pass
instance = Main()
instance.some_method() # "I'm in class Main"
Daniel's answer gives the reason why this is not possible in the declarative way you seem to like it - nobody knows at Mixin's definition-time where and when it will be used.
However, if you don't care about the time, but want the syntax, meaning you want to access bar defined as property in Mixin, and return self.class, this should work:
class classproperty(object):
def __get__(self, instance, clazz):
return clazz
class Mixin(object):
bar = classproperty()
class Foo(Mixin):
pass
print Foo().bar
First off, no special action is needed to know the name of a class:
class MyMixin(object):
def frob(self):
print "frobbing a", self.__class__.__name__
class Foo(MyMixin): pass
class Bar(MyMixin): pass
>>> Foo().frob()
frobbing a Foo
>>> Bar().frob()
frobbing a Bar
similarly, no special action is needed to discover subclasses:
>>> MyMixin.__subclasses__()
[__main__.Foo, __main__.Bar]
If these aren't what you need, because you want to take action when your base class is subclassed, you need a metaclass!:
class MyMixinMeta(type):
def __init__(cls, name, bases, attrs):
if bases != (object,):
print name, cls, "is a subclass of", bases
class MyMixin(object):
__metaclass__ = MyMixinMeta
def frob(self):
print "frobbing a", self.__class__.__name__
>>> class Foo(MyMixin): pass
Foo <class '__main__.Foo'> is a subclass of (<class '__main__.MyMixin'>,)
>>> class Bar(MyMixin): pass
Bar <class '__main__.Bar'> is a subclass of (<class '__main__.MyMixin'>,)
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?