As I know, the typical child class of python might should be:
class Parent:
"""CODE HERE"""
class Child(Parent):
"""CODE HERE"""
But this doesn't fit my situation. I would like that, when the variable of parent class changes, the child class changes together. So I have to use:
class Session:
def __init__(self):
self.token = 'FoObArFooBar'
self.api_url = f'https://example.com/post/{self.token}'
class Post:
def __init__(self):
pass
def post(self):
requests.post(super.api_url)
So that when I change Session.api_url, the child class Post also changes. But I got this error:
----> 1 Session.Post.post()
TypeError: post() missing 1 required positional argument: 'self'
So how to pass variables in this situation? Thanks.
Related
from abc import abstractmethod
class Parent:
""" Class from some library"""
def __init__(self):
# how can I tell the IDE that the child class should not overwrite this?
self.data = "don't touch this, some other method needs it"
#abstractmethod
def method(self):
pass
def some_other_method(self):
print(self.data)
class Child(Parent):
""" My specified class, that implements the abstract method"""
def __init__(self, data):
super().__init__()
# I did not look into all parents of all parents,
# How to know that this is dangerous?
self.data = data
def method(self):
print(self.data)
child = Child('hello')
child.method()
child.some_other_method()
Is there a way to mark the data attribute in the Parent class so that pylint (or a modern IDE) would warn about overwriting the attribute in the Child?
Or do I always have to check all attributes of all parents manually when using attributes in a child?
The only idea I have is checking for each attribute if it exists after initializing the parent before setting it in a child, but that also seems like some weird overhead to me.
assert not hasattr(super(), "data")
edit: To better explain what I mean, I am probably looking for something similar like the abstractmethod decorator for methods but for protected attributes instead.
For example, if I write something like this in my IDE:
class Parent:
""" Class from some library"""
#abstractmethod
def method(self):
pass
class Child(Parent):
""" My specified class, that should implement the abstract method"""
def __init__(self):
super().__init__()
My IDE complains about the missing implementation of method in the Child:
Class Child must implement all abstract methods
It would be cool to have something similar to mark attributes as protected like:
class Parent:
""" Class from some library"""
def __init__(self):
#protected # does not exist I am afraid
self.data = 'do not touch this'
class Child(Parent):
""" My specified class, that touches the data"""
def __init__(self):
super().__init__()
self.data = 'I touch it!' # should be marked with warning
For the linter/IDE to mark the overwritten protected attribute
Not really, but what you can do is to prefix your attribute with __ and will automatically will be rename when you're outside of the class. See code bellow
>>> class P :
def __init__():
self.__data = "no overwritable"
>>> class C(P):
def __init__(self):
super().__init__()
self.__data = "overwrited"
>>> c = C()
>>> c.__dict__
{'_P__data': 'no overwritable', '_C__data': 'overwrited'}
here your instance of C will have to data attribute, the one from the parent class P accessible through _P__data and the one from the child class C accessible through _C__data
In this way you don't always have to check if an attribute exists in a parent, but you can still access it if you really need it
Consider the following sample snippet
import abc
class BASE(metaclass=abc.ABCMeta):
def __init__(self, name):
assert name is not None, "Name must be provided."
self.num = 3
#abc.abstractmethod
def compute(self):
pass
class CHILD(BASE):
def __init__(name):
'''
'''
def compute(self):
return self.num + 34
On execution it gives the following sensible error :
AttributeError: 'CHILD' object has no attribute 'num'
In the present situation BASE is not being initialized because if we add a print function to it as below, it does not print absolutely anything.
class BASE(metaclass=abc.ABCMeta):
def __init__(self, name):
print(name)
assert name is not None, "Name must be provided."
self.num = 3
Can we do anything in this class design to make sure that an implementor subclassing from BASE must explicitly call the initializer of the BASE ?
Can we do anything in this class design to make sure that an
implementor subclassing from BASE must explicitly call the initializer
of the BASE ?
I guess you can do something like this:
class BASE(metaclass=abc.ABCMeta):
'''
when subclassing this class, ensure you explicitly
call super().__init__() for this parent class
'''
def __init__(self, name):
assert name is not None, "Name must be provided."
self.num = 3
From comments secion:
I just wanted to understand that how in real world problems, designs
are made to ensure that such mistakes do not happen
I have done many sub-classes where I did not explicitly call the super().__init__() of the parent class. So I am not sure if you can say that all sub-classes must call the parent class __init__ to avoid "mistakes" (as you call it). It is up to the creator of the parent class to document properly how to sub-class, and then it is still up to the creator of the sub-class to either do it or not. Not something you can "enforce"
I have one simple doubt with respect to python 2.7:
I have created an abstract base class and a child class:
from abc import ABCMeta, abstractmethod
class Base:
"""
Abstract base class for all entities.
"""
__metaclass__ = ABCMeta
def __init__(self, name):
self.name = name
def send_data(self):
self.send_data()
class Child (Base):
def __init__(self, name):
super(Child, self).__init__(name=name)
When the object for the child class is created and the send_method is called I get the following error which is the expected behavior:
sample = Child('test')
sample.send_data()
# …
RuntimeError: maximum recursion depth exceeded
But when the send_method reference is passed in the base class and call is made to send_method by creating the child class object I think the expected behavior is to receive AttributeError but I am surprised to see no error is generated. Please explain.
from abc import ABCMeta, abstractmethod
class Base:
"""
Abstract base class for all entities.
"""
__metaclass__ = ABCMeta
def __init__(self, name, parent):
self.name = name
self.parent = parent
def send_data(self):
self.send_data
sample = Child('test')
sample.send_data()
# No error
In your first example you simply created a recursive function:
def send_data(self):
self.send_data()
This calls itself, without end, and that's why you end up with a recursion depth exception.
Your second example doesn't actually call the method:
def send_data(self):
self.send_data
The only difference here is that you forgot to use ().
None of this has anything to do with abstract base classes or inheritance. You didn't mark the send_data function as abstract, and even if you did, all that using abstractmethod does is make it impossible to create an instance of a class without a concrete implementation to replace it.
You won't get an AttributeError just because you defined a method on an ABCMeta class. And note that methods are just attributes on a class; they don't live a separate namespace. self.send_data references the bound method, not some other attribute that is separate. Referencing the method without calling it does nothing otherwise.
I have base class like below
class FileUtil:
def __init__(self):
self.outFileDir = os.path.join(settings.MEDIA_ROOT,'processed')
if not os.path.exists(outFileDir):
os.makedirs(outFileDir)
## other methods of the class
and I am extending this class as below:
class Myfile(FileUtil):
def __init__(self, extension):
super(Myfile, self).__init__()
self.extension = 'text'
## other methods of class
But i am getting below error?
super(Myfile, self).__init__()
TypeError: super() takes at least 1 argument (0 given)
I gone through many documents and found that there are different sytex of calling super() in 2.x and 3.x. I tried both ways but getting error.
You have 2 options
old style class, you should call the super constructor directly.
class FileUtil():
def __init__(self):
pass
class Myfile(FileUtil):
def __init__(self, extension):
FileUtil.__init__(self)
new style class, inherit from object in your base class and your current call to super will be processed correctly.
class FileUtil(object):
def __init__(self):
pass
class Myfile(FileUtil):
def __init__(self, extension):
super(Myfile, self).__init__()
You may need to create the FileUtil class using the super() function as well:
class FileUtil(object):
def __init__(self):
super(FileUtil, self).__init__()
...
I'm using wxpython to generate a GUI. The structure of the program I'm doing is shown below. I have a class for each section of the GUI (class1 and class2). I'm using the Panel class to create these sections. class1 and class2 are derived from another class (the Group class). I want to access the methods of a derived class from the other derived class on the fly. So when I'm in classA.method1() I want to call classB.method3(). what is the best way to do that?
class Panel(wx.Panel):
def __init__(self, parent):
class1 = ClassA()
class2 = ClassB()
class Group(wx.Panel):
def __init__(self, parent, name):
.
.
.
class ClassA(Group):
def method1(self):
....
def method2(self):
....
class ClassB(Group):
def method3(self):
....
def method4(self):
....
I's assuming you want to call the class method, not the method of an instance of that class.
From ClassA.method1(), ClassB be should be a global, so all you have to do is:
class ClassA(Group):
def method1(self):
classB.method3(someclass)
Now all you have to do is figure out what you want to put in for 'someclass'. If method3 never uses 'self' then just pass it None. If ClassA is compatible, then you can pass it 'self'. Otherwise, you need to pass it an instance of ClassB.