Inherit from a built-in class - python

I would like to add some methods to the datetime.datetime object. It seems that we can only do that by inheriting from it and adding this new method. The problem is that this method need to update the day/month/year values of the base class and that i can't call the base init method with the new parameters.
How can I do this?

You can call the base class __init__ method.
class Foo(datetime.datetime):
def __init__(self, argument):
datetime.datetime.__init__(self, argument)
The key point here is that you need to call the __init__ method explicitly and you need to manually supply the first self argument that Python normally supplies for you.
Also, don't forget about the * and ** calling techniques to catch arguments that you don't want to deal with manually but that you still want to be able to pass to the parent constructor.

Related

python primitive class constructor - int() can't convert non-string with explicit base -

I have read contructor theory in Python explaining that constructor inheritance is possible in Python. I have inherited int class into my class a. In principle, constructor in child class have highest priority. Why constructor of my child class does not evoke?
class a(int):
def __init__(self,value1,value2):
self.value1=value1
self.value2=value2
obj1=a(2,2)
TypeError: int() can't convert non-string with explicit base
int is an immutable type in Python. That means that is does not use __init__, but __new__.
The difference between __init__ and __new__ is that __init__ is an initializer, while __new__ is a constructor. So, when __init__ is called, your instance has already been created. In order to implement immutable objects, you want the ability to "cancel" creating a new object in some cases. For instance, when int(1) is performed, it would make little sense to create a new instance equal to 1. In stead, the existing instance can simply be returned.
So, in theory, you could do something like this:
class a(int):
def __new__(cls, value1, value2):
self = super().__new__(cls)
self.value1 = value1
self.value2 = value2
return self
The error you are getting is because a(2, 2) calls int.__new__ with two arguments: 2 and 2. The two-argument form of int.__new__ expects the first argument to be a str in a base specified by the second argument.
If you want to experiment with inheritance in Python, you might find it easier to use your own defined classes -- inheritance involving built-in classes can be tricky at times.
One additional detail I wanted to add: in my experience, you usually do not want to replace the initializer or constructor of your parent class. In stead, you probably want to extend it, like I did in my example above using the call to super().__new__. But then again, there might be valid use cases.
I believe that since int is immutable; the __init__ cannot be changed, so a(2, 2) still ends up looking calling like int(2, 2)

Default call to __init__ when creating an instance

Just wanted some help understanding these lines of code:
class Parent:
def __init__(self):
print("instance created")
parent1=Parent()
parent2=Parent.__init__(parent1)
output
instance created
instance created
I am trying to understand how a constructor is called in OOP for python.
In the first line the the method __init__ is called by default and the self argument that is passed is somehow parent1?
The second line is the more traditional way I would've thought methods would be called. Since __init__ takes an instance of the parent class as an argument I passed parent1 and it works. I get what is happening in the second line, just wanted to ask what the computer is doing to create the instance parent1 in the first line.
__init__ is not a constructor, it's an initializer. When Python creates an object, it's actually created in __new__ (usually left as the default, which just makes an empty object of the right class), which receives a reference to the class, and returns an instance (typically empty; no attributes set). The resulting instance is passed implicitly as the self in __init__, which then establishes the instance attributes.
Typically, you don't call special methods like __init__ directly (aside from cases involving super() with cooperative inheritance), you just let Python do it for you. The only way to avoid calling __init__ would be to explicitly invoke the class's __new__ (which is also extremely unusual).
__init__ is the equivalent to a constructor in Python. Think of an object oriented language as one that has a mandatory argument for functions that represent object methods, so you always have access to that object in that function. Most languages don't make you type out the way you pass in this. Python uses self, and makes you type it out for every method. It's the same thing, it's just not doing extra work for you.
So when Python instantiates a class, it passes the class to the class's __new__ function, generates an object, and then passes that object to the class's __init__ function as the first argument.
You are correct that __init__() work like a constructor, is automatically runs when an object is instantiated (as would happen with Java constructor, if that helps). Although you can call __init__, you shouldn't call functions/methods starting with _ or __, they are meant to be called from with the class/object.
When self appears as a parameter in a class method you won't have to supply the object's name, Python will figure it out. So the second line above (Parent2 = ...) is not recommended.
See the documentation:
object.__init__(self[, ...])
Called after the instance has been created (by __new__()), but before it is returned to the caller. The arguments are those passed to the class constructor expression.
object.__new__(cls[, ...])
Called to create a new instance of class cls. __new__() is a static method (special-cased so you need not declare it as such) that takes the class of which an instance was requested as its first argument. The remaining arguments are those passed to the object constructor expression
So under the hood in parent1 = Parent(), Python's basically doing this:
_temp_new_parent = Parent.__new__(Parent) # Inherited from "object.__new__"
Parent.__init__(_temp_new_parent)
parent1 = _temp_new_parent
(_temp_new_parent doesn't really exist, I'm just using it as an abstraction.)
Note that __init__() doesn't return anything, so in your code, parent2 is None. And if __init__() had set instance attributes, it would have set them on parent1 since that's what you passed in.

