difference between variables inside and outside of __init__()

172,329

Solution 1

Variable set outside __init__ belong to the class. They're shared by all instances.

Variables created inside __init__ (and all other method functions) and prefaced with self. belong to the object instance.

Solution 2

Without Self

Create some objects:

class foo(object):
    x = 'original class'

c1, c2 = foo(), foo()

I can change the c1 instance, and it will not affect the c2 instance:

c1.x = 'changed instance'
c2.x
>>> 'original class'

But if I change the foo class, all instances of that class will be changed as well:

foo.x = 'changed class'
c2.x
>>> 'changed class'

Please note how Python scoping works here:

c1.x
>>> 'changed instance'

With Self

Changing the class does not affect the instances:

class foo(object):
    def __init__(self):
        self.x = 'original self'

c1 = foo()
foo.x = 'changed class'
c1.x
>>> 'original self'

Solution 3

I would like to add something to the responses that I read in this thread and this thread (which references this one).

Disclaimer: this remarks come from the experiments I ran

Variables outside __init__:

These are, in fact, static class variables and are, therefore, accesible to all instances of the class.

Variables inside __init__:

The value of these instance variables are only accesible to the instance at hand (through the self reference)

My contribution:

One thing that programmers must consider when using static class variables is that they can be shadowed by instance variables (if you are accessing the static class variables through the self reference).

Explanation:

Previously, I thought that both ways of declaring the variables were exactly the same (silly me), and that was partly because I could access both kind of variables through the self reference. It was now, when I ran into trouble, that I researched the topic and cleared it up.

The problem with accessing static class variables through the self reference is that it only references the static class variable if there is no instance variable with the same name, and to make things worse, trying to redefine a static class variable through the self reference does not work because an instance variable is created which then shadows the previously-accesible static class variable.

To get around this problem, you should always reference static class variables through the name of the class.

Example:

#!/usr/bin/env python

class Foo:
    static_var = 'every instance has access'

    def __init__(self,name):
        self.instance_var = 'I am %s' % name

    def printAll(self):
        print 'self.instance_var = %s' % self.instance_var
        print 'self.static_var = %s' % self.static_var
        print 'Foo.static_var = %s' % Foo.static_var

f1 = Foo('f1')

f1.printAll()

f1.static_var = 'Shadowing static_var'

f1.printAll()

f2 = Foo('f2')

f2.printAll()

Foo.static_var = 'modified class'

f1.printAll()
f2.printAll()

Output:

self.instance_var = I am f1
self.static_var = every instance has access
Foo.static_var = every instance has access
self.instance_var = I am f1
self.static_var = Shadowing static_var
Foo.static_var = every instance has access
self.instance_var = I am f2
self.static_var = every instance has access
Foo.static_var = every instance has access
self.instance_var = I am f1
self.static_var = Shadowing static_var
Foo.static_var = modified class
self.instance_var = I am f2
self.static_var = modified class
Foo.static_var = modified class

I hope this is helpful to someone

Solution 4

further to S.Lott's reply, class variables get passed to metaclass new method and can be accessed through the dictionary when a metaclass is defined. So, class variables can be accessed even before classes are created and instantiated.

for example:

class meta(type):
    def __new__(cls,name,bases,dicto):
          # two chars missing in original of next line ...
          if dicto['class_var'] == 'A':
             print 'There'
class proxyclass(object):
      class_var = 'A'
      __metaclass__ = meta
      ...
      ...

Solution 5

class User(object):
    email = 'none'
    firstname = 'none'
    lastname = 'none'

    def __init__(self, email=None, firstname=None, lastname=None):
        self.email = email
        self.firstname = firstname
        self.lastname = lastname

    @classmethod
    def print_var(cls, obj):
        print ("obj.email obj.firstname obj.lastname")
        print(obj.email, obj.firstname, obj.lastname)
        print("cls.email cls.firstname cls.lastname")
        print(cls.email, cls.firstname, cls.lastname)

u1 = User(email='abc@xyz', firstname='first', lastname='last')
User.print_var(u1)

In the above code, the User class has 3 global variables, each with value 'none'. u1 is the object created by instantiating this class. The method print_var prints the value of class variables of class User and object variables of object u1. In the output shown below, each of the class variables User.email, User.firstname and User.lastname has value 'none', while the object variables u1.email, u1.firstname and u1.lastname have values 'abc@xyz', 'first' and 'last'.

obj.email obj.firstname obj.lastname
('abc@xyz', 'first', 'last')
cls.email cls.firstname cls.lastname
('none', 'none', 'none')
Share:
172,329

Related videos on Youtube

Teifion
Author by

Teifion

I am a Software Engineer in a UK Car Insurance provider. I mainly work in Python and PHP.

Updated on November 06, 2021

Comments

  • Teifion
    Teifion over 2 years

    Is there any difference at all between these classes besides the name?

    class WithClass ():
        def __init__(self):
            self.value = "Bob"
        def my_func(self):
            print(self.value)
    
    class WithoutClass ():
        value = "Bob"
    
        def my_func(self):
            print(self.value)
    

    Does it make any difference if I use or don't use the __init__ method for declaring the variable value?

    My main worry is that I'll be using it one way, when that'll cause me further problems down the road.

  • Theo Orphanos
    Theo Orphanos over 14 years
    That's not what python does for me. Lists/dicts/etc get shared between all instances if you don't create them in __init__().
  • user1066101
    user1066101 over 14 years
    @too much php: All variables at the class method (irrespective of mutability -- lists and dicts are mutable) are shared. With immutable objects, the sharing isn't interesting. With mutable objects (lists and dicts) the sharing is significant.
  • Teifion
    Teifion over 14 years
    I suspected that might be the case but figured that if I stated my assumptions it might distract from the question itself, cheers for clearing it up :)
  • Ar5hv1r
    Ar5hv1r about 13 years
    I figured this was what was happening, but it was very unclear to me. Thanks for clearing it up.
  • stgeorge
    stgeorge almost 11 years
    I am a Python novice and I do not understand this reply by S.Lott. Would somebody please clarify this a bit for us beginners?
  • Abdelouahab
    Abdelouahab over 9 years
    note that this example works only for new type classes, with old ones, they will have the same result
  • Anwar
    Anwar about 9 years
    What is the analogy of the variables created outside __init__? if those are shared by all instances, are modifying one of them affects all other instances?
  • farmir
    farmir almost 9 years
    @Abdelouahab, is that so? I tried it with old style classes, and got the same result as new style objects. Python 2.7.8
  • silviomoreto
    silviomoreto about 8 years
    No, just will change the new instances declared after the change. The existing instances will still have the old value for the variable
  • Lobotomik
    Lobotomik about 7 years
    This is a bit misleading. A varnamevariable set outside the init does belong to the class, and may be read via self.varname producing the same value for all instances. However, when assigned a value via an instance reference (as in self.varname = X) a new self.varname will be created for that instance only, obscuring the class variable. The class var remains reachable through a class reference (e.g: WithClass.varname). And class vars can also be set from any method by prefacing with the class name (WithClass.myvar = X) rather than an instance reference (self.myvar = X).
  • Pedro
    Pedro about 4 years
    A variable set outside the init __is called: 'Class Variable'. variable set inside the __init is called: 'Instance Variable'.
  • Ali K.
    Ali K. about 4 years
    finding this answer helpful or not !! Try check this youtube.com/…
  • Oskar Hofmann
    Oskar Hofmann almost 3 years
    But if I use L to store an int, I can change the L even for the outside x, without changing the L of the outside y...
  • gowthz
    gowthz over 2 years
    This is the most important answer here