Refer to a class outside its method? - python

I need to deliver something like this in my program
class the_class_name(Parent):
the_attribute = self.parent_class_method()
#the parent class method will return a value
#but I cannot use self here since there's no self
How can I carry this out? Is there any other alternative that can do the job for me?
I have tried using __init__ like this:
def __init__(self):
Parent.__init__(self)
self.attribute = self.the_method()
But then I have problem creating the object, it won't receive any parameters that the Parent class normally receives anymore

Sounds like you are looking for __init__:
class TheClassName(Parent):
def __init__(self):
# Set attribute to the result of the parent method
self.attribute = super(TheClassName, self).the_method()
EDIT
If your parent class has parameters in it's own __init__ function, include them in the child class:
class Parent(object):
def __init__(self, foo, bar):
...
#classmethod
def the_method(cls):
...
class TheClassName(Parent):
def __init__(self, foo, bar):
super(TheClassName, self).__init__(foo, bar)
self.attribute = super(TheClassName, self).the_method()
I don't quite understand why you don't just call the parent method on your child object when you need the value though.

There is no self at that point of the creation of the subclass, nor is there an instance of the Parent class. That means the only Parent class methods you could call would have to be either static or class methods.
To demonstrate:
class Parent(object):
#staticmethod
def static_method():
return 42
#classmethod
def class_method(cls):
return 43
class TheClassName(Parent):
the_attribute = Parent.static_method()
another_attribute = Parent.class_method()
print(TheClassName.the_attribute) # -> 42
print(TheClassName.another_attribute) # -> 43

You must use class methods, declared with the #classmethod decorator, or a #staticmethod. The #classmethod decorator is preferable so that inheritance is handled correctly, i.e. the method is invoked on the derived class (a bit of a technicality, if you are still learning this).
class Alpha(object):
#classmethod
def method1(cls):
return 'method1 has been called on {}'.format(cls)
class Beta(Alpha):
def __init__(self):
self.myattr = Beta.method1()
print(Beta().myattr)
method1 has been called on class <'__main__.Beta'>

Use
super(ClassName, self).methodname(arg)
inside a method
def child_method(self, arg):
super(ClassName, self).methodname(arg)
You cannot use self outside a method.

Related

Inheritance in Python for variable that's not parameter

In Python, I'm using inheritance for a class. The initial init for the main parent class is below:
def __init__(self, Date = None):
self.Date = Date
self.DatabaseClass = Database()
self.Connection = self.DatabaseClass.databaseConnection()
I've inherited the class into the child class, but am wondering what the correct approach would be to inherit DatabaseClass and Connection variables, i.e., what would be in def __init__?
You just need to call the inherited __init__ method from your own class's __init__ method.
class Child(Parent):
def __init__(self, Date=None, other, arguments):
super().__init__(Date)
# ...

When running a method from a Python superclass, how can I know the name of the child class that invoked it?

Let's say I have this parent class:
class BaseTestCase(unittest.TestCase):
#classmethod
def setUpClass(cls):
# I want to assign the name of the class that called
# the super class in a variable.
cls.child_class_name = ??
# Do some more stuff...
And I have this class that inherits from the BaseTestCase class above:
class MyTestCase(BaseTestCase):
#classmethod
def setUpClass(cls):
# Call SetUpClass from parent (BaseTestCase)
super(cls, cls).setUpClass()
# Do more stuff...
Since many classes can inherit from the same parent class. How can I know the name of the class that invoked the parent class in a given time?
I hope my question make sense. :S
cls.__name__ is always the name of the current class, because cls is bound the actual class object on which the class method was called.
In other words, cls is not a reference to the class on which the method is defined.
Note that you should not use super(cls, cls)! That'll lead to infinite recursion if you were to create a derived class from MyTestCase! Use the actual class, always:
class MyTestCase(BaseTestCase):
#classmethod
def setUpClass(cls):
# Call SetUpClass from parent (BaseTestCase)
super(MyTestCase, cls).setUpClass()
# Do more stuff...
Demo:
>>> class Foo(object):
... #classmethod
... def spam(cls):
... print(cls.__name__)
...
>>> class Bar(Foo):
... #classmethod
... def spam(cls):
... super(Bar, cls).spam()
...
>>> Bar.spam()
Bar
>>> Foo.spam()
Foo

Subclassing a Python class to inherit attributes of super class

I'm trying to inherit attributes from a super class but they are not being initialized correctly:
class Thing(object):
def __init__(self):
self.attribute1 = "attribute1"
class OtherThing(Thing):
def __init__(self):
super(Thing, self).__init__()
print self.attribute1
This throws an error since attribute1 is not an attribute of OtherThing, even though Thing.attribute1 exists. I thought this was the correct way to inherit and extend a super class. Am I doing something wrong? I don't want to create an instance of Thing and use its attributes, I need it to inherit this for simplicity.
You have to give, as argument, the class name (where it is being called) to super():
super(OtherThing, self).__init__()
According to Python docs:
... super can be used to refer to parent classes without naming them
explicitly, thus making the code more maintainable.
so you are not supposed to give the parent class.
See this example from Python docs too:
class C(B):
def method(self, arg):
super(C, self).method(arg)
Python3 makes this easy:
#!/usr/local/cpython-3.3/bin/python
class Thing(object):
def __init__(self):
self.attribute1 = "attribute1"
class OtherThing(Thing):
def __init__(self):
#super(Thing, self).__init__()
super().__init__()
print(self.attribute1)
def main():
otherthing = OtherThing()
main()

