Listing all instance of a class - python

I wrote a Python module, with several classes that inherit from a single class called MasterBlock.
I want to import this module in a script, create several instances of these classes, and then get a list of all the existing instances of all the childrens of this MasterBlock class. I found some solutions with vars()['Blocks.MasterBlock'].__subclasses__() but as the instances I have are child of child of MasterBlock, it doesn't work.
Here is some example code:
Module:
Class MasterBlock:
def main(self):
pass
Class RandomA(MasterBlock):
def __init__(self):
pass
# inherit the main function
Class AnotherRandom(MasterBlock):
def __init__(self):
pass
# inherit the main function
Script:
import module
a=module.RandomA()
b=module.AnotherRandom()
c=module.AnotherRandom()
# here I need to get list_of_instances=[a,b,c]
Th ultimate goal is to be able to do:
for instance in list_of_instances:
instance.main()

If you add a __new__() method as shown below to your base class which keeps track of all instances created in a class variable, you could make the process more-or-less automatic and not have to remember to call something in the __init__() of each subclass.
class MasterBlock(object):
instances = []
def __new__(cls, *args, **kwargs):
instance = super(MasterBlock, cls).__new__(cls, *args, **kwargs)
instance.instances.append(instance)
return instance
def main(self):
print('in main of', self.__class__.__name__) # for testing purposes
class RandomA(MasterBlock):
def __init__(self):
pass
# inherit the main function
class AnotherRandom(RandomA): # works for sub-subclasses, too
def __init__(self):
pass
# inherit the main function
a=RandomA()
b=AnotherRandom()
c=AnotherRandom()
for instance in MasterBlock.instances:
instance.main()
Output:
in main of RandomA
in main of AnotherRandom
in main of AnotherRandom

What about adding a class variable, that contains all the instances of MasterBlock? You can record them with:
Class MasterBlock(object):
all_instances = [] # All instances of MasterBlock
def __init__(self,…):
…
self.all_instances.append(self) # Not added if an exception is raised before
You get all the instances of MasterBlock with MasterBlock.all_instances (or instance.all_instances).
This works if all base classes call the __init__ of the master class (either implicitly through inheritance or explicitly through the usual super() call).

