this question must be a stupid one but important one and couldn't find any discussion about this in stackoverflow.
I'm trying to declare a class (lets say class 'B') inside another class (lets say 'A'), and use that class('B') in a method of class 'A', but for some reason in python you cannot declare an object member of class type that is declared in the same class.
why is that the case? in C you can access to the inner class from a method of the outside class without any problem...
(my intention that is only class A will ever need a member of type class B and i want only A to be able to find out that such a class like B...)
what is the proper way to do so in python?
class A:
def __init__(self):
self.B_object = B() # error 'unresolved refernace B'
class B:
def __init(self):
pass
class A:
def __init__(self):
self.B_object = A.B()
class B:
def __init(self):
pass
Try this
if you want to make B class private you can try this
class A:
def __init__(self):
self.__B_object = A.__B()
class __B:
def __init__(self):
pass
Related
I'm trying to define two clases, A and B, with B being the child, as in the following code
class A:
def __init__(self, att_A=False):
self.att_A = att_A
def call_B(self):
b = B()
class B(A):
def __init__(self):
super().__init__()
print(f'{self.att_A=}')
a = A()
a.att_A = True
a.call_B()
B does properly inherit the methods and attributes at the time of definition but I want it to also access the values of self.att_A even when they were updated after being initiated.
Is it possible to do that or is there any workaround, like forwarding the attribute as a method parameter?
I have tried deffining att_A as a class attribute but still B cannot access the updated value
So, I think the code probably explains what I'm trying to do better than I can in words, so here goes:
import abc
class foo(object):
__metaclass__ = abc.ABCMeta
#abc.abstractmethod
def bar(self):
pass
class bar_for_foo_mixin(object):
def bar(self):
print "This should satisfy the abstract method requirement"
class myfoo(foo, bar_for_foo_mixin):
def __init__(self):
print "myfoo __init__ called"
self.bar()
obj = myfoo()
The result:
TypeError: Can't instantiate abstract class myfoo with abstract methods bar
I'm trying to get the mixin class to satisfy the requirements of the abstract/interface class. What am I missing?
Shouldn't the inheritance be the other way round? In the MRO foo currently comes before bar_for_foo_mixin, and then rightfully complains. With class myfoo(bar_for_foo_mixin, foo) it should work.
And I am not sure if your class design is the right way to do it. Since you use a mixin for implementing bar it might be better not to derive from foo and just register it with the 'foo' class (i.e. foo.register(myfoo)). But this is just my gut feeling.
For completeness, here is the documentation for ABCs.
i think (tested in similar case) that reversing the baseclasses works:
class myfoo(bar_for_foo_mixin, foo):
def __init__(self):
print "myfoo __init__ called"
self.bar()
so in the mro() it would find a concrete version of bar() before it finds the abstract one. No idea if this is actually what happens in the background though.
Cheers, Lars
PS: the code that worked in python 2.7 (python 3 has a different way to set metaclasses) was:
class A(object):
__metaclass__ = abc.ABCMeta
#abc.abstractmethod
def do(self):
pass
class B(object):
def do(self):
print "do"
class C(B, A):
pass
c = C()
1. A problem with dataclass mix-ins, solved
To make abstract dataclasses that type-check under mypy, I've been breaking them into two classes, one that contains the abstract methods and one that contains the data members, as explained in this answer. The abstract class inherits from the dataclass. This runs into a problem, though, when another abstract-class-and-dataclass pair inherits from the first one: the "ancestor" dataclass's fields get wiped out by the "descendant". For example:
from dataclasses import dataclass
from abc import ABC, abstractmethod
#dataclass
class ADataclassMixin:
a_field: int = 1
class A(ADataclassMixin, ABC):
#abstractmethod
def method(self):
pass
#dataclass
#class BDataclassMixin(A): # works but fails mypy 0.931 type-check
class BDataclassMixin: # fails
b_field: int = 2
pass
class B(BDataclassMixin, A):
def method(self):
return self
o = B(a_field=5)
The last line fails, yielding this error message:
TypeError: BDataclassMixin.__init__() got an unexpected keyword argument 'a_field'
B's method-resolution order (B.__mro__) is (B, BDataclassMixin, A, ADataclassMixin, ABC, object), as expected. But a_field is not found.
A solution, shown in the commented-out line above, is to put the ancestor class explicitly in the descendant dataclass's declaration: class BDataclassMixin(A) instead of class BDataclassMixin. This fails type-checking, though, because a dataclass can only be a concrete class.
2. A problem with that solution, unsolved
The above solution breaks down if we add a third class, inheriting from B:
#dataclass
#class CDataclassMixin: # fails
class CDataclassMixin(A): # fails
#class CDataclassMixin(B, A): # works but fails type-check
c_field: int = 3
pass
class C(CDataclassMixin, B):
def method(self):
return "C's result"
pass
o = C(b_field=5)
Now, C has a_field and c_field but has lost b_field.
I have found that if I declare CDataclassMixin explicitly to inherit from B and A (in that order), b_field will be in the resulting class along with a_field_ and c_field`. However, explicitly stating the inheritance hierarchy in every mix-in defeats the purpose of mix-ins, which is to be able to code them independently of all the other mix-ins and to mix them easily and any way you like.
What is the correct way to make abstract dataclass mix-ins, so that classes that inherit from them include all the dataclass fields?
The correct solution is to abandon the DataclassMixin classes and simply make the abstract classes into dataclasses, like this:
#dataclass # type: ignore[misc]
class A(ABC):
a_field: int = 1
#abstractmethod
def method(self):
pass
#dataclass # type: ignore[misc]
class B(A):
b_field: int = 2
#dataclass
class C(B):
c_field: int = 3
def method(self):
return self
The reason for the failures is that, as explained in the documentation on dataclasses, the complete set of fields in a dataclass is determined when the dataclass is compiled, not when it is inherited from. The internal code that generates the dataclass's __init__ function can only examine the MRO of the dataclass as it is declared on its own, not when mixed in to another class.
It's necessary to add # type: ignore[misc] to each abstract dataclass's #dataclass line, not because the solution is wrong but because mypy is wrong. It is mypy, not Python, that requires dataclasses to be concrete. As explained by ilevkivskyi in mypy issue 5374, the problem is that mypy wants a dataclass to be a Type object and for every Type object to be capable of being instantiated. This is a known problem and awaits a resolution.
The behavior in the question and in the solution is exactly how dataclasses should behave. And, happily, abstract dataclasses that inherit this way (the ordinary way) can be mixed into other classes willy-nilly no differently than other mix-ins.
Putting the mixin as the last base class works without error:
#dataclass
class ADataclassMixin:
a_field: int = 1
class A(ABC, ADataclassMixin):
#abstractmethod
def method(self):
pass
#dataclass
class BDataclassMixin:
b_field: int = 2
class B(A, BDataclassMixin):
def method(self):
return self
o = B(a_field=5)
print((o.a_field, o.b_field)) # (5,2)
I have to model several cases, each case is realised by a class. I want to make sure that each class must have 2 methods get_input() and run(). So in my opinion, I can write a CaseBase class where these 2 methods are decorated as #abstractmethod. Therefore, any child class has to implement these 2 methods. And this is exactly my goal.
However, due to the nature of my work, each case is for distinct subject, and it is not easy to define a fixed group of attributes. The attributes should be defined in the __init__ method of a class. That means I don't know what exactly attributes to write in the CaseBase class. All I know is that all children cases must have some common attributes, like self._common_1 and self._common_2.
Therefore, my idea is that I also decorate the __init__ method of CaseBase class by #abstractmethod. See my code below.
from abc import ABC, abstractmethod
from typing import Dict, List
class CaseBase(ABC):
#abstractmethod
def __init__(self):
self._common_1: Dict[str, float] = {}
self._common_2: List[float] = []
...
#abstractmethod
def get_input(self, input_data: dict):
...
#abstractmethod
def run(self):
...
class CaseA(CaseBase):
def __init__(self):
self._common_1: Dict[str, float] = {}
self._common_2: List[float] = []
self._a1: int = 0
self._a2: str = ''
def get_input(self, input_data: dict):
self._common_1 = input_data['common_1']
self._common_2 = input_data['common_2']
self._a1 = input_data['a1']
self._a2 = input_data['a2']
def run(self):
print(self._common_1)
print(self._common_2)
print(self._a1)
print(self._a2)
def main():
case_a = CaseA()
case_a.get_input(input_data={'common_1': {'c1': 1.1}, 'common_2': [1.1, 2.2], 'a1': 2, 'a2': 'good'})
case_a.run()
if __name__ == '__main__':
main()
My question: Is my way a good Python style?
I followed many Python tutorials about how to make Abstract class and child class. They all give examples where a fixed group of attributes are defined in the __init__ method of the base class. I also see some approach to use super().__init__ code in the child class to change the attributes defined in the base class or to add new attributes. But I am not sure if it is better (more pro) than my way.
Thanks.
You mostly used the abc module in python 3.10 correctly. but it doesn't make sense to decorate the constructor with #abstractmethod. It's unnecessary. Each class, derived or not, can and will have its own constructor. You can call super().__init__(args) within the child class to call the constructor of its immediate parent if you didn't want to duplicate its code but wanted to do further initialization in the child class constructor.
Is it possible to access a class object or its inner class object from a class static variable in python3?
class OuterClass:
all_subclasses = {
# is it possible to access the OuterClass from a class static variable
'innerclass1': OuterClass.InnerClass1
}
#classmethod
isInnerClass(cls, identifier: str):
return identifier.lower() in cls.all_subclasses
class InnerClass1:
def __init__(self):
pass
If not, what will be alternative for this?
You can refer to attributes of the class directly in the class definition, as long as the reference comes after the definition:
class A:
class B:
pass
x = B
print(A.x)
# <class '__main__.A.B'>
This has some caveats. For reasons that are very complicated, you can't use class attributes directly in a comprehension in the class definition:
class A:
class B:
pass
x = [B for _ in range(5)] # NameError: name 'B' is not defined
You also can't refer to the class itself in it's own definition:
class A:
x = A # NameError: name 'A' is not defined
This is because class definition is basically another way of creating a type object
class A:
x = 1
A = type('A', (object,), {'x': 1})
And it makes total sense both that you can't use an object before it's created and that you can't refer to it by a name it hasn't been assigned to yet.
It's important to note that this all applies only to the class definition itself, that is to say all of the code that gets executed directly as the class is created. Code that gets executed later, like method definitions, can refer to the class like any other code or through type(self)