Python 2.7 super method can't see child class name - python

Got the code like below:
class Type:
def __init__(self, index):
self.index = index
class MyCls(Type):
def __init__(self, index):
super(MyCls, self).__init__(index)
And after trying to compile - got next error message on the super line:
Detail NameError: global name 'MyCls' is not defined
How should I define MyCls to make the above code work?

The snippet you've shown shouldn't trigger a NameError - classes are allowed to refer to themselves in this way
However, super only works with new-style classes - trying to instantiate a MyCls object will raise a TypeError. To fix this, the class Type needs to explicitly inherit from object:
class Type(object):
def __init__(self, index):
self.index = index
MyCls can stay as it is in this case. Then you have:
>>> a = MyCls(6)
>>> a
<__main__.MyCls object at 0x7f5ca8c2aa10>
>>> a.index
6

Related

Using metaclasses in order to define methods, class methods / instance methods

I am trying to understand deeper how metaclasses work in python. My problem is the following, I want to use metaclasses in order to define a method for each class which would use a class attribute defined within the metaclass. For instance, this has application for registration.
Here is a working example:
import functools
def dec_register(func):
#functools.wraps(func)
def wrapper_register(*args, **kwargs):
(args[0].__class__.list_register_instances).append(args[0])
return func(*args, **kwargs)
return wrapper_register
dict_register_classes = {}
class register(type):
def __new__(meta, name, bases, attrs):
dict_register_classes[name] = cls = type.__new__(meta, name, bases, attrs) # assigniation from right to left
cls.list_register_instances = []
cls.print_register = meta.print_register
return cls
def print_register(self):
for element in self.list_register_instances:
print(element)
def print_register_class(cls):
for element in cls.list_register_instances:
print(element)
#
class Foo(metaclass=register):
#dec_register
def __init__(self):
pass
def print_register(self):
pass
class Boo(metaclass=register):
#dec_register
def __init__(self):
pass
def print_register(self):
pass
f = Foo()
f_ = Foo()
b = Boo()
print(f.list_register_instances)
print(b.list_register_instances)
print(dict_register_classes)
print("1")
f.print_register()
print("2")
Foo.print_register_class()
print("3")
f.print_register_class()
print("4")
Foo.print_register()
The test I am making at the end do not work as I was expected. I apologize in advance if what I am saying is not using the proper syntax, I am trying to be as clear as possible :
I was thinking that the line cls.print_register = meta.print_register is defining a method within the class using the method defined within the metaclass. Thus it is a method that I can use on an object. I can also use it a class method since it is defined in the metaclass. However, though the following works :
print("1")
f.print_register()
this do not work correctly :
print("4")
Foo.print_register()
with error :
Foo.print_register()
TypeError: print_register() missing 1 required positional argument: 'self'
Same for test 2 and 3, where I was expecting that if a method is defined on the class level, it should also be defined on the object level. However, test 3 is raising an error.
print("2")
Foo.print_register_class()
print("3")
f.print_register_class()
Hence, can you please explain me how come my understanding of class methods is wrong ? I would like to be able to call the method print_register either on the class or on the object.
Perhaps it could help to know that in fact I was trying to reproduce the following very simple example :
# example without anything fancy:
class Foo:
list_register_instances = []
def __init__(self):
self.__class__.list_register_instances.append(self)
#classmethod
def print_register(cls):
for element in cls.list_register_instances:
print(element)
Am I not doing the exact same thing with a metaclass ? A classmethod can be used either on a class or on objects.
Also if you have any tips about code structure I would greatly appreciate it. I must be very bad at the syntax of metaclasses.
Fundamentally, because you have shadowed print_register on your instance of the metaclass (your class).
So when you do Foo.print_register, it finds the print_register you defined in
class Foo(metaclass=register):
...
def print_register(self):
pass
Which of course, is just the plain function print_register, which requires the self argument.
This is (almost) the same thing that would happen with just a regular class and it's instances:
class Foo:
def bar(self):
print("I am a bar")
foo = Foo()
foo.bar = lambda x: print("I've hijacked bar")
foo.bar()
Note:
In [1]: class Meta(type):
...: def print_register(self):
...: print('hi')
...:
In [2]: class Foo(metaclass=Meta):
...: pass
...:
In [3]: Foo.print_register()
hi
In [4]: class Foo(metaclass=Meta):
...: def print_register(self):
...: print('hello')
...:
In [5]: Foo.print_register()
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-5-a42427fde947> in <module>
----> 1 Foo.print_register()
TypeError: print_register() missing 1 required positional argument: 'self'
However, you do this in your metaclass constructor as well!
cls.print_register = meta.print_register
Which is effectively like defining that function in your class definition... not sure why you are doing this though.
You are not doing the exact same thing as using a classmethod, which is a custom descriptor that handles the binding of methods to instances in just the way you'd need to be able to call it on a class or on an instance. That is not the same as defining a method on the class and on the instance! You could just do this in your metaclass __new__, i.e. cls.print_register = classmethod(meta.print_register) and leave def print_register(self) out of your class definitions:
import functools
def dec_register(func):
#functools.wraps(func)
def wrapper_register(*args, **kwargs):
(args[0].__class__.list_register_instances).append(args[0])
return func(*args, **kwargs)
return wrapper_register
dict_register_classes = {}
class register(type):
def __new__(meta, name, bases, attrs):
dict_register_classes[name] = cls = type.__new__(meta, name, bases, attrs) # assigniation from right to left
cls.list_register_instances = []
cls.print_register = classmethod(meta.print_register) # just create the classmethod manually!
return cls
def print_register(self):
for element in self.list_register_instances:
print(element)
def print_register_class(cls):
for element in cls.list_register_instances:
print(element)
#
class Foo(metaclass=register):
#dec_register
def __init__(self):
pass
Note, print_register doesn't have to be defined inside your metaclass, indeed, in this case, I would just define it at the module level:
def print_register(self):
for element in self.list_register_instances:
print(element)
...
class register(type):
def __new__(meta, name, bases, attrs):
dict_register_classes[name] = cls = type.__new__(meta, name, bases, attrs) # assigniation from right to left
cls.list_register_instances = []
cls.print_register = classmethod(print_register)
return cls
...
I think you understand metaclasses sufficiently, actually, it is your understanding of classmethod that is incorrect, as far as I can tell. If you want to understand how classmethod works, indeed, how method-instance binding works for regular functions, you need to understand descriptors. Here's an enlightening link. Function objects are descriptors, they bind the instance as the first argument to themselves when called on an instance (rather, they create a method object and return that, but it is basically partial application). classmethod objects are another kind of descriptor, one that binds the class to the first argument to the function it decorates when called on either the class or the instance. The link describes how you could write classmethod using pure python.

