Python Forum
Assignment of non-existing class variable is accepted - Why?
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Assignment of non-existing class variable is accepted - Why?
#1
Hi, I am a newbie. My understanding is that I cannot assign to a non-existing class variable, but the python interpreter (3.8.3) allows this to occur. Why does the following code work without complaint? See the comment for the statement I would think should cause an error. TIA.

class My_object:
    class_var1 = 123

def main():
    my_obj = My_object()
    print(my_obj.class_var1)
    my_obj.foobar = 101   #foobar is not a My_object variable
    print(my_obj.foobar)

main()
Reply
#2
The line
my_obj.foobar = 101
has created a new instance attribute foobar and assigned it the value of 101
Reply
#3
(Jul-12-2020, 03:55 PM)Yoriz Wrote: The line
my_obj.foobar = 101
has created a new instance attribute foobar and assigned it the value of 101

My question should have been expanded a little more...Why is this allowed? Is it a commonly used feature in python programming? I am starting to get a grasp on the subject of object data encapsulation and as I understand it for python this is self-imposed via leading underscores in variable names and using data access methods. As a newbie, it seems to me that allowing "on-the-fly" creation of class variables is an encapsulation violation - no? Why would I ever want to do this? Any and all answers appreciated.
Reply
#4
You're correct. In python it is generally expected that you can create attributes of classes and instances after instantiation.

There are some ways to prevent that for in individual class (like overriding __setattr__ or __slots__), but using them in that way is not simple. Using them improperly can break other bits in subtle ways. Python isn't Java or C++, and attribute creation outside of __init__ is considered normal. Yes, this can cause some problems, but it also gives benefits allowing users the flexibility to do things the author had not anticipated.
Reply
#5
Ok, thanks for that explanation.

"You're correct. In python it is generally expected that you can create attributes of classes and instances after instantiation."
FWIW, I noticed that one can create attributes of the class before any instantiation has occurred and all instances will inherit the newly added attribute.

This all started when I made a bogus assignment to a class instance with a spelling error. The assignment was quietly taken in - no complaints - and I spent a lot of time finding the error. So, I gather that on-the-fly object variables are inherited, but if applied to an instance only remain with that instance.

I will try to understand how to use this "feature".

Thanks again.
Reply
#6
Yup, and typos/spelling/author confusion is the biggest drawback to this flexibility. But linters can help find problems like this early.
Reply
#7
Only class variables and methods are inherited. The only relationship between instance variables and the class is that something executed code that created an instance variable.
class Things:

    favorite_things = ['Raindrops on roses'] # Class variable

    def do_something(self):
        self.favorite_things = ['Bright copper kettles'] # instance variable

a = Things()
b = Things()
b.do_something()
c = Things()
c.favorite_things = ['Warm wollen mittens']

print('Things', Things.favorite_things)
print('a', a.favorite_things)
print('b', b.favorite_things)
print('c', c.favorite_things)
Output:
Things ['Raindrops on roses'] a ['Raindrops on roses'] b ['Bright copper kettles'] c ['Warm wollen mittens']
In this example, "a" has a class variable and no instance variables. "b" and "c" have a class variable and an instance variable. For "b" the instance variable is defined in a method of Things, but the instance variable for "c" is defined outside the scope of the class. The instance variable "favorite_things" is obviously not inherited, and relies on code that is executed after the instance is created.

When I first started writing classes with inheritance I ran into the "X is not defined" errors all the time. I would look at the code and see the instance variable created in the __init__, but setting a breakpoint before the error I would inspect the instance and there was no instance variable! My problem was that the instance variable was not defined yet. Even though it was defined inside __init__ of the base class, it was used before the base class __init__ was called, or before the base class __init__ had completed.

A linter will complain about instance variables defined outside the __init__ method. Listen to the linter and make you code complient. It is also a good idea to call __init__ for all superclass(es) at the top of the __init__ method.

As for typos, learn how to write unit tests and test everything. The compiler safety net is gone
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  Variable Types in a class nafshar 9 2,443 Oct-07-2022, 07:13 PM
Last Post: deanhystad
  can Inner Class reference the Outer Class's static variable? raykuan 6 5,877 Jul-01-2022, 06:34 AM
Last Post: SharonDutton
  UnboundLocalError: local variable 'wmi' referenced before assignment ilknurg 2 1,905 Feb-10-2022, 07:36 PM
Last Post: deanhystad
  Calling a base class variable from an inherited class CompleteNewb 3 1,673 Jan-20-2022, 04:50 AM
Last Post: CompleteNewb
  is it pythonic to add a name 'attribute' to an existing variable? amjass12 6 2,182 Oct-04-2021, 09:33 PM
Last Post: amjass12
  pls help with this assignment. basic into to python class valerie_thomas 2 2,044 Nov-21-2020, 12:37 PM
Last Post: ibreeden
  Can we access instance variable of parent class in child class using inheritance akdube 3 13,969 Nov-13-2020, 03:43 AM
Last Post: SalsaBeanDip
  Create new variable dependent on two existing variables JoeOpdenaker 6 3,005 Oct-25-2020, 02:15 PM
Last Post: jefsummers
  Class variable / instance variable ifigazsi 9 4,292 Jul-28-2020, 11:40 AM
Last Post: buran
  Limiting valid values for a variable in a class WJSwan 5 3,592 Jul-06-2020, 07:17 AM
Last Post: Gribouillis

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020