Inherit and then override parent init - python

I have the following code:
# file1.py
class GenericScript(object):
def __init__(self):
self.start_time = time.time()
self.date_stem = str(timezone.now().date()).replace('-','')
self.script_name = os.path.basename(sys.argv[0]).replace('.py','')
self.file_name = None
self.log_file = None
self.integrity_field = '%s+%s' % (self.script_name, str(int(time.time())))
# file2.py
class RTUpdater(GenericScript):
def __init__(self):
self.integrity_field = '%s+%s' % (self.script_name, self.date_stem)
self.update_title_data = False
self.update_title_ranking = True
self.update_title_box_office = True
self.update_person_ranking = True
What I am trying to do is call RTUpdate() and get it to initialize all the items first in the parent Class and then add to those with its own __init__ method. However, when I call it, the self.integrity_field keep raising an error because self.script_name is not defined, meaning it's not first inheriting the parent __init__ variables. Here is how I'm calling it:
if __name__ == '__main__':
x = RTUpdater()
main(x)
>>> AttributeError: 'RTUpdater' object has no attribute 'script_name'
What am I doing wrong and how would I fix this?

You need to explicitly call the constructor of the parent class. Based on your inheritance of object I'm guessing you're using Python 2, so try this:
class RTUpdater(GenericScript):
def __init__(self):
super(RTUpdater, self).__init__()
# ...
If you are actually using Python 3 you can just use super().__init__().

You completly override __init__ as far as I see it. Just call super().__init__() in your inherited __init__ (so that the init of the parent will be run) and check if the error still persists.
Or if you are using Python 2 you need to fix the classes for the super call: super(RTUpdater, self).__init__().

Related

override a method of a class with an method from another class

I have following code:
class SomeClass:
def __init__(self) -> None:
pass
def some_class_function(self, par):
print(par)
class SomeOtherClass:
def __init__(self) -> None:
pass
def some_other_class_function(self, par):
print(par+1)
if __name__ == "__main__":
sc = SomeClass()
sc.some_class_function = SomeOtherClass.some_other_class_function
sc.some_class_function(1)
When I execute the code I get
TypeError: some_other_class_function() missing 1 required positional argument: 'par'
How can I override the method of the first class with the method of the second class properly?
As you have noted in the comments, you are interested in adding method that will use sc as the "self" instance.
To that end, see this post. To summarize, you can either add a function to the class definition (affecting future instances of the same class), or bind the function to the particular instance.
As an example, consider the following class and function.
class Test():
def __init__(self):
self.phrase = "hello world"
def func(self):
print("this is the old method")
def test_func(self):
print(self.phrase)
For the first approach, we could do the following
test = Test()
Test.func = test_func
test.func()
Note that future instances of Test will have this function as an attribute. For example, running Test().func() will still result in the same output, even though the method is being used on a new class instance.
For the second, we could do the following.
import types
test = Test()
test.func = types.MethodType(test_func, test)
test.func()
In this case, running the line Test().func() will result in the output "this is the old method" because func has not been overwritten for new instances.
You need to initialize the class to call its method.
sc = SomeClass()
sco = SomeOtherClass() # initialize the second call to call it's method
sc.some_class_function = sco.some_other_class_function
sc.some_class_function(1)

Make class method able to check if it has been called

