Class Variable Acting Like An Instance Attribute

FYI: I am using Python v3.11.5 on Windows 11

Hi,

I am currently getting familiarized with class attributes vs. instance attributes.
The following is a test class to test the difference. My expected output based
on the terminal commands, is:

Expected Output Actual Output
ibm ucd
tester ibm
tester tester

class Person:
    
    company = 'ucd'    # Class attribute

    def __init__(self):
        self.age = 23  # Instance attribute

Terminal Commands:

p1 = Person()
p2 = Person()
p1.company = 'ibm'
print(p2.company)
Person.company = 'tester'
print(p1.company)
print(p2.company)

From python theory, class attributes affect all subsequent instances. It appears
from the results here that the class attribute ‘company’ is being treated like an
instance attribute.

Can someone please advise regarding the discrepancy?

Could you please fix the preformatted text to include all your code?
It is hard to see without the correct indenting.

Hi,

that is all of the code:

class Person:

company = 'ucd'    # Class attribute

def __init__(self):
    self.age = 23  # Instance attribute

The expected output is:
ibm
tester
tester

Instead, I am getting the following:
ucd
ibm
tester

What do you mean by “all subsequent instances”?

By instances, I mean as in:

p1 = Person()
p2 = Person()
.
.
.
pn = Person()

Since it is a ‘class’ attribute, it should be the same for all instances (at least
according to theory).

So, if I gave the following command:
p1.company = ‘change variable result’ # As an example of course

then, for all instances:
print(pn.company) # should all be ‘change variable result’
# where ‘n’ can be any integer

p1.company = "abc"

creates (or resets) a new instance attribute for p1. This is not identical to Person.company.

Person.company = "xyz"

changes the company attribute of all new (and old) Person instances:

>>> class P:
...     comp = "abc"
>>> p = P()
>>> p.comp
'abc'
>>> P.comp = "xyz"
>>> p.comp
'xyz'
>>> p.comp = "123"
>>> p.comp
'123'
>>> P.comp
'xyz'

See: 9. Classes — Python 3.12.0 documentation

If the same attribute name occurs in both an instance and in a class, then attribute lookup prioritizes the instance

Hi,

thank you for your response. This makes a lot of sense as the change
is being directed from the class itself. I was actually basing my proposition
from the attached tutorial which I found during a search on composition.

Notice how it states:

Change to class attribute ‘company’ affects all instances …’

1 Like

Yes, so the information in the last block is misleading/incorrect since p1.company = "ibm" does not in any way impact the class attribute Person.company.

There is a glut of tutorials currently - I don’t think all of them are particularly good…

In that case, the tutorial has two ‘typos’. A ‘screenshot’ of the test run results and the instructions
stating the expected results.

In any case, since you’re here, I want to learn more on composition via examples since I am
prepping myself for the tkinter module for GUI creation. From my initial research on the subject matter,
this module is inheritance/composition heavy. Do you have any recommendations?

Yeah, unfortunately that tutorial seems to have written it wrongly. It would be correct if it said it like this:

>>> p1 = Person()
>>> p2 = Person()
>>> Person.company = "IBM"
>>> p2.company
'IBM'

Though I’ve made the same blunder that the tutorial author presumably did, and typed this out directly, without testing it at the REPL. I know this because the example says print p2.company which is a SyntaxError in current Pythons, but even in older Pythons where it would have been legal, it would have just printed out ibm rather than putting it in quotes.

So! Here’s what actually happens. Whenever you look something up, Python goes first to the instance, and then, if it’s not found, goes to the class. It’s the same as how nested scopes work:

company = "IBM"
def p1():
    print(company) # IBM

def p2():
    company = "two" # three's a crowd, yaknow?
    print(company) # two

It’s the same with instance and class attributes. Python will look first at the individual instance, then at the class. Note that this applies to everything. Methods aren’t particularly special - they’re just functions - and when you say thing.method(), Python looks first to see if there’s an instance attribute on thing, and then looks for type(thing).method.

Hope that clears things up!

I don’t really have experience with tinter - apart from knowing it exists (and I believe IDLE was written using it). But “Python GUI Programming With Tkinter – Real Python” seems a pretty decent intro.

Hi,

thank you for your time replying to my query. Your effort is very much
appreciated. Yes, it makes sense to me since I am used to programming
in C (procedural/embedded - so I am familiar with local/global variables).
I never really had to think in terms of ‘objects’ before. So, now that I am
really delving into this new language, I want to make sure that I understand
the theory and concepts correctly and thoroughly so that I have
a good base of understanding for creating GUIs using tkinter.

Again, thank you very much for your explanation.

1 Like

Thank you! Going over it now.

Much appreciated!

No problem, happy to help!

The similarity between scopes, objects, and dictionaries in Python is very real. In fact, most scopes are implemented using dictionaries that map variable names to their values, and most objects (including type objects as created by classes) have a dictionary that maps instance attributes to their values.

wxPython :smiling_face_with_three_hearts: