Want to write to variables in one class, then inherit those set variable values in another class without having set the values again.
Below code should print 100, without having to initialize the values again for subclass instance; want to use the originally set values in master class (data handler).
One class manages all income data; Data Handler, then the other classes simple inherit those values. What is the way of handling this flow structure ? Please and Thank you!!
from dataclasses import dataclass
#dataclass
class Datahandler:
A : int
B : int
C : int
D : int
E : int
F : int
Datahandler=Datahandler(100,100,50,40,10,1000)
class Some_Class(Datahandler):
pass
print(Some_Class.A)
To define an attribute of a class, assign to it in the class definition, not inside any function.
class Datahandler:
staticmember = 200
The dataclass class won't help you with that. It is for defining attributes of class instances, not classes.
You can then access the base class member in a derived class, which is what you want to do.
class Some_Class(Datahandler):
pass
print(Some_Class.staticmember)
Also, you should avoid using the same name for a class and an instance of that class.
Datahandler=Datahandler(100,100,50,40,10,1000) #Likely problematic
Edit: While I answered the question as posted, there are simpler ways to do the same thing without using inheritance, as #juanpa.arrivillaga suggested.
Related
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)
When i use the subclass method, a method that base class don't have, comes the warning.
Code is as following:
class A:
pass
class B(A):
def b_method(self):
pass
def test(arg: A):
arg.b_method() #generate warning at this line
warning:Unresolved attribute reference 'b_method' for class 'A'
The variables of the input function can only be class A and its subclasses, and the function will call the unique method of some subclasses. How to write type annotations to eliminate the warning?
Any help would be greatly appreciated!
The behavior you are seeing is expected.
A is the parent class
B is child class.
B can access a method that A has but not vice versa..
Makes sense?
In one of my classes, I am printing data from another class that is yet to be initialized.I only want to print that data once the class has been initialized.Is there any way check if the class has been instantiated?
Two functions that return true if you pass an undeclared class, and false if it is instantiated:
import inspect
inspect.isclass(myclass)
or
isinstance(myclass, type)
In general, if it's not a type (i.e. undeclared class), it's an instantiated type.
Simply add a variable into the class to be made, like this:
class tobeinitiated():
initiated=False
def __init__(self):
global initiated
tobeinitiated.initiated = True
Then, where you need the information:
global initiated #(if in class)
if tobeinitiated.initiated:
#do the stuff you need to do
Hope this helps. :)
You can add a counter of instances in the constructor for example.
I am a bit confused with the definition of class inside a function.
Usually while defining class inside a function, we define it as follows:
def dude():
class swaroop(object)
What if there is no object at all and the function goes like this:
def dude():
class swaroop():
What does this mean?
The class(object) syntax is an example of inheritance. If you remove the inherited object, then the class that you create inherits from nothing and is therefore a new class. Because you're defining it within a function, it can only be used within that scope.
If I have the following :
class A:
attrs = [...]
A_attr = [...]
class B(A):
B_attr = [...]
Is there a way to prevent my B subclass from inheriting the A_attr from the A class?
Or would this be considered a bad design and I should better subclass both A and B from a third C class containing all the attrs attributes and add the particular attribute to each subclass like this?
class C:
attrs = [...]
class A(C):
A_attr = [...]
class B(C):
B_attr = [...]
Better idea is to dump the common functionality in a class.
class Commmon:
attrs = [...]
Extend this class who want this extra functonality.
class A(Common):
# only one attribute added in this class
A_attr = [...]
classB(Common):
attrs_B = [...]
Extend class A when that extra attribute is needed in the class, this will bring all those other attributes.
class C(A):
attrs_C = [...]
What this will allow is wherever you want an object of type Common you can provide instance of B as well as C. And wherever you want instance of class A you can provide instance of C. If you add specific instance in each of your subclasses you will not be able to do so.
From Comment
So according to you I should use the second solution I exposed in my question.
No.
Instead of adding the attribute in each subclass, my advice is to add the attribute in a separate class and let your new classes inherit this intermediate class. So you do not have to add the specific attribute in each one of those subclass.
Example is already provided above. Lets see what is the benefit of doing this, as opposed to your suggestion. Take the following function
def foo(obj):
# check to make sure object has the specific attribute
if (isinstance(obj, A)):
pass; #do something
else:
raise TypeError("Object is not an instance of A")
But if we add the specific attribute in each class, the method will need to be changed to something like this:
def foo(obj):
# check to make sure object has the those type which has that specific attribute
if( isinstance(obj, class1) or (isinstance(obj, class2) or ...):
pass; #do something
else:
raise TypeError("Object does not have specific attribute")
Of course, you can perform a check using something like this:
def foo(obj):
# check to make sure obj has attribute
if hasattr(obj, 'property')
pass; # do something
else:
raise TypeError("Object does not have necessary attribute")
Using correct inheritance relationship (as shown in 1st example) will also help your IDE (if you are using one) in inferring types, because IDE can determine which type of object it expects. You can even augment the function with type information like this:
def foo(obj : A):
pass; #do something
That A after colon is a hint to the IDE that function expects an object of type or subtype of A.