Here is a nice way to make a function object self-aware and able to check if it has been called (per this answer):
def example():
example.has_been_called = True
pass
example.has_been_called = False
example()
#Actual Code!:
if example.has_been_called:
print("foo bar")
How can I translate this solution to a class instance method?
I have tried this:
class Example:
def method_one(self):
self.method_one.has_been_called = True
pass
def method_two(self):
self.method_two.has_been_called = True
pass
example = Example()
example.method_one()
#Actual Code!:
if example.method_one.has_been_called:
print("foo bar")
but I keep getting:
> Traceback (most recent call last): File "c:\python
> projects\dog\tests.py", line 8, in <module>
> example.run() File "c:\python projects\dog\tests.py", line 4, in run
> self.run.has_been_called = True AttributeError: 'method' object has no attribute 'has_been_called'
Instance methods are in fact members of the class. If you want to know whether an method has been called on a specific object, you should make the indicator a boolean member of the instance:
class Example:
has_been_called = False
def run(self):
self.has_been_called = True
After example = Example(), example.has_been_called will be true if and only if example.run() has been called
If you want to know whether the method has been called on any object, you should make the indicator a member of the class:
class Example:
has_been_called = False
def run(self):
Example.has_been_called = True # global
# self.__class__.has_been_called = True # per sub_class
Here Example.has_been_called (also accessible for any instance from Example) would be true if and only if it has been called on one instance. The difference between the global and per sub-class way only matters if you have subclasses.
For a class method, the method already receives a class object and not an instance, so it would be:
class Example:
has_been_called = False
#classmethod
def run(cls):
Example.has_been_called = True # global
# cls.has_been_called = True # per sub_class
Beware in the per sub-class way, the attribute is set on the subclass, so you should examine it only from an instance.
Even if it is possible, you would have no reason to set an attribute on the method itself. The code should be:
class Example:
has_been_called = False
def run(self):
Example.run.has_been_called = True
but it would be non Pythonic.
Create a dict to store the functions that have been run.
class Example:
def __init__(self):
self.has_been_called = {}
def run(self):
self.has_been_called["run"] = True
example = Example()
example.run()
#Actual Code!:
try:
if example.has_been_called["run"]:
print("foo bar")
except KeyError:
pass
If you comment example.run(), no error is raised.
Using a dictionary also allows you to apply the same process to other methods without creating a ton of variables.
Every use of self.run produces a new instance of method, not the actual function bound to Example.run. You need a reference to the actual function, which you can get through the special name __class__, which here will refer to the static class Example. You also need to ensure the attribute is initialized (though you don't need any special magic here; the name run is bound to an ordinary function at this point and doesn't need to be used as an attribute).
class Example:
def run(self):
__class__.run.has_been_called = True
run.has_been_called = False
If instead you want to update an override in a subclass, use type(self) instead of __class__.
As you want each instance to have its own has_been_called flag, then you shouldn't attempt to define has_been_called on the method, as the method exists on the class object, not on the instance (self).
Instead, define it as an attribute on the instance object (self). So just skip the .run part:
class Example:
def run(self):
self.has_been_called = True
example = Example()
example.run()
#Actual Code!:
if example.has_been_called:
print("foo bar")
If you want to have a separate flag for each method, then use a dictionary:
from collections import defaultdict
class Example:
def __init__(self):
self.has_been_called = defaultdict(bool)
def run(self):
self.has_been_called["run"] = True
example = Example()
example.run()
if example.has_been_called["run"]:
print("foo bar")
Don't use .'s in variable names:
class Example:
def method_one(self):
self.method_one_has_been_called = True
def method_two(self):
self.method_two_has_been_called = True
example = Example()
example.method_one()
#Actual Code!:
if example.method_one_has_been_called:
print("foo bar")
Output:
foo bar

create instance of a class in the same class's definition in python

I am trying to create a new MyClass instance in MyClass's definition.
Why does this code fail and how can achieve it?
class MyClass:
def __init__(self):
self.child=MyClass()
mc=MyClass()
Well, it fails because it has infinite recursion. Think about it, if every MyClass has a child which is a MyClass, it will go on for infinity!
You can resolve this a couple of ways. First, you can have a parameter to the constructor:
class MyClass:
def __init__(self, create = True):
if create:
self.child = MyClass(False)
mc = MyClass()
Or, you can have another, external method:
class MyClass:
def set_child(self,child = None):
# I prefer to make child optional for ease of use.
child = MyClass() if child is None else child
self.child=child
mc=MyClass()
mc.set_child()
I personally prefer the first solution as it means that outside objects don't need to know anything about the class. Of course, you could combine the two:
class MyClass:
def __init__(self, create):
if create:
self.set_child(create=False)
def set_child(self,child = None, create = True):
child = MyClass(create) if child is None else child
self.child=child
mc=MyClass()
This way mc has a child by default and you have the option of setting the child whenever you like.
Then there is also the "let's create a certain number" approach:
class MyClass:
def __init__(self, count = 10):
count -= 1
if count:
# the first child gets the value 9.
# the second gets 8.
# when the count gets to 0, stop!
self.child = MyClass(count)
Aside: If you want to get an object's class, you can use the value obj.__class__. That will output MyClass in all of the examples above.
You're making an infinitely recursing call — MyClass is creating another MyClass during initialization, and thus it recurses infinitely.
You may want to do something like:
class MyClass:
def create_child(self):
self.child=MyClass()
mc=MyClass()
mc.create_child()
If you're feeling particularly naughty, you could try:
class MyClass(object):
#property
def child(self):
if self._child is None: self._child = MyClass()
return self._child
def __init__(self):
self._child=None
mc=MyClass()
What you did there is actualy recursive, the new isntance of MyClass will create a new instance that will in turn create a new one, etc ...
Soo I supose that is why your code fails, I can't tell for sure since you didn't post the error message.
I suggest to define two classes:
class MyClass(object):
def __init__(self):
self.child = MyChildClass()
...many other methods...
class MyChildClass(MyClass):
def __init__(self):
pass
I think that if two classes must behave in two different ways, they must be different (although one can subclass the other)

