'Classes with property referencing other classes
I'm creating a library, and one part of it requires a structured model.
Let's say we have sections, and each section can have subsections (categories). All of them fit this model:
class Section:
sec_property = ""
class Category:
sub_property = ""
class General:
sec_property = ""
sub_property = ""
Now, I want to have multiple sections, and each one should have custom categories, or even other sections, which would reference the specific one. Each category inherits from its section, so it has access to the sec_property
of the parent.
This is what I have right now, but I'm facing some issues with it.
class CARS(General):
sec_property = "car"
CAR1 = None
class CAR1(CARS):
sub_property = "car1"
CARS.CAR1 = CAR1
I want to be able to access CAR1
only through CARS
-> CARS.CAR1
. The issue right now is, that it acts as a property of the class, not a class itself, meaning the IDE doesn't recognize it properly.
Why I want the inheritance, and General class: I want to be able do anyClass.sub_property
, and it should either return the empty string or the property itself. I also want to be able to do anyCategory.sec_property
, and it should have the property of the parent class (hence the inheritance).
I want to avoid duplicating data and other bad practices.
The goal
# sections.py
class MOTOR(PARTS):
sub_property = "motor"
class PARTS(General):
sec_property = "parts"
MOTOR = MOTOR
class CAR1(CARS):
sub_property = "car1"
class CARS(General):
sec_property = "car"
CAR1 = CAR1
PARTS = PARTS
In this example, the CAR1 is an alias to the class itself, not a property, constant or anything. The issue is, that it can't inherit from CARS
in this case, which I would very much like to do.
I want to be able to access all categories (sub-sections) from the sections themselves, and be able to access the parent attributes (unless they are overridden, where a section would have another section as reference).
I also don't want to create duplicates (instead of inheriting the attribute sec_property
assign it to each category), as that's not really a great practise.
# some other .py
import sections
sections.CARS.CAR1.sec_property
sections.CARS.CAR1.sub_property
sections.CARS.PARTS.MOTOR.sec_property
sections.CARS.PARTS.MOTOR.sub_property
sections.PARTS.MOTOR.sec_property
# etc etc
I also don't want to be able to access the categories (CAR1
, MOTOR
) directly, but I've already figured that one out - create __init__.py
and include the stuff I want, and don't include the rest.
Clarifications
I only need to access these as special dataclasses, or enums, or something like that. I don't need to make instances of them ever.
I'm looking for a solution that IDEs recognize properly. My current solution (second codeblock with the = None
) works without errors at runtime, but the IDE has no idea what I'm working with, therefore can't suggest anything. https://i.imgur.com/l5hsQOE.png https://i.imgur.com/KOkWbuM.png
Info on how I generate the file: First I make all the definitions with no connections (only inheritance), and at the end, I connect everything, so it links properly.
Specific file in question
Solution 1:[1]
Use type hints with forward references (string literals):
class PARTS(General):
sec_property = "parts"
MOTOR: "MOTOR" = None
class MOTOR(PARTS):
sub_property = "motor"
class CARS(General):
sec_property = "car"
CAR1: "CAR1" = None
PARTS: "PARTS" = None
class CAR1(CARS):
sub_property = "car1"
PARTS.MOTOR = MOTOR
CARS.CAR1 = CAR1
CARS.PARTS = PARTS
Verifying the annotations programmatically:
assert "PARTS" in CARS.__annotations__
assert "MOTOR" in CARS.PARTS.__annotations__
Strictly speaking, the type hints should be Optional[Type["TYPE"]
:
from typing import Optional, Type
class General:
sec_property = ""
sub_property = ""
class PARTS(General):
sec_property = "parts"
MOTOR: Optional[Type["MOTOR"]] = None
class MOTOR(PARTS):
sub_property = "motor"
class CARS(General):
sec_property = "car"
CAR1: Optional[Type["CAR1"]] = None
PARTS: Optional[Type["PARTS"]] = None
class CAR1(CARS):
sub_property = "car1"
PARTS.MOTOR = MOTOR
CARS.CAR1 = CAR1
CARS.PARTS = PARTS
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 |