Here's my problem statement:
I've an extractor class which calls a ConfigManager class and passes a type as an argument. Based on the type, ConfigManager resolves the class that needs to be called.
At this point, ConfigManager has a reference to the class.
However ConfigManager needs to pass this class back to the extractor.
ConfigManager is a helper class which the Extractor will call to get type specific class.
How do I make the ConfigManager pass the class to Extractor?
I'm new to python and any help is much appreciated.
Extractor -> ConfigManager -> AbstractLoader| -> Metric1Loader
Extractor class calls ConfigManager. ConfigManager gets Metric1Loader class and needs to pass it to Extractor.
ConfigManager should pass class reference of Metric1Loader back to Extractor.
To me, your requirement sounds like a problem which can be solved by factory design pattern.
Here's an example which can be used as a reference.
class AbstractLoader:
def __init__(self):
pass
class Metric1Loader(AbstractLoader):
def __init__(self):
print('Metric1Loader')
class Metric2Loader(AbstractLoader):
def __init__(self):
print('Metric2Loader')
class Factory:
#staticmethod
def make_class(target_class):
# This will instantiate object of type determined from target_class string
return globals()[target_class]()
def extractor():
types = ['Metric1Loader', 'Metric2Loader']
for type in types:
obj = Factory.make_class(type)
if __name__ == '__main__':
extractor()
# STDOUT:
# Metric1Loader
# Metric2Loader
perhaps create a method that returns the data to the object that needs it?
def ConfigManager:
def resolveClass(self, name):
return obj
def Extractor:
def doSomething(self):
configManager = ConfigManager()
resolvedClass = configManager.resolveClass("name")
Related
Given:
Module A.py
class utilities:
def __init__(self):
#Is there a way to get the class that instantiates this constructor ? But here, in the init method?
def utilMethod(self):
pass
Module B.py
from A import utilities
class dummy:
utils = utilities()
def dummyMthod(self):
utils.utilMethod()
#Is there a way to get the class that instantiates utilities class constructor ? But in the init method of the class being instanciated?
Since you're instantiating utils as a static variable, at the time of its creation class dummy is not yet available so the answer is "no": you can't do that.
Alternative solution: "pass yourself in" (see code comments for explanations)
class utilities:
def __init__(self):
pass
def utilMethod(self, obj): # the caller is passed in
print(obj.__class__.__name__) # this is how we can access the class-name of the caller
pass
class dummy:
utils = utilities()
def dummyMthod(self):
self.utils.utilMethod(self) # here we "pass ourselves in"
d = dummy()
d.dummyMthod() # prints "dummy"
UPDATE
If we want to declare utils as an object attribute (vs. static class attribute in the previous snippet), we can do:
class utilities:
def __init__(self, obj):
print(obj.__class__.__name__)
pass
def utilMethod(self, obj):
pass
class dummy:
def __init__(self):
self.utils = utilities(self) # declare utils as object attribute inside the constructor and pass 'self' into utilities
def dummyMthod(self):
self.utils.utilMethod()
d = dummy() # prints "dummy"
Within __init__ (and generally within the methods of the class) you can use self.__class__ and/or self.__class__.__name__; the latter can be particularly useful for logging and similar messages.
self.logger = logging.getLogger(self.__class__.__name__)
(Or similar, perhaps also incorporating the module name.)
I'm working on a project using abstract classes in Python (specifically, the abc module).
I have a few implementations of this abstract class, which have their own constructors and need to use self.
This is what my code looks like, but simplified:
from abc import ABC, abstractmethod
class BaseClass(ABC):
def __init__(self):
self.sublinks = [] # not meant to be passed in, that's why it isn't an argument in __init__
#classmethod
def display(cls):
print(cls.get_contents())
#abstractmethod
def get_contents():
pass
class ImplementationOne(Base):
def __init__(self, url):
self.url = url
def get_contents(self):
return "The url was: " + url
class ImplementationTwo(Base):
def get_contents():
return "This does not need a url"
test_one = ImplementationOne("https://google.com")
test_two = ImplementationTwo()
test_one.display()
When I run this, however, I get the error TypeError: get_contents() missing 1 required positional argument: 'self'.
I figured that this is because get_contents() in ImplementationOne takes self, but it's not specified in the abstract method.
So, if I changed:
#abstractmethod
def get_contents():
pass
to
#abstractmethod
def get_contents(self):
pass
But I get the same error.
I've tried many combinations, including putting self as an argument to every occurrence or get_contents, and passing in cls to get_contents in the abstract class - but no luck.
So, pretty much, how can I use the self keyword (aka access attributes) in only some implementations of an abstract method, that's called within a class method in the abstract class itself.
Also, on a side note, how can I access self.sublinks from within all implementations of BaseClass, while having its values different in each instance of an implementation?
There are a few things wrong here. One is that the #classmethod decorator should only be used when you need it to be called on a class.
Example:
class ImplementationOne:
#classmethod
def display(cls):
print(f'The class name is {cls.__name__}.')
ImplementationOne.display()
There is nothing special about the name self. It's just what is used by everyone to refer to the instance. In python the instance is implicitly handed to the first argument of the class unless you have a #classmethod decorator. In that case the class is handed as the first argument.
That is why you are getting the TypeError. Since you are calling the method on the instance test_one.display() you are essentially calling it as an instance method. Since you need to access the instance method get_contents from within it that is what you want. As a classmethod you wouldn't have access to get_contents.
That means you need both the ABC and ImplementationOne to have those methods implemented as instance methods.
Since it is now an instance method on the ABC it also should be an instance method in ImplementationTwo.
Your other question was how to get self.sublinks as an attribute in both subclasses.
Since your are overriding __init__ in ImplementationOne you need to call the parent class's __init__ as well. You can do this by using super() to call the Super or Base class's methods.
class ImplementationOne(BaseClass):
def __init__(self, url):
self.url = url
super().__init__()
Full working code:
from abc import ABC, abstractmethod
class BaseClass(ABC):
def __init__(self):
self.sublinks = []
def display(self):
print(self.get_contents())
#abstractmethod
def get_contents(self):
pass
class ImplementationOne(BaseClass):
def __init__(self, url):
self.url = url
super().__init__()
def get_contents(self):
return "The url was: " + self.url
class ImplementationTwo(BaseClass):
def get_contents(self):
return "This does not need a url"
test_one = ImplementationOne("https://google.com")
test_two = ImplementationTwo()
test_one.display()
test_two.display()
print(test_one.sublinks)
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>
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.
When I create a parent class and child class as shown below, why don't the arguments from the parent class automatically get pulled in by the child class?
I understand that explicit is better, but I'm wondering in what circumstance this code...
class testParent(object):
def __init__(self,testParentParam1,testParentParam2):
pass
class testChild(testParent):
def __init__(self,testParentParam1,testParentParam2,testChildParam1,testChildParam2):
pass
Is better than this code...
class testParent(object):
def __init__(self,testParentParam1,testParentParam2):
pass
class testChild(testParent):
def __init__(self,testChildParam1,testChildParam2):
pass
Derived classes extend base classes. That means they might need more/less/different information at construction time to do their extending. Consider:
class BaseTextDocument(object):
def __init__(self, content):
self.content = content
class WordDocument(object):
def __init__(self, path, word_version="guess_from_file"):
content = parse_word_document(path, word_version)
super(WordDocument, self).__init__(content)