Here's a way of doing that using a class variable:
class MasterBlock(object):
instances = []
def __init__(self):
self.instances.append(self)
def main(self):
print "I am", self
class RandomA(MasterBlock):
def __init__(self):
super(RandomA, self).__init__()
# other init...
class AnotherRandom(MasterBlock):
def __init__(self):
super(AnotherRandom, self).__init__()
# other init...
a = RandomA()
b = AnotherRandom()
c = AnotherRandom()
# here I need to get list_of_instances=[a,b,c]
for instance in MasterBlock.instances:
instance.main()
(you can make it simpler if you don't need __init__ in the subclasses)
output:
I am <__main__.RandomA object at 0x7faa46683610>
I am <__main__.AnotherRandom object at 0x7faa46683650>
I am <__main__.AnotherRandom object at 0x7faa46683690>

Related

How to override a function in a dict

As part of a message parser I have something similar to what is below, I want to be able to override some of the base class message functions as needed, but the override only works if I add a pass through function. I have lots of these functions and would like to not have to use a pass through function for every message function the child might override.
I know I could provide the functions that the child wants to override as part of the init append operation from the child, but the real messages are a lot more complicated than this simple example and doing that would break the rules I have set for the child classes.
First question is why does it not just work without the pass though, dictionaries are mutable, so the override should be called from the dictionary.
Second question, is there a solution that does not entail the pass though function or appending the override functions to the dictionary from the child init?
class Base():
def set_enable_ind(self):
print("using the pass through hack")
self.set_enable(self)
def set_enable(self):
print("In base class set_enable")
# base msg config dict
msgConfig = {
'setEnable': (set_enable),
}
msgConfigInd = {
'setEnable': (set_enable_ind),
}
def __init__(self, msgConfig=None):
# add the child's messages to the default ones
if msgConfig:
self.msgConfig.update(msgConfig)
self.msgConfigInd.update(msgConfig)
#this one calls the function directly
def msg_recived(self,msg):
self.msgConfig[msg](self)
# this one calls the pass though function
def msg_recived_ind(self,msg):
self.msgConfigInd[msg](self)
class Child(Base):
# override from base class
def set_enable(self, data = None, header=None):
print("In child class set_enable")
# add my own
def disconnect(self, data = None, header=None):
print("In child class disconnect_connection")
# each entry gets a function to call
BtMsgs = {
'disconnect' : (disconnect),
}
def __init__(self):
# call base class __init__ function first, adding my messages
Base.__init__(self, Child.BtMsgs)
if __name__ == "__main__":
child = Child()
#these both work as expected
child.msg_recived('disconnect')
child.msg_recived_ind('disconnect')
#this will always call the Base class function
child.msg_recived('setEnable')
#this will call the child function
child.msg_recived_ind('setEnable')
#output is as follow:
#In child class disconnect_connection
#In child class disconnect_connection
#In base class set_enable
#using the pass through hack
#In child class set_enable
The reason your msg_recived function always calls the Base.set_enable method is because of scoping. When you do:
class Base:
def set_enable(self):
print("In base class set_enable")
msgConfig = {
'setEnable': set_enable, # I removed parens here
}
...
you are telling Python to reference the nearest-scoped set_enable function (the one right above the dictionary).
The reason your Child class never calls its set_enable method, is because you haven't updated the reference in its own msgConfig dictionary. Calling the self.msgConfig.update method is only adding the new key/val reference to the disconnect method of the Child class.
If you change the Child.BtMsgs attribute/dict to have new references, it will work:
class Child(Base):
...
BtMsgs = {
'disconnect': disconnect,
'setEnable': set_enable,
}
def __init__(self):
super().__init__(Child.BtMsgs) # This is Python3.X+ convention
...
Output:
In child class disconnect_connection
In child class disconnect_connection
In child class set_enable
In child class set_enable
This is because 'setEnable': set_enable is now scoped to the one defined inside the Child class.
Regarding my original comment on your question about using __getitem__, getattr, and setattr:
You don't have to subclass dict for these methods to be useful.
class MsgConfig:
def __init__(self, **kwargs):
for attr in kwargs:
setattr(self, attr, kwargs[attr])
def __getitem__(self, item):
return self.__dict__.get(item)
def update(self, d):
if isinstance(d, MsgConfig):
d = d.__dict__
for k,v in d.items():
setattr(self, k, v)
class Base:
def set_enable(self):
print("In base class set_enable")
def __init__(self, msgConfig=None):
self.msgConfig = MsgConfig(setEnable=self.set_enable)
if msgConfig:
self.msgConfig.update(msgConfig)
def msg_recived(self,msg):
self.msgConfig[msg](self)
class Child(Base):
def set_enable(self, data = None, header=None):
print("In child class set_enable")
def disconnect(self, data = None, header=None):
print("In child class disconnect_connection")
def __init__(self):
super().__init__(MsgConfig(disconnect=self.disconnect))
if __name__ == "__main__":
child = Child()
child.msg_recived('disconnect')
child.msg_recived('setEnable')
Output:
In child class disconnect_connection
In child class set_enable
You could try modifying or extending the above class to work for you to automatically pull in necessary message function pointers.

Determine if subclass has a base class's method implemented in Python

I have a class that extends a base class. Upon instantiation, I want to check if the subclass has one of the classes implemented from its base, but I'm not sure the best way. hasattr(self, '[method]') returns the method from super if not implemented by the child, so I'm trying to tell the difference.
Here is an example:
class Base :
def __init__ ( self,) :
pass
def fail (self,) :
pass
# Now create the subclass w/o .fail
class Task ( Base ) :
def __init__ ( self, ):
print( hasattr( self, 'fail' ) ) # < returns True
When Task() is instantiated it prints True because Task inherits .fail from Base. But in this case, I want to know that Task Does Not implement .fail, so I want a False returned somehow. It seems like I'm looking for something like isimplemented( self, 'fail' ). What am I missing?
I'm not sure I understand correctly, but it sounds like you might be looking for Abstract Base Classes. (Documentation here, tutorial here.) If you specify an abstractmethod in a base class that inherits from abc.ABC, then attempting to instantiate a subclass will fail unless that subclass overrides the abstractmethod.
from abc import ABC, abstractmethod
class Base(ABC):
#abstractmethod
def fail(self):
pass
class Task(Base):
pass
class Task2(Base):
def fail(self):
pass
# this raises an exception
# `fail` method has not been overridden in the subclass.
t1 = Task()
# this succeeds
# `fail` method has been overridden in the subclass.
t2 = Task2()
If you want a check to happen at class definition time rather than instance instantiation time, another option is to write an __init_subclass__ method in your base class, which is called every time you subclass your base class or you subclass a class inheriting from your base class. (You don't have to raise an exception in __init_subclass__ — you could just add a fail_overriden boolean attribute to the class, or do anything you like really.)
class Base:
def fail(self):
pass
def __init_subclass__(cls, **kwargs):
if cls.fail == Base.fail:
raise TypeError(
'Subclasses of `Base` must override the `fail` method'
)
super().__init_subclass__(**kwargs)
# this class definition raises an exception
# because `fail` has not been overridden
class Task(Base):
pass
# this class definition works fine.
class Task2(Base):
def fail(self):
pass
And if you just want each instance to tell you whether fail was overridden in their subclass, you can do this:
class Base:
def __init__(self):
print(type(self).fail != Base.fail)
def fail(self):
pass
class Task(Base):
def __init__(self):
super().__init__()
class Task2(Base):
def __init__(self):
super().__init__()
def fail(self):
pass
t1 = Task() # prints "True"
t2 = Task2() # prints "False"
IIUC, you can check super().fail == self.fail
class Base:
def __init__(self):
pass
def fail(self):
pass
class Task(Base):
def __init__(self):
print(super().fail == self.fail)
class Task2(Base):
def __init__(self):
print(super().fail == self.fail)
def fail(self):
# Override
pass
Output:
t1 = Task()
# True
t2 = Task2()
# False
Not sure if I understand correctly but you could check if fail method is in the vars of the classes, but not inherited to the main class.
So you could try:
class Base:
def __init__(self):
print(self.__dir__())
def fail(self):
pass
class Task(Base):
def __init__(self):
print('fail' not in vars(Task))
class Task2(Base):
def __init__(self):
print('fail' not in vars(Task2))
def fail(self):
# Override
pass
t1 = Task()
t2 = Task2()
Output:
True
False
Or use __dict__:
...
class Task(Base):
def __init__(self):
print('fail' not in Task.__dict__)
class Task2(Base):
def __init__(self):
print('fail' not in Task2.__dict__)
def fail(self):
# Override
pass
...

Python: How to define a variable in an __init__ function with a class method?

class TextToNumbers():
def __init__(self, number):
self.text = str(number)
self.chunks = parse_text_to_chunks(self.text)
def parse_text_to_chunks(text_to_parse):
#stuff
This is an example of a class I'm building. I want it to define some variables with class methods on initialization. (at least I think that is what I want) I think if I talk about my end goal it is that I have a set of complex information that needs to be available about a class directly at initialization. How do I call a class method at initialization, to define a class variable?
If you are looking for a way to call an instance method during initialization, you can use self to call that like this
class TextToNumbers():
def __init__(self, number):
self.text = str(number)
self.chunks = self.parse_text_to_chunks(self.text)
print self.chunks
def parse_text_to_chunks(self, text_to_parse):
# 1st parameter passed is the current INSTANCE on which this method is called
self.var1 = text_to_parse[1:]
return self.var1
TextToNumbers(123)
And I believe this is what you really need. But if you want a class method
class TextToNumbers():
def __init__(self, number):
self.text = str(number)
self.chunks = TextToNumbers.parse_text_to_chunks(self.text)
print self.chunks
#classmethod
def parse_text_to_chunks(cls, text_to_parse):
# 1st parameter passed is the current CLASS on which this method is called
cls.var1 = text_to_parse[1:]
return cls.var1
TextToNumbers(123)
But there is no point in creating a class method to initialize a class variable in __init__, since a class variable is shared by all the instances of the class, calling from __init__ will overwrite everytime an object is created.

Pass a parent class as an argument?

Is it possible to leave a parent class unspecified until an instance is created?
e.g. something like this:
class SomeParentClass:
# something
class Child(unspecifiedParentClass):
# something
instance = Child(SomeParentClass)
This obviously does not work. But is it possible to do this somehow?
You can change the class of an instance in the class' __init__() method:
class Child(object):
def __init__(self, baseclass):
self.__class__ = type(self.__class__.__name__,
(baseclass, object),
dict(self.__class__.__dict__))
super(self.__class__, self).__init__()
print 'initializing Child instance'
# continue with Child class' initialization...
class SomeParentClass(object):
def __init__(self):
print 'initializing SomeParentClass instance'
def hello(self):
print 'in SomeParentClass.hello()'
c = Child(SomeParentClass)
c.hello()
Output:
initializing SomeParentClass instance
initializing Child instance
in SomeParentClass.hello()
Have you tried something like this?
class SomeParentClass(object):
# ...
pass
def Child(parent):
class Child(parent):
# ...
pass
return Child()
instance = Child(SomeParentClass)
In Python 2.x, also be sure to include object as the parent class's superclass, to use new-style classes.
You can dynamically change base classes at runtime. Such as:
class SomeParentClass:
# something
class Child():
# something
def change_base_clase(base_class):
return type('Child', (base_class, object), dict(Child.__dict__))()
instance = change_base_clase(SomeParentClass)
For example:
class Base_1:
def hello(self):
print('hello_1')
class Base_2:
def hello(self):
print('hello_2')
class Child:pass
def add_base(base):
return type('Child', (base, object), dict(Child.__dict__))()
# if you want change the Child class, just:
def change_base(base):
global Child
Child = type('Child', (base, object), dict(Child.__dict__))
def main():
c1 = add_base(Base_1)
c2 = add_base(Base_2)
c1.hello()
c2.hello()
main()
Result:
hello_1
hello_2
Works well in both python 2 and 3.
For more information, see the related question How to dynamically change base class of instances at runtime?

Create Thread on Class Method

How can I call thread on a class method passing it 'self'? I have a class defined as follows and want to call class method in new thread with self as argument. I tried following but self is not passed as argument
cust_obj = Customer()
thread.start_new_thread(cust_obj.process, ())
class Customer():
def __init__(self):
pass
def process(self):
self.fetch_data()
self.serialize_data()
def fetch_data(self):
# Fetch data logic
pass
def serialize_data(self):
# Serialize fetched data
pass
I believe you should put the class definition before the instance creating. Then it will work.
class Customer():
...
cust_obj = Customer()
thread.start_new_thread(cust_obj.process, ())

Categories