Reputation: 180
Sorry for posting such strange question, usually when I am confused I just "go with it" until I have an epiphany, and later sort it out, but calling def __init__(self):
inside my class seems totally redundant and seems that leaving it out works just as well:
class Pet(object):
type_of_pet = ""
number_of_legs = 0
name = ""
Lets me create:
fred = pet()
fred.type_of_pet = "alligator"
Just the same as if I were to change the class to:
class Pet(object):
def __init__(self):
type_of_pet = ""
alice = Pet()
alice.type_of_pet = "Pterodactyl"
I'm just not getting why I need __init__
and the other threads on here were not as clear as I had hoped. Is there anything I can do to make this "click"?
Upvotes: 2
Views: 2294
Reputation: 184081
You're asking why you need __init__()
when you can just assign attributes on the class after it's instantiated.
And the answer is, so you can pass the attribute values when instantiating the object, like you're supposed to. This doesn't just save you typing; assigning attributes on the class after instantiation is prone to error: what if you accidentally assigned to number_off_legs
instead of number_of_legs
? This is not itself an error because attributes may be named anything, but it will cause other code (that expects number_of_legs
) to fail or, in your case, to get the wrong data (since the default value on the class would be used at this point). Also, if you need to change an attribute name, that name is all over your code so you'd need to change it in a lot of places.
So to avoid these headaches, you want to write a little function that creates the object and then assigns the attributes on it, and performs any other necessary initialization (opening files, creating subordinate objects, and so on) before giving the object back to you. That's your __init__()
method and Python helpfully attaches it to your class so that you can instantiate the object and pass in the attribute values all at once. It doesn't seem very useful when you're just storing some data, but when your classes get more complicated you will find it very convenient.
Upvotes: 1
Reputation: 37319
__init__
is called on each instance of your class immediately after creating it. It's the correct place to do instance-level initialization.
Your type_of_pet
and other attributes defined in your first example are class-level information. That form declares that the Pet
class itself has a type_of_pet
value, and that value exists at the same level as, say, any methods you might define.
When you check an instance for a name, it will get the value assigned to that instance if there is one, or go to the class level if there isn't. So this:
fred = Pet()
print fred.type_of_pet
actually checks type_of_pet
on the class itself.
Assignment will modify only the object you actually call it on, so this sets a value at the instance level:
fred.type_of_pet = 'alligator'
That makes no change to the class, just puts a value for the name type_of_pet
into the fred
instance. Therefore, it's common to use class-level definitions as defaults for instances.
But where this will get you in trouble is with mutable types like list. This will not do what you expect:
class Pet:
vaccinations = []
fido = Pet()
fido.vaccinations.append('rabies')
Because fido.vaccinations
ends up being a reference to the single list defined at the class level. Instead, you'd use __init__
to give each pet its own independent list.
Personally, I'm increasingly of the belief that using class-level attributes as defaults for nonmutable types creates more confusion than it's worth, and should be saved only for things that truly should be tracked at the class level rather than per instance. But that's opinion.
Upvotes: 2
Reputation: 64308
When you define the members inside the class directly, those members become part of the class itself, not part of the instances of the class. You can still access them through the instances, but each instance doesn't have its own.
Upvotes: 0
Reputation: 8376
__init__
is a kind of constructor, when a instance of a class is created, python calls__init__()
during the instantiation to define additional behavior that should occur when a class is instantiated, basically setting up some beginning values for that object or running a routine required on instantiation.
You could for example change your Pet class to:
class Pet(object):
def __init__(self, type_of_pet):
self.type_of_pet = type_of_pet
And make a new instance with:
alice = Pet("Pterodactyl")
If you initialize your class variables outside of the __init__
function, every instance will share that values. This is usefull for static classes, but I don't think you want that behaviour on "normal" classes.
Btw, you cannot use type_of_pet=""
in __init__
, it has to be self.type_of_pet=""
.
Upvotes: 1
Reputation: 280207
Putting assignment statements in a class definition doesn't declare instance attributes; it sets class attributes. If you do that, all pets will share the same name
, type_of_pet
, and number_of_legs
.
__init__
is, among other things, used to set instance attributes:
def __init__(self, type_of_pet, name, number_of_legs):
self.type_of_pet = type_of_pet
self.name = name
self.number_of_legs = number_of_legs
This will set attributes on the instance, rather than the class, so each object will have its own name, type, and leg count.
Upvotes: 6