What is the best practice for class properties of the same type in python? [duplicate]

I have the following code:
import numpy as np
class ClassProperty(property):
def __get__(self, cls, owner):
return self.fget.__get__(None, owner)()
def coord(cls, c):
if cls.dimension <= 2:
return c
else:
return c + [0]*(cls.dimension-2)
class Basis_NonI(object):
#ClassProperty
#classmethod
def zerocoord(cls):
return coord(cls, [0,0])
def __init__(self, dimension):
pass
class Basis_D(Basis_NonI):
dimension = 2
proj_matrix = np.array([Basis_D.zerocoord, Basis_D.zerocoord])
def __init__(self, dimension):
super(Basis_D, self).__init__(Basis_D.dimension)
where basically I want dimension and proj_matrixto be class attributes of Basis_D.
When I run it, the following error is given:
proj_matrix = np.array([Basis_D.zerocoord, Basis_D.zerocoord])
NameError: name 'Basis_D' is not defined
--
What I don't understand is that I can use Basis_D.dimension in the init, so why does it not recongise the name Basis_D when I use it to define proj_matrix?
class is an executable statement. When the module is first imported (for a given process), all the code at the top-level of the class statement is executed, all names defined that way are collected into a dict, then the class object is created with this dict, and finally bound to the class name. IOW, at this point:
class Basis_D(Basis_NonI):
dimension = 2
# HERE
proj_matrix = np.array([Basis_D.zerocoord, Basis_D.zerocoord])
the class has not yet been created nor bound to the name Basis_D.
Now by the time __init__ is called, the class has already been created and bound to the module-level name Basis_D, so the name can be resolved.
FWIW, you shouldn't directly reference Basis_D in your methods, but type(self) (or even self - if a name is not resolved as an instance attribute, it's looked up on the class).
Also, why do you insist on using class attributes ? Do you understand that your project_matrix array will be shared amongst all instances of Basis_D ?
Basis_D gets created once all the statements inside it are executed and reaches the end.
You can check that using globals() dictionary.
class Basis_D(Basis_NonI):
dimension = 2
print('Basis_D got created?:',bool(globals().get('Basis_D')))
#proj_matrix = np.array([Basis_D.zerocoord, Basis_D.zerocoord])
def __init__(self, dimension):
super(Basis_D, self).__init__(Basis_D.dimension)
print('Basis_D got created?:',bool(globals().get('Basis_D')))
=================== RESTART: D:/PythonWorkspace/sometry.py ===================
Basis_D got created?: False
Basis_D got created?: True

calling a base class method in the child class python

What is going on. I have looked at other solutions on stack overflow but non seem to work from what I have seen. I have a base object with a method that changes the value of the base attribute. When I call the base function in a child class (Inheritance) I get that the child class does not have the attribute "baseAttribute"
class GameObject(object):
#This is the base class for gameObjects
def __init__(self):
self.components = {}
def addComponent(self, comp):
self.components[0] = comp #ignore the index. Placed 0 just for illustration
class Circle(GameObject):
#circle game object
def __init__(self):
super(GameObject,self).__init__()
#PROBLEM STATEMENT
self.addComponent(AComponentObject())
#or super(GameObject,self).addComponent(self,AComponentObject())
#or GameObject.addComponent(self, AComponentObject())
EDIT:
Apologies, I never originally passed in a self.
Simple - leave out the second self:
self.addComponent(AComponentObject())
You see, the above actually translates to
addComponent(self, AComponentObject())
In other words: in essence "OO" works on functions that have an implicit this/self pointer (however you name that) as argument.
You are using incorrect arguments for .addComponent() method.
# ...
class Circle(GameObject):
def __init__(self):
super(GameObject,self).__init__()
# NOT A PROBLEM STATEMENT ANYMORE
self.addComponent(AComponentObject())
# ...

