I need to override __import__ function in python when I dynamically import a derived class. (I only have access to the base class code). For example:
Servers=[]
class ServerBase(object):
name='' #name of the specific server class, for each server class
def __init__(self):
self.connected = False
self.name = self.__class__.__module__.capitalize()
Servers.append(self)
When a derived class is imported I need to call __init__ of the base class to add it to Servers[] list, so when in the main module I call:
__import__('DerivedClassName')
Base __init__ will be called
I ended up metaclassing the Servers class:
Servers=[]
''' Servers Metaclass that handles addition of servers to the list '''
class MetaServer(type):
def __init__(self, name, bases, attrs):
self.name = name.capitalize()
Servers.append(self)
super(MetaServer, self).__init__(name, bases, attrs)
class ServerBase:
__metaclass__ = MetaServer
name='' #name of the specific server class, for each server class
def __init__(self):
self.connected = False
That way every time a derived class was imported meta-init got called.
Exactly what I wanted.
Thanks #MartijnPieters
Related
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)
In Python, I'm using inheritance for a class. The initial init for the main parent class is below:
def __init__(self, Date = None):
self.Date = Date
self.DatabaseClass = Database()
self.Connection = self.DatabaseClass.databaseConnection()
I've inherited the class into the child class, but am wondering what the correct approach would be to inherit DatabaseClass and Connection variables, i.e., what would be in def __init__?
You just need to call the inherited __init__ method from your own class's __init__ method.
class Child(Parent):
def __init__(self, Date=None, other, arguments):
super().__init__(Date)
# ...
I have a BaseClass and an AbstractClass that inherits from the BaseClass. This is the structure I have in place
class BaseClass(object):
def __init__(self, initialize=True):
self.name = 'base_class'
self.start = 0
if initialize:
self.start = 100
class AbstractClass(BaseClass):
def __init__(self):
self.name = 'asbtract_class'
super(BaseClass, self).__init__()
I want to pass the abstract class an initialize parameter that gets transferred to the base class and if True sets the object's start value to 100.
I tried using the super(BaseClass, self).__init__() but the abstract class gets no start attribute. I get an error when I try to access it.
How can I pass a value the initialize argument to the AbstractClass and use the BaseClass's __init__ method to set the start attribute on the AbstractClass.
The code I used
best = BaseClass()
abs = AbstractClass()
abs.start # AttributeError: 'AbstractClass' object has no attribute 'start'
To invoke the constructor of the super class you should use the class name of the sub class and not the super class, i.e.:
class AbstractClass(BaseClass):
def __init__(self):
super(AbstractClass, self).__init__()
self.name = 'abstract_class'
Note also that I changed the order of invoking the constructor of the super class and setting the name attribute. If you set it before calling the super, the attribute would be overridden by the constructor of the super class, which is most likely not what you intended
And as #Sraw pointed out, for python 3 the notation of calling the super no longer requires the referencing of the class name and can be simplified to
class AbstractClass(BaseClass):
def __init__(self):
super().__init__()
I want to call an instance method but the instance itself is unknown to me. The instance can be identified by it's attributes which I know, e.g. a unique name.
Here're my class definitions and instantiation:
from abc import ABCMeta
class MyAbstractClass():
__metaclass__ = ABCMeta
def do_something(self):
print(self.name)
class MyFirstClass(MyAbstractClass):
def __init__(self):
self.name = 'first'
class MySecondClass(MyAbstractClass):
def __init__(self):
self.name = 'second'
my_first_class_instance = MyFirstClass()
my_second_class_instance = MySecondClass()
What I want to achive is a look-up by name:
def myPrint('first'):
# should call my_first_class_instance.do_something()
def myPrint('second'):
# should call my_second_class_instance.do_something()
I looked into the built-in class methods but didn't find a way to manage the parametrization of the calls.
What's a good way of doing this?
Let me give a brief explanation of the issue:
I have a server object with several functionalities.
all functionalities have some common code, so this warrants a functionalities base class
Each functionality has its own set of constants, defined in a constants class within the functionality.
The functionality base class has a set of common constants as well.
here is a sample code:
class server:
class base_func:
class common_consts:
name = "name"
def validate(self):
pass
def execute(self):
pass
class func1(base_func):
class consts:
new_name = base_func.common_consts.name #this is where the problem occurs
def get_result(self):
self.validate()
self.execute()
so when i try to use the common_consts from base_func, in func1.consts, I get the following error:
NameError: global name 'base_func' is not defined
I do not know why this happens. Can someone help?
Is there a limitation to the scope of nesting in python, especially 2.7
Also if i remove the top level server class, and have the functionality classes as independent classes, everything seems to work fine. The example of the working code is here:
class base_func:
class common_consts:
name = "name"
def validate(self):
pass
def execute(self):
pass
class func1(base_func):
class consts:
new_name = base_func.common_consts.name #this is where the problem occurs
def get_result(self):
self.validate()
self.execute()
This leads me to believe that there definitely exists some limitation to the nesting depth and namespace scopes in python. I just want to be sure before i make changes to my design.
class server:
class base_func:
class common_consts:
name = "name"
def validate(self):
pass
def execute(self):
pass
# base_func and func1 are at same, level. So, here you can directly use base_func and func1 anywhere
# at top level of the server class
class func1(base_func):
class consts:
new_name = base_func.common_consts.name # this is where the problem occurs
def get_result(self):
self.validate()
self.execute
For a class(classes have their own namespace), variable lookup works like this:
While parsing the class body any variable defined inside the class body can be access directly, but once
it is parsed it becomes a class attribute.
As, the class base_func is inside server class which is still being parsed the func1(base_func) will work fine.
But, for class consts base_func is not at the same level. So, after looking the variable in its body it will directly jump
to its enclosing scope, i.e global namespace in this case.
A fix will be to do the assignement like this:
class server:
class base_func:
class common_consts:
name = "name"
def validate(self):
pass
def execute(self):
pass
class func1(base_func):
class consts:
pass
def get_result(self):
self.validate()
self.execute
func1.consts.new_name = base_func.common_consts.name
You've hit a problem with class scope. The class scope is never made available except to operations that directly occur in the class scope. This is why you can't call method within another method without referencing self.
eg.
class A(object):
def f(self):
pass
def g(self):
f() # error, class scope isn't available
The same is true when you create a nested class. The initial class statement class ClassName(Base): has access to the class scope, but once in the nested class scope you lose access to the enclosing class scope.
Generally, there is no good reason to nest classes in python. You should try to create all classes at module level. You can hide internal classes by either placing them in a sub module or all prefixing them with an underscore.
class _BaseFunctionality(object):
# common constants
name = "name"
value = "value"
def execute(self):
return (self.name, self.value)
class _SpecificFunctionality(_BaseFunctionality):
# specific constants
# override value of value attribute
value = "another_value"
def get_result(self):
assert self.name == "name"
return self.execute()
class Server(object):
functionality = _SpecificFunctionality()
assert _BaseFunctionality.value == "value"
assert _SpecificFunctionality.value == "another_value"
assert Server().functionality.get_result() == ("name", "another_value")