how to make child class call parent class __init__ automatically?

i had a class called CacheObject,and many class extend from it.
now i need to add something common on all classes from this class so i write this
class CacheObject(object):
def __init__(self):
self.updatedict = dict()
but the child class didn't obtain the updatedict attribute.i know calling super init function was optional in python,but is there an easy way to force all of them to add the init rather than walk all the classes and modify them one by one?
I was in a situation where I wanted classes to always call their base classes' constructor in order before they call their own. The following is Python3 code that should do what you want:
class meta(type):
def __init__(cls,name,bases,dct):
def auto__call__init__(self, *a, **kw):
for base in cls.__bases__:
base.__init__(self, *a, **kw)
cls.__init__child_(self, *a, **kw)
cls.__init__child_ = cls.__init__
cls.__init__ = auto__call__init__
class A(metaclass=meta):
def __init__(self):
print("Parent")
class B(A):
def __init__(self):
print("Child")
To illustrate, it will behave as follows:
>>> B()
Parent
Child
<__main__.B object at 0x000001F8EF251F28>
>>> A()
Parent
<__main__.A object at 0x000001F8EF2BB2B0>
I suggest a non-code fix:
Document that super().__init__() should be called by your subclasses before they use any other methods defined in it.
This is not an uncommon restriction. See, for instance, the documentation for threading.Thread in the standard library, which says:
If the subclass overrides the constructor, it must make sure to invoke the base class constructor (Thread.__init__()) before doing anything else to the thread.
There are probably many other examples, I just happened to have that doc page open.
You can override __new__. As long as your base classes doesn't override __new__ without calling super().__new__, then you'll be fine.
class CacheObject(object):
def __new__(cls, *args, **kwargs):
instance = super().__new__(cls, *args, **kwargs)
instance.updatedict = {}
return instance
class Foo(CacheObject):
def __init__(self):
pass
However, as some commenters said, the motivation for this seems a little shady. You should perhaps just add the super calls instead.
This isn't what you asked for, but how about making updatedict a property, so that it doesn't need to be set in __init__:
class CacheObject(object):
#property
def updatedict(self):
try:
return self._updatedict
except AttributeError:
self._updatedict = dict()
return self._updatedict
Hopefully this achieves the real goal, that you don't want to have to touch every subclass (other than to make sure none uses an attribute called updatedict for something else, of course).
There are some odd gotchas, though, because it is different from setting updatedict in __init__ as in your question. For example, the content of CacheObject().__dict__ is different. It has no key updatedict because I've put that key in the class, not in each instance.
Regardless of motivation, another option is to use __init_subclass__() (Python 3.6+) to get this kind of behavior. (For example, I'm using it because I want users not familiar with the intricacies of Python to be able to inherit from a class to create specific engineering models, and I'm trying to keep the structure of the class they have to define very basic.)
In the case of your example,
class CacheObject:
def __init__(self) -> None:
self.updatedict = dict()
def __init_subclass__(cls) -> None:
orig_init = cls.__init__
#wraps(orig_init)
def __init__(self, *args, **kwargs):
orig_init(self, *args, **kwargs)
super(self.__class__, self).__init__()
cls.__init__ = __init__
What this does is any class that subclasses CacheObject will now, when created, have its __init__ function wrapped by the parent class—we're replacing it with a new function that calls the original, and then calls super() (the parent's) __init__ function. So now, even if the child class overrides the parent __init__, at the instance's creation time, its __init__ is then wrapped by a function that calls it and then calls its parent.
You can add a decorator to your classes :
def my_decorator(cls):
old_init = cls.__init__
def new_init(self):
self.updatedict = dict()
old_init(self)
cls.__init__ = new_init
return cls
#my_decorator
class SubClass(CacheObject):
pass
if you want to add the decorators to all the subclasses automatically, use a metaclass:
class myMeta(type):
def __new__(cls, name, parents, dct):
return my_decorator(super().__new__(cls, name, parents, dct))
class CacheObject(object, metaclass=myMeta):
pass

Calling a class method upon creation of Python classes

I'd like to automatically run some code upon class creation that can call other class methods. I have not found a way of doing so from within the class declaration itself and end up creating a #classmethod called __clsinit__ and call it from the defining scope immediately after the class declaration. Is there a method I can define such that it will get automatically called after the class object is created?
You can do this with a metaclass or a class decorator.
A class decorator (since 2.6) is probably easier to understand:
def call_clsinit(cls):
cls._clsinit()
return cls
#call_clsinit
class MyClass:
#classmethod
def _clsinit(cls):
print "MyClass._clsinit()"
Metaclasses are more powerful; they can call code and modify the ingredients of the class before it is created as well as afterwards (also, they can be inherited):
def call_clsinit(*args, **kwargs):
cls = type(*args, **kwargs)
cls._clsinit()
return cls;
class MyClass(object):
__metaclass__ = call_clsinit
#classmethod
def _clsinit(cls):
print "MyClass._clsinit()"

Categories