How to correctly inherit from class that returns other class based on condition?

I will first write the code and than the full explanation of what I am trying to achieve as it is easier this way:
global child_selector
class Base(object):
def __init__(self):
self.extended_name = self.name + '_Base'
class Child1(Base):
def __init__(self):
super(Child1, self).__init__()
def print_my_name(self):
print 'I am ChildOne'
class Child2(Base):
def __init__(self):
super(Child2, self).__init__()
def print_my_name(self):
print 'I am ChildTwo'
class ChildAsBaseSelector(object):
def __new__(cls):
if child_selector == 1:
return Child1()
elif child_selector == 2:
return Child2()
else:
print 'No child selected'
Now if I create a class that inherits from Child1 or Child2 and has self.name as instance variable everything works as expected:
class Testing1(Child1):
def __init__(self):
self.name = 'Testing1'
super(Testing1, self).__init__()
a = Testing1()
a.print_my_name() # 'I am ChlidOne'
print a.extended_name # 'Testing1_Base'
But if I create another class that will inherit directly from ChildAsBaseSelector() things become fishy:
class Testing2(ChildAsBaseSelector):
def __init__(self):
self.name = 'Testing2'
super(Testing2, self).__init__()
child_selector = 1
a = Testing2()
# Will raise AttributeError: 'Child1' object has no attribute 'name'
After reading the python documentation for '__new__()' I think the problem is because: 'If __new__() does not return an instance of cls, then the new instance’s __init__() method will not be invoked.' This does not really help since i don't know how to 'fix it'.
I also know I could do something like:
if child_selector == 1:
ChildAsBaseSelector = Child1
if child_selector == 2:
ChildAsBaseSelector = Child2
And than inherit directly from ChildAsBaseSelector. But I find this somehow not elegant and pushing python flexibility to its limits.
What I really want to do is have a class that will just return another class based on a condition, that I could use then to inherit from. Any hints? I guess metaclasses (a concept I am painfully trying to understand) would come in handy now.
Any tips appreciated. Thank you!
Why don't you just make ChildAsBaseSelector inherit from Base ? In your example, super(Testing2, self).__init__() will resolves to object.__init__() (so it wouldn't do what you expect), but - as you mentionned - it won't get called anyway because it's not in the __mro__ of neither Child1 nor Child2.
Anyway: having your Base.__init__() depending on a child class setting an attribute before invoking super().__init__() is bad design - if Base needs it, then it should be passed as an argument or have a usable default in Base itself.
Also if the only raison d'être of ChildAsBaseSelector is to create instances of either Child1 or Child1 based on a global / setting / whatever, just use a factory function... Not having a 'new' keyword is really a blessing.

Communicating between objects in Python

I have something like this:
class exampleClass(object):
def doSomething(self,number):
return number + 1
class exampleClass2(exampleClass):
def callDefDoSomething(self):
print exampleClass.doSomething(5)
exampleClass2.callDefDoSomething()
-
TypeError: unbound method callDefDoSomething() must be called
with exampleClass2 instance as first argument (got nothing instead)
I started to learn about objects in Python but i cant find solution for this :(
You need to create an instance of the class, i.e., an active object, to make things work:
class exampleClass(object):
def doSomething(self,number):
return number + 1
class exampleClass2(exampleClass):
def __init__(self):
self.member1 = exampleClass()
def callDefDoSomething(self):
print self.member1.doSomething(5)
object2 = exampleClass2()
object2.callDefDoSomething()
doSomething is a method of exampleClass. Therefore, it has to be called for an instance of this class.
In callDefDoSomething, you use
exampleClass.doSomething(5)
exampleClass, however, is not an instance of this class but the class itself. What you want to use here is
self.doSomething(5)
self refers to the instance of exampleClass2, for whichcallDefDoSomethingsis invoked, which, due to inheritance, is an instance ofexampleClass`.
Regular class methods can only be called for instances not for classes. So if you want to call callDefDoSomething you have to first instantiate exampleClass2. You also have to instantiate exampleClass inside the call to callDefDoSomething.
class exampleClass(object):
def doSomething(self,number):
return number + 1
class exampleClass2(exampleClass):
def callDefDoSomething(self):
exampleClassInstance = exampleClass()
print exampleClassInstance.doSomething(5)
exampleClass2Instance = exampleClass2()
exampleClass2Instance.callDefDoSomething()
If you want to call methods on classes you should try classmethods. Check the documentation on classes in the python tutorial.
You can use this:
class exampleClass(object):
def doSomething(self,number):
return number + 1
class exampleClass2(exampleClass):
def callDefDoSomething(self):
print super(exampleClass2,self).doSomething(5)
example = exampleClass2()
example.callDefDoSomething()

Categories