running __init__ inside its own definition

I'm currently learning tkinter from sentdex's tutorial and to me it seems that I'm writing to run __init__ in its own definition, what does a line like that mean? Is it tKinter's __init__ function?
class seaOfBTCapp(tk.Tk):
def __init__(self,*args,**kwargs)
tk.Tk.__init__(self,*args,**kwargs)
It's invoking another class's constructor on itself.
This is a fun quirk of python's object-oriented design. "Instance methods" are really just class methods that take the current instance as an implicit parameter. You can, in fact, call them as class methods and provide the object explicitly:
ex = [1, 2, 3, 4, 5]
# the following are equivalent:
ex.pop(0) # call the method on the instance, passing it implicitly
list.pop(ex, 0) # call the method on the class `list`, passing the instance explicitly
The same behavior is being invoked here. You're taking the __init__ method of the tk.TK class, and passing self in as the "instance". This is an uncommon, but valid, way of accessing methods in the superclass that have been overridden in your subclass (for example, the constructor).
As in #Barmar's answer, a better solution is using super(), which produces something resembling an instance of the superclass, which you then call __init__ on to get the superclass's implementation of __init__() passing self implicitly, as you would expect.
What that line does is call your parent class's __init__ method. That's what would have happened if you didn't define your own method, so if you're not doing anything else in your __init__, you should probably just skip it and let the inherited method run normally.
It's also probably better to call super().__init__(*args, **kwargs), rather than naming the parent class explicitly (and needing to pass self by hand). This is particularly the case if you might ever use this class in a situation involving multiple inheritance, where explicitly naming the next class to be called can get the MRO wrong. If you're just starting in programming, don't worry too much about this, multiple inheritance is a pretty advanced topic (though it's easier to get right in Python than in many other languages).
I think this is equivalent to the more modern:
class seaOfBTCapp(tk.Tk):
def __init__(self,*args,**kwargs)
super().__init__(*args,**kwargs)

Call a method in initialization without overriding base class's __init__

I hope I make it clear in the title. I'm trying to inherit from list, and I want some of my own methods to be called when an instance of my class is created. However, I can't override list.__init__ since that would make me unable to use list's original methods. How can I accomplish this?
Simply call super.__init__ before / after you call your own methods:
class CustomList(list):
def __init__(self, *args):
super(CustomList, self).__init__(*args)
# call your own methods here

understanding python self and init

