aerain
aerain

Reputation: 1179

Must all Python instance variables be declared in def __init__?

Or can they be declared otherwise?

The code below does not work:

class BinaryNode():
    self.parent = None
    self.left_child = None

Do they need to be declared in __init__?

Upvotes: 14

Views: 18705

Answers (4)

Fouad Boukredine
Fouad Boukredine

Reputation: 1633

Must all Python instance variables be declared in def __init__? Short answer: no. But it really depends on how/where to use them.

Or can they be declared otherwise? Yes they can be declared otherwise (not an instance variable). Since you're referring to variables inside a class, yes you can declare a local variable (for example) inside of it if you don't want to use __init__ constructor function that uses the keyword self.

The code below does not work:

class BinaryNode():
    self.parent = None
    self.left_child = None

What do you mean by not working? if you're referring to how most developers use a class, then you are right, it does not work in the sense that you can not create a class object (it's also called class instance) and then call one of its instance variables assuming they are declared properly (ie: declared INSIDE the init method that plays the role of the constructor method.)

In other words: if you declare a variable outside the constructor method init then it's called a class variable and not an instance variable. To initiate an instance variable, it needs to be inside the init method that will actually construct (instantiate) the class instance (class object) along with its associated instance variables (instance attributes.)

for example:

if you have parent = None instead of self.parent = None you just created a local variable inside your class.

So the word self is there to hold the place for when you call the class instance is called, it's passed-in in lieu of self. Therefor the word self is just there as a parameter to hold a place for passing whatever instance variable we want to call in its place. So the word self is just doing a favor service here.

Similarly , when creating a class object and say you want to create an instance variable, you must use the attribute word self (it does not have to be self but since most python developers use it, using it became a convention and a good practice in python) that will work as a reference (a holder) to complete the work of the constructor function __init__ which will assign the argument value passed-in the class instance (object) created to be the new value of the instance variable copy that belongs to the class instance created.

Now, let's try another scenario to better solidify the concept:

What if we use the __init__ function but not the keyword self? if you create a class object named object_x and then you want to call one of its instance variables named instance_y from the , then you execute the program, it will throw an error saying that the class object created does not have an attribute (instance variable).

It will be just a local variable with whatever value you assigned to it when you defined it.

The error occurs because it doesn't recognize it as one of the instance variables defined inside the class when it's missing the reference word self.

Upvotes: 3

sberry
sberry

Reputation: 132138

They do not have to be declared in __init__, but in order to set an instance variable using self, there needs to be a reference to self, and the place you are defining the variables does not.

However,

class BinaryNode():
    parent = None
    left_child = None

    def run(self):
        self.parent = "Foo"
        print self.parent
        print self.left_child

The output will be

Foo
None

To answer your question in the comment, yes. You can, in my example say:

bn = BinaryNode()
bn.new_variable = "Bar"

Or, as I showed, you can set a class level variable. All new instances of the class will get a copy of the class level variables at instantiation.

Perhaps you are not aware that you can pass arguments to the constructor:

class BinaryNode(object):

    def __init__(self, parent=None, left_child=None):
        self.parent = parent
        self.left_child = left_child



bn = BinaryNode(node_parent, node_to_the_left)

Upvotes: 13

yurisich
yurisich

Reputation: 7119

Also, you can have class level variables, but I call them class constants.

class Connection(object):
    """helps you connect to the server at work"""
    YOUR_IP = '10.0.9.99'

    def __init__(self, username, password):
        self.ip = Connection.YOUR_IP
        self.un = username
        self.pw = password

    #...and so on

Upvotes: 0

yurisich
yurisich

Reputation: 7119

Nope. I love the @property variable for just this thing:

class Data(object):
    """give me some data, and I'll give you more"""
    def __init__(self, some, others):
        self.some   = some
        self.others = others

    @property
    def more(self):
        """you don't instantiate this with __init__, per say..."""
        return zip(self.some, self.others)


>>> mydata = Data([1, 2, 3], ['a', 'b', 'c'])
>>> mydata.more
[(1, 'a'), (2, 'b'), (3, 'c')]

Upvotes: 2

Related Questions