If you never instantiate your classes it is perfectly OK to do this for namespacing alone:
class Colors:
class RGB:
Red = (255, 0, 0)
Green = (0, 255, 0)
Blue = (0, 0, 255)
class CMYK:
pass
color1 = Colors.RGB.Red
However this is different:
class Big:
class Coordinates:
x = 0
y = 0
coords = Coordinates()
You instantiate a Coordinates
class object in Big
class, specifically in Big.coords
.
x
and y
are 0
for every Coordinates
object instance, at start. But they are also class attributes, not instance attributes. This means they are shared between every instance, until you assign one of them in the instance. Then that particular instance starts to have its own x
or y
. This is totally diferent from what you seem to expect. You should make it like:
class Coordinates:
def __init__(self, x=0, y=0):
self.x = x
self.y = y
class Big:
def __init__(self, coords=None):
self.coords = coords or Coordinates(0,0)
def __str__(self):
return "Big coords at x:{} y:{}".format(self.coords.x, self.coords.y)
big = Big()
print(big)
print(big.coords.x, big.coords.y)
point1 = Coordinates(1, 2)
big1 = Big(point1)
print(big1)
Output:
Big coords at x:0 y:0
0 0
Big coords at x:1 y:2
This way you make one instance contain an instance of another type. This is also an example of using containment instead of inheritance.
Another common way of arranging namespaces is to just organize your names inside modules to import.
See here for other ideas.