0

I am new to Python and want to create classes/structures similar to c++ but I have problems understanding what python actually does

from dataclasses import dataclass

class innerClass:
    x: int


class outerClass:
    a: innerClass
    b: str
    c: str

test_1 = outerClass()

def setTest(val):
    global test_1
    test_1.x=val


def getTest():
    z=1
    global test_1
    if z==1:
        setTest(z)
    
    return [test_1.x]

getTest()

If I change the value of z to z=0 then it has the following issue

Traceback (most recent call last):
  File "simplePy.py", line 27, in <module>
    getTest()
  File "simplePy.py", line 25, in getTest
    return [test_1.x]
AttributeError: 'outerClass' object has no attribute 'x'

so I have two questions

  1. how does it access x with only test_1.x? I would expect it to be test_1.a.x as outerClass->innerClass->variable
  2. as it worked with z=1 why does it complain about x not being an attribute with z=0? I was expecting it to return either rubbish value or zero

2 Answers2

2

I think the main problem is that outerClass has no x. You should call outerClass.inner.x.

You also forgot to use the dataclass decorator in your classes. Without it, they behave like regular classes and you'd need to define an __init__.

Furthermore, the globals are not doing anything. A variable must be defined as global if you want to re-assign it, eg test_1 = None, but you can re-assign its attributes without the global keyword.

Here's my version of the code:

from dataclasses import dataclass

@dataclass
class InnerClass:
    x: int

@dataclass
class OuterClass:
    inner: InnerClass
    a: str
    b: str
    c: str

outter_instance = OuterClass(inner=InnerClass(x=0), a="a", b="b", c="c")

print(outter_instance.inner.x)
outter_instance.inner.x = 5
print(outter_instance.inner.x)

Some things I did:

  • use the dataclass decorator
  • use PascalCase in classes names, which is the standard in Python
  • rename some attributes to make them clearer, eg outter_instance and OutClass.inner
  • remove the functions and run everything in the module

Finally, you can also do this without dataclasses:

class InnerClass:
    def __init__(self, x: int):
        self.x = x

class OuterClass:
    def __init__(self, inner: InnerClass, a:str, b:str, c:str):
        self.inner = inner
        self.a = a
        self.b = b
        self.c = c

outter_instance = OuterClass(inner=InnerClass(x=0), a="a", b="b", c="c")

print(outter_instance.inner.x)
outter_instance.inner.x = 5
print(outter_instance.inner.x)
Duarte P
  • 154
  • 12
1
  1. How does it access x with only test_1.x? I would expect it to be test_1.a.x as outerClass->innerClass->variable

When you call setTest(z) it creates the test_1.x attribute. Python doesn't normally prevent you from creating new attributes in an object (it's possible to prevent this, but it's not the default).

  1. as it worked with z=1 why does it complain about x not being an attribute with z=0? I was expecting it to return either rubbish value or zero

With z = 0 you never call setTest(), so the x attribute is never added to the object. So you get an error when you try to access it.

Barmar
  • 741,623
  • 53
  • 500
  • 612
  • can you write an quick line how to access it properly because its still not working with `test_1.a.x=val` I get `AttributeError: 'int' object has no attribute 'x'` – Andrew Ahmos Jun 22 '22 at 16:02
  • That means you didn't set `test_1.a` to an `InnerClass` instance. You need `test_1 = OuterClass(InnerClass(0), 0, 0)` – Barmar Jun 22 '22 at 16:06
  • sorry the previous comment had some code in it but it was messed up, updated the comment :) – Andrew Ahmos Jun 22 '22 at 16:07
  • I know, I already answered the updated comment. – Barmar Jun 22 '22 at 16:07
  • are there anything like default constructors where I don't have to set these values myself? – Andrew Ahmos Jun 22 '22 at 16:08
  • 1
    See https://stackoverflow.com/questions/56665298/how-to-apply-default-value-to-python-dataclass-field-when-none-was-passed – Barmar Jun 22 '22 at 16:09