As might be familiar to most of you, this is from Mark Pilgrim's book DIP, chapter 5
class FileInfo(UserDict):
"store file metadata"
def __init__(self, filename=None):
UserDict.__init__(self)
self["name"] = filename
Well I am new to python, coming from basic C background and having confusion understanding it. Stating what I understand, before what I don't understand.
Statement 0: FileInfo is inheriting from class UserDict
Statement 1: __init__ is not a constructor, however after the class instantiates, this is the first method that is defined.
Statement2: self is almost like this
Now the trouble:
as per St1 init is defined as the first function.
UserDict.__init__(self)
Now within the same function __init__ why is the function being referenced, there is no inherent recursion I guess. Or is it trying to override the __init__ method of the class UserDict which the class FileInfo has inherited and put an extra parameter(key value pair) of filename and reference it to the filename being passed to __init__ method.
I am partly sure, I have answered my question, however as you can sense there is confusion, would be great if someone can explain me how to rule this confusion out with some more advanced use case and detailed example of how generally code is written.
You're correct, the __init__ method is not a constructor, it's an initializer called after the object is instantiated.
In the code you've presented, the __init__ method on the FileInfo class is extending the functionality of the __init__ method of the base class, UserDict. By calling the base __init__ method, it executes any code in the base class's initialization, and then adds its own. Without a call to the base class's __init__ method, only the code explicitly added to FileInfo's __init__ method would be called.
The conventional way to do this is by using the super method.
class FileInfo(UserDict):
"store file metadata"
def __init__(self, filename=None):
super(UserDict, self).__init__()
self["name"] = filename
A common use case is returning extra values or adding additional functionality. In Django's class based views, the method get_context_data is used to get the data dictionary for rendering templates. So in an extended method, you'd get whatever values are returned from the base method, and then add your own.
class MyView(TemplateView):
def get_context_data(self, **kwargs):
context = super(MyClass, self).get_context_data(**kwargs)
context['new_key'] = self.some_custom_method()
return kwargs
This way you do not need to reimplement the functionality of the base method when you want to extend it.
Creating an object in Python is a two-step process:
__new__(self, ...) # constructor
__init__(self, ...) # initializer
__new__ has the responsibility of creating the object, and is used primarily when the object is supposed to be immutable.
__init__ is called after __new__, and does any further configuration needed. Since most objects in Python are mutable, __new__ is usually skipped.
self refers to the object in question. For example, if you have d = dict(); d.keys() then in the keys method self would refer to d, not to dict.
When a subclass has a method of the same name as its parent class, Python calls the subclass' method and ignores the parent's; so if the parent's method needs to be called, the subclass method must call it.
"Or is it trying to override the init method of the class UserDict which the class FileInfo has inherited and put an extra parameter(key value pair) of filename and reference it to the filename being passed to init method."
It's exactly that. UserDict.__init__(self) calls the superclass init method.
Since you come from C, maybe you're not well experienced with OOP, so you could read this article : http://en.wikipedia.org/wiki/Inheritance_(object-oriented_programming) to understand the inheritance principle better (and the "superclass" term I used).
.. the self variable represents the instance of the object itself. In python this is not a hidden parameter as in other languages. You have to declare it explicitly. When you create an instance of the FileInfo class and call its methods, it will be passed automatically,
The __init__ method is roughly what represents a constructor in Python.
The __init__ method of FileInfo is overriding the __init__ method of UserDict.
Then FileInfo.__init__ calls UserDict.__init__ on the newly created FileInfo instance (self). This way all properties and magic available to UserDict are now available to that FileInfo instance (ie. they are inherited from UserDict).
The last line is the reason for overriding UserDict.__init__ : UserDict does not create the wanted property self.filename.
When you call __init__ method for a class that is inheriting from a base class, you generally modify the ancestor class and as a part of customization, you extend the ancestor's init method with proper arguements.
__init__ is not a constructor, however after the class instantiates, this is the first method that is defined.
This method is called when an instance is being initialized, after __new__ (i.e. when you call ClassName()). I'm not sure what difference there is as opposed to a constructor.
Statement2: self is almost like this
Yes but it is not a language construct. The name self is just convention. The first parameter passed to an instance method is always a reference to the class instance itself, so writing self there is just to name it (assign it to variable).
UserDict.__init__(self)
Here you are calling the UserDict's __init__ method and passing it a reference to the new instance (because you are not calling it with self.method_name, it is not passed automatically. You cannot call an inherited class's constructor without referencing its name, or using super). So what you are doing is initializing your object the same way any UserDict object would be initialized.

Categories