Can someone please explain me the following code
TickGenerator inherit from object and methods of Observer, why do we need both observer.init?
class TickGenerator(Observer):
def __init__(self):
Observer.__init__(self)
self.price = 1000
I guess you came from a language where the parent class constructor is automatically called.
In Python, if you override the __init__ method, the parent class constructor will not be called unless you call it explicitly.
Until Python 3, it used to be called as:
def __init__(self, *args, **kwargs):
super(TickGenerator, self).__init__(*args, **kwargs)
The new [super()][1] syntax (PEP-3135) is just:
def __init__(self, *args, **kwargs):
super().method(*args, **kwargs)
Because programmer needs Observer class __init__ to be done in addition to
what is being done in the current class's (TickGenerator) __init__.
This Stackoverflow answer will help you understand more.
If you don't call Observer.init as below:
class TickGenerator(Observer):
def __init__(self):
self.price = 1000
It means you override the TickGenerator.init method and Observer.init will not be called automaticlly.
Related
I have a question about the instantiation process of a child class with multiple inheritance from parent class A without arg and parent class B with kwargs respectively.
In the code below, I don't know why ParentB's set_kwargs()method is executed while ParentA is inited when a Child instance is created.
(Expecially, why does the results show Child receive {}? How can I avoid this results?)
Any help would be really appreciated.
Thanks!
class GrandParent:
def __init__(self):
print(f"{self.__class__.__name__} initialized")
class ParentA(GrandParent):
def __init__(self):
super().__init__()
class ParentB(GrandParent):
def __init__(self, **kwargs):
super().__init__()
self.set_kwargs(**kwargs)
def set_kwargs(self, **kwargs):
print(f"{self.__class__.__name__} receive {kwargs}")
self.content = kwargs.get('content')
class Child(ParentA, ParentB):
def __init__(self, **kwargs):
ParentA.__init__(self)
ParentB.__init__(self, **kwargs)
c = Child(content = 3)
results:
Child initialized
Child receive {}
Child initialized
Child receive {'content': 3}
For most cases of multiple inheritance, you will want the superclass methods to be called in sequence by the Python runtime itself.
To do that, just place a call to the target method in the return of super().
In your case, the most derived class' init should read like this:
class Child(ParentA, ParentB):
def __init__(self, **kwargs):
super().__init__(self, **kwargs)
And all three superclasses __init__ methods will be correctly run. Note that for that to take place, they have to be built to be able to work cooperatively in a class hierarchy like this - for which two things are needed: one is that each method in any of the superclasses place itself a class to super().method()- and this is ok in your code. The other is that if parameters are to be passed to these methods, which not all classes will know, the method in each superclass should extract only the parameters it does know about, and pass the remaining parameters in its own super() call.
So the correct form is actually:
class GrandParent:
def __init__(self):
print(f"{self.__class__.__name__} initialized")
class ParentA(GrandParent):
def __init__(self, **kwargs):
super().__init__(**kwargs)
class ParentB(GrandParent):
def __init__(self, **kwargs):
content = kwargs.pop('content')
super().__init__(**kwargs)
self.set_kwargs(content)
def set_kwargs(self, content):
print(f"{self.__class__.__name__} receive {content}")
self.content = content
class Child(ParentA, ParentB):
def __init__(self, **kwargs):
super.__init__(**kwargs)
c = Child(content = 3)
The class which will be called next when you place a super() call is calculated by Python when you create a class with multiple parents - so, even though both "ParentA" and "ParentB" inherit directly from grandparent, when the super() call chain bubbles up from "Child", Python will "know" that from within "ParentA" the next superclass is "ClassB" and call its __init__ instead.
The algorithm for finding the "method resolution order" is quite complicated, and it just "works as it should" for most, if not all, usecases. It's exact description can be found here: https://www.python.org/download/releases/2.3/mro/ (really - you don't have to understand it all - there are so many corner cases it handles - just get the "feeling" of it.)
So I am trying to override __new__ and let it exist as a factory to create
derived instances. After reading a bit on SO, I am under the impression that I should be calling __new__ on the derived instance as well.
BaseThing
class BaseThing:
def __init(self, name, **kwargs):
self.name = name
# methods to be derived
ThingFactory
class Thing(BaseThing):
def __new__(cls, name, **kwargs):
if name == 'A':
return A.__new__(name, **kwargs)
if name == 'B':
return B.__new__(name, **kwargs)
def __init__(self, *args, **kwargs):
super().__init__(name, **kwargs)
# methods to be implemented by concrete class (same as those in base)
A
class A(BaseThing):
def __init__(self, name, **kwargs):
super().__init__(name, **kwargs)
B
class B(BaseThing):
def __init__(self, name, **kwargs):
super().__init__(name, **kwargs)
what I am expecting was that it'd just work.
>>> a = Thing('A')
gives me TypeError: object.__new__(X): X is not a type object (str)
I am bit confused by this; when I just return a concrete instance of derived classes, it just worked. i.e.
def __new__(cls, name, **kwargs):
if name == 'A':
return A(name)
if name == 'B':
return B(name)
I don't think this is the correct way to return in __new__; it may duplicate the calls to __init__.
when I am checking signatures of __new__ in object it seems be this one:
#staticmethod # known case of __new__
def __new__(cls, *more): # known special case of object.__new__
""" Create and return a new object. See help(type) for accurate signature. """
pass
I didn't expect this was the one; I'd expect it came with args and kwargs as well. I must have done something wrong here.
it seems to me that I need to inherit object directly in my base but could anyone explain the correct way of doing it?
You're calling __new__ wrong. If you want your __new__ to create an instance of a subclass, you don't call the subclass's __new__; you call the superclass's __new__ as usual, but pass it the subclass as the first argument:
instance = super().__new__(A)
I can't guarantee that this will be enough to fix your problems, since the code you've posted wouldn't reproduce the error you claim; it has other problems that would have caused a different error first (infinite recursion). Particularly, if A and B don't really descend from Thing, that needs different handling.
class SeaofBTCapp(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
container = tk.Frame(self)
Hello all I am trying to understand objects and classes. Using tkinter the author has created a class which inherits from the Tk() class of tkinter and proceeds to write his own __init__ method which I assume overrides the parent class' __init__. The author then initialises the parents original tk.Tk.__init__ method.
Could the author just have used the super().__init__(*args, **kwargs) to achieve the same result?
Yes, I believe the author could have used super() .
The main advantage of super comes with multiple inheritance, this may interest you
I try do this:
import unittest
def decorator(cls):
class Decorator(cls):
def __init__(self, *args, **kwargs):
super(Decorator, self).__init__(*args, **kwargs)
return Decorator
#decorator
class myClass(unittest.TestCase):
def __init__(self, *args, **kwargs):
super(myClass, self).__init__(*args, **kwargs)
self.test = 'test'
def test_test(self):
pass
myClass().run()
But I get recursion in MyClass.__init__. Are there any ways to avoid this?
You cannot use super(myClass, self) within a decorated class in this way.
myClass is looked up as a global, and the global myClass is rebound to Decorator, so you are telling Python to look in the class MRO for __init__ starting from Decorator which is myClass, which calls super(myClass, self).__init__(), looking up myClass as a global, which is bound to Decorator, etc.
The easiest work-around is to not use super() here:
#decorator
class myClass(unittest.TestCase):
def __init__(self, *args, **kwargs):
unittest.TestCase.__init__(self, *args, **kwargs)
self.test = 'test'
This is one of the reasons why in Python 3 the argument-less version of super() was introduced, giving methods a __class__ cell instead.
You could jump through some (very tricky) hoops to re-compile the myClass.__init__() method to give it a myClass closure bound to the original undecorated class object instead, but for a unittest, I would not bother.
I'm trying to find the best way to create a class decorator that does the following:
Injects a few functions into the decorated class
Forces a call to one of these functions AFTER the decorated class' __init__ is called
Currently, I'm just saving off a reference to the 'original' __init__ method and replacing it with my __init__ that calls the original and my additional function. It looks similar to this:
orig_init = cls.__init__
def new_init(self, *args, **kwargs):
"""
'Extend' wrapped class' __init__ so we can attach to all signals
automatically
"""
orig_init(self, *args, **kwargs)
self._debugSignals()
cls.__init__ = new_init
Is there a better way to 'augment' the original __init__ or inject my call somewhere else? All I really need is for my self._debugSignals() to be called sometime after the object is created. I also want it happen automatically, which is why I thought after __init__ was a good place.
Extra misc. decorator notes
It might be worth mentioning some background on this decorator. You can find the full code here. The point of the decorator is to automatically attach to any PyQt signals and print when they are emitted. The decorator works fine when I decorate my own subclasses of QtCore.QObject, however I've been recently trying to automatically decorate all QObject children.
I'd like to have a 'debug' mode in the application where I can automatically print ALL signals just to make sure things are doing what I expect. I'm sure this will result in TONS of debug, but I'd still like to see what's happening.
The problem is my current version of the decorator is causing a segfault when replacing QtCore.QObject.__init__. I've tried to debug this, but the code is all SIP generated, which I don't have much experience with.
So, I was wondering if there was a safer, more pythonic way to inject a function call AFTER the __init__ and hopefully avoid the segfault.
Based on this post and this answer, an alternative way to do this is through a custom metaclass. This would work as follows (tested in Python 2.7):
# define a new metaclass which overrides the "__call__" function
class NewInitCaller(type):
def __call__(cls, *args, **kwargs):
"""Called when you call MyNewClass() """
obj = type.__call__(cls, *args, **kwargs)
obj.new_init()
return obj
# then create a new class with the __metaclass__ set as our custom metaclass
class MyNewClass(object):
__metaclass__ = NewInitCaller
def __init__(self):
print "Init class"
def new_init(self):
print "New init!!"
# when you create an instance
a = MyNewClass()
>>> Init class
>>> New init!!
The basic idea is that:
when you call MyNewClass() it searches for the metaclass, finds that you have defined NewInitCaller
The metaclass __call__ function is called.
This function creates the MyNewClass instance using type,
The instance runs its own __init__ (printing "Init class").
The meta class then calls the new_init function of the instance.
Here is the solution for Python 3.x, based on this post's accepted answer. Also see PEP 3115 for reference, I think the rationale is an interesting read.
Changes in the example above are shown with comments; the only real change is the way the metaclass is defined, all other are trivial 2to3 modifications.
# define a new metaclass which overrides the "__call__" function
class NewInitCaller(type):
def __call__(cls, *args, **kwargs):
"""Called when you call MyNewClass() """
obj = type.__call__(cls, *args, **kwargs)
obj.new_init()
return obj
# then create a new class with the metaclass passed as an argument
class MyNewClass(object, metaclass=NewInitCaller): # added argument
# __metaclass__ = NewInitCaller this line is removed; would not have effect
def __init__(self):
print("Init class") # function, not command
def new_init(self):
print("New init!!") # function, not command
# when you create an instance
a = MyNewClass()
>>> Init class
>>> New init!!
Here's a generalized form of jake77's example which implements __post_init__ on a non-dataclass. This enables a subclass's configure() to be automatically invoked in correct sequence after the base & subclass __init__s have completed.
# define a new metaclass which overrides the "__call__" function
class PostInitCaller(type):
def __call__(cls, *args, **kwargs):
"""Called when you call BaseClass() """
print(f"{__class__.__name__}.__call__({args}, {kwargs})")
obj = type.__call__(cls, *args, **kwargs)
obj.__post_init__(*args, **kwargs)
return obj
# then create a new class with the metaclass passed as an argument
class BaseClass(object, metaclass=PostInitCaller):
def __init__(self, *args, **kwargs):
print(f"{__class__.__name__}.__init__({args}, {kwargs})")
super().__init__()
def __post_init__(self, *args, **kwargs):
print(f"{__class__.__name__}.__post_init__({args}, {kwargs})")
self.configure(*args, **kwargs)
def configure(self, *args, **kwargs):
print(f"{__class__.__name__}.configure({args}, {kwargs})")
class SubClass(BaseClass):
def __init__(self, *args, **kwargs):
print(f"{__class__.__name__}.__init__({args}, {kwargs})")
super().__init__(*args, **kwargs)
def configure(self, *args, **kwargs):
print(f"{__class__.__name__}.configure({args}, {kwargs})")
super().configure(*args, **kwargs)
# when you create an instance
a = SubClass('a', b='b')
running gives:
PostInitCaller.__call__(('a',), {'b': 'b'})
SubClass.__init__(('a',), {'b': 'b'})
BaseClass.__init__(('a',), {'b': 'b'})
BaseClass.__post_init__(('a',), {'b': 'b'})
SubClass.configure(('a',), {'b': 'b'})
BaseClass.configure(('a',), {'b': 'b'})
I know that the metaclass approach is the Pro way, but I've a more readable and easy proposal using #staticmethod:
class Invites(TimestampModel, db.Model):
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
invitee_email = db.Column(db.String(128), nullable=False)
def __init__(self, invitee_email):
invitee_email = invitee_email
#staticmethod
def create_invitation(invitee_email):
"""
Create an invitation
saves it and fetches it because the id
is being generated in the DB
"""
invitation = Invites(invitee_email)
db.session.save(invitation)
db.session.commit()
return Invites.query.filter(
PartnerInvites.invitee_email == invitee_email
).one_or_none()
So I could use it this way:
invitation = Invites.create_invitation("jim#mail.com")
print(invitation.id, invitation.invitee_email)
>>>> 1 jim#mail.com