How can I use Python's super() to update a parent value?

I'm new to inheritance and all of the previous discussions about inheritance and Python's super() function are a bit over my head. I currently use the following code to update a parent object's value.
#!/usr/bin/env python
# test.py
class Master(object):
mydata = []
def __init__(self):
s1 = Sub1(self)
s2 = Sub2(self)
class Sub1(object):
def __init__(self,p):
self.p = p
self.p.mydata.append(1)
class Sub2(object):
def __init__(self,p):
self.p = p
self.p.mydata.append(2)
if __name__ == "__main__":
m = Master()
print m.mydata
This command line returns as follows:
user#host:~$ ./test.py
[1, 2]
Is there a better way to do this with super() instead of passing the the "self" reference to the child?
super only applies to class inheritance structures, where Sub1 and Sub2 are subclasses of Master.
In your example, you use a containment structure, Sub1 and Sub2 are attributes of Master, and you have no use for super calls.
Also, you generally really do not want to use a mutable list as a class attribute; appending to it will alter the one copy of the list (defined in the class) globally, not per instance; initiate the list in the Master.__init__ method instead:
class Master(object):
mydata = None
def __init__(self):
self.mydata = []
The __init__ function is called to set up a new instance, and by assigning a new empty list to self there, you ensure that each instance has it's own copy.
Here's how you would do it by inheritance. You first have Master which is the parent class, then Sub1 and Sub2 will inherit from Master and become subclasses. All subclasses can access methods and variables in the parent class. This might be a duplicate of: Call a parent class's method from child class in Python?
#!/usr/bin/env python
# test.py
class Master(object):
mydata = []
def __init__(self):
s1 = Sub1()
s2 = Sub2()
class Sub1(Master):
def __init__(self):
super(Sub1, self).mydata.append(1)
class Sub2(Master):
def __init__(self):
super(Sub2, self).mydata.append(2)
if __name__ == "__main__":
m = Master()
print m.mydata

Method assignment and objects

i've got a problem with python:
I want to assign a method to an object form another class, but in this method use its own attributes. Since i have many container with different use methods in my project (not in that example) i dont want to use inheritance, thad would force me to create a custom class for each instance.
class container():
def __init__(self):
self.info = "undefiend info attribute"
def use(self):
print self.info
class tree():
def __init__(self):
# create container instance
b = container()
# change b's info attribute
b.info = "b's info attribute"
# bound method test is set as use of b and in this case unbound, i think
b.use = self.test
# should read b's info attribute and print it
# should output: test: b's info attribute but test is bound in some way to the tree object
print b.use()
# bound method test
def test(self):
return "test: "+self.info
if __name__ == "__main__":
b = tree()
Thank you very much for reading this, and perhaps helping me! :)
Here you go. You should know that self.test is already bound since by the time you are in __init__ the instance has already been created and its methods are bound. Therefore you must access the unbound member by using the im_func member, and binding it with MethodType.
import types
class container():
def __init__(self):
self.info = "undefiend info attribute"
def use(self):
print self.info
class tree():
def __init__(self):
# create container instance
b = container()
# change b's info attribute
b.info = "b's info attribute"
# bound method test is set as use of b and in this case unbound, i think
b.use = types.MethodType(self.test.im_func, b, b.__class__)
# should read b's info attribute and print it
# should output: test: b's info attribute but test is bound in some way to the tree object
print b.use()
# bound method test
def test(self):
return "test: "+self.info
if __name__ == "__main__":
b = tree()
Looks like you are trying to use inheritance? The tree inherits from the container?
Use tree.test instead of self.test. The method attributes of an instance are bound to that instance.
Do not move methods around dynamically.
Just Use Delegation. Avoid Magic.
Pass the "Tree" object to the Container. It saves trying to move methods around.
class Container( object ):
def use( self, context ):
print context.info
context.test()
class Tree( object ):
def __init__( self, theContainerToUse ):
b= theContinerToUse( self )
print b.use()
def test( self ):
print "test"+self.info

Categories