2

I am just beggining to learn python (coming from C); I have found myself very confused regarding the way that variables belonging to a class are defined (don't care if "class type" or "instance type" yet, my question is way more basic). This far I have experimented with these code lines:

class A:
  pass

A.a = 1
A.b = 2
print(A.a+A.b)

This code surprisingly returned "3" (while I expected an error), which leads me to here. I don't understand why the interpreter is able to infere the variables (which I never defined) belonging to the class "A".

Saularis
  • 389
  • 4
  • 13
  • 4
    you did define them. by doing `A.a = 1` you now created an attribute `a` of the class `A`. This is possible because user-defined classes come with `__dict__` which holds the mapping of attributes. Try for example doing `object().a = 1` and see what happens – Tomerikoo Jul 31 '19 at 11:34
  • Python's class model is quite different from C's. You *should* worry about the details, as your intuition from C isn't going to help you as much as you might think. – chepner Jul 31 '19 at 11:40
  • 2
    Your confusion stems from the fact that you didn't *declare* the attributes first in the `class` statement, but Python doesn't *have* variable declarations at all, only definitions. – chepner Jul 31 '19 at 11:41
  • 1
    @chepner I agree, I'm suffering from Stockholm syndrome to C at this point... – Guillermo. D. S. Jul 31 '19 at 11:47
  • 1
    @Guillermo.D.S. - I'm not sure that ever goes away, C is a very good captor – Sayse Jul 31 '19 at 11:51
  • 2
    I'll note, thought, that while you *can* add attributes to (most) objects at any time, you *should* refrain from doing so. Initialize the *expected* class attributes in the `class` statement itself, and initialize expected instance attribute in the class's `__init__` method. You can *change* the value of either later using direct access, but don't *add* new attributes in this fashion. – chepner Jul 31 '19 at 11:55

1 Answers1

2

From a C point of view, imagine that Python attributes are stored in a hash table, and so can be modified and queried dynamically at runtime.

Consider this:

class A:
    pass

print(A.__dict__)
{'__module__': '__main__', '__dict__': <attribute '__dict__' of 'A' objects>, '__weakref__': <attribute '__weakref__' of 'A' objects>, '__doc__': None}

When you modify A as you did, you are modifying its __dict__ member:

A.a = 1

print(A.__dict__)
{'__module__': '__main__', '__dict__': <attribute '__dict__' of 'A' objects>, '__weakref__': <attribute '__weakref__' of 'A' objects>, '__doc__': None, 'a': 1}

Note how it now includes a

print(A.__dict__['a'])
1
Ami Tavory
  • 66,807
  • 9
  • 114
  • 153