Here is a screenshot from a lecture that I am going through at school:
My question is, if the class data fields are already being defined:
slices=16
temperature=75.0
Do those values (16 and 75.0) also need to be passed to the __init__ method or can you just pass the variables names, because they are already assigned to those values?
Not sure why/if you would need to pass the default values when they are the exact same as what the variables are already set to? so instead of:
def __init__(self, slices=16, temperature=75.0)
Could you just do:
def __init__(self, slices, temperature)
Updated new question
If you removed the initial class-level variables at the top, and are only defining them in the constructor class, are they only scoped to the constructor class? Or are they available throughout the entire class, even though you didn't define them at the very top (class-level)?? Example:
Class Pizza(object):
# no class-level slice or temp variables
def __init__(self, slices=16, temperature=75.0):
self.slices = slices
self.temperature = temperature
Or, because you are defining them as "self.slices", they are by default passed to all of the other methods when you pass (self) into the other methods?
If you use:
def __init__(self, slices, temperature)
Then slices and temperature are parameters that must be specified.
What you can do is create a variable, and then use that as the default for the function parameter.
a = "foo"
def b(c=a):
print(c)
Just keep in mind that if you redefine that variable, it does not affect the default value for the function.
>>> a = "foo"
>>> def b(c=a):
... print(c)
...
>>> b()
foo
>>> a = 42
>>> b()
foo
The class defined in your lecture is dumb (not very dumb, just pointless and misleading, as you've clearly been misled by it). There is zero reason to define class attributes that happen to share the same value as the default arguments to the initializer. The only thing doing that accomplishes is:
You can do Pizza.slices and Pizza.temperature and see that the abstract concept of a pizza (not a specific pizza) somehow has a known number of slices and a known temperature, and
If someone using the class, for whatever reason, does del mypizza.slices, then future access to mypizza.slices will still "work", but will retrieve the value from the class attribute (since the instance attribute was blown away). Sane code should almost never do this.
In all other ways, there is no relationship between the class level attributes and the defaults defined for the __init__ initializer method; the moment __init__ assigns to self.slices and self.temperature, it shadows the class level attributes so they cannot be directly accessed from that instance of the class (without deleting the instance attributes or bypassing the instance to look at the values on the class itself).
So no, you can't do:
def __init__(self, slices, temperature):
self.slices = slices
self.temperatue = temperature
because the arguments named slices and temperature have nothing to do with the class attributes. By removing their defaults, the user of your class is forced to provide their own values, and there is no default that will be provided (they could, I suppose, do Pizza(Pizza.slices, Pizza.temperature), but that's an insane way to handle defaults).
To your updated question, even without the class variables,
class Pizza:
# no class-level slice or temp variables
def __init__(self, slices=16, temperature=75.0):
self.slices = slices
self.temperature = temperature
works just fine. Outside of any methods of the class, slices and temperature won't exist, but any other methods you define on Pizza will be able to access that instance's slice and temperature attributes by looking them up on self, just like __init__ did when it assigned to them (with self.slices or self.temperature), and anyone who creates an instance of Pizza, say, with mypizza = Pizza(12, 140), can do mypizza.slices to see the attribute for the instance they hold.
A note on the class attributes: In normal cases, they're stupid and nonsensical. There is an exception for dataclasses though, where you define them at class level for the express purpose of helping the dataclasses module dynamically generate your code, removing the need to write a __init__ with separate defaults entirely. For example:
from dataclasses import dataclass
#dataclass
class Pizza:
slices: int = 16
temperature: float = 75.0
is a perfectly reasonable way to write the baseline class, and it uses those annotations and defaulted assignments to generate as __init__ for you (along with reasonable default implementations of __repr__ and __eq__, and other special methods if you pass specific arguments to the #dataclass decorator, saving you a ton of boilerplate required for minimal expected class functionality). It does leave the class attributes in place, which is arguably a bad idea, but at least you're getting something useful out of the deal, it's not just repeating the same defaults in two essentially unrelated places, one of which is completely useless.
Related
I have read contructor theory in Python explaining that constructor inheritance is possible in Python. I have inherited int class into my class a. In principle, constructor in child class have highest priority. Why constructor of my child class does not evoke?
class a(int):
def __init__(self,value1,value2):
self.value1=value1
self.value2=value2
obj1=a(2,2)
TypeError: int() can't convert non-string with explicit base
int is an immutable type in Python. That means that is does not use __init__, but __new__.
The difference between __init__ and __new__ is that __init__ is an initializer, while __new__ is a constructor. So, when __init__ is called, your instance has already been created. In order to implement immutable objects, you want the ability to "cancel" creating a new object in some cases. For instance, when int(1) is performed, it would make little sense to create a new instance equal to 1. In stead, the existing instance can simply be returned.
So, in theory, you could do something like this:
class a(int):
def __new__(cls, value1, value2):
self = super().__new__(cls)
self.value1 = value1
self.value2 = value2
return self
The error you are getting is because a(2, 2) calls int.__new__ with two arguments: 2 and 2. The two-argument form of int.__new__ expects the first argument to be a str in a base specified by the second argument.
If you want to experiment with inheritance in Python, you might find it easier to use your own defined classes -- inheritance involving built-in classes can be tricky at times.
One additional detail I wanted to add: in my experience, you usually do not want to replace the initializer or constructor of your parent class. In stead, you probably want to extend it, like I did in my example above using the call to super().__new__. But then again, there might be valid use cases.
I believe that since int is immutable; the __init__ cannot be changed, so a(2, 2) still ends up looking calling like int(2, 2)
What is the difference between class and instance variables in Python?
class Complex:
a = 1
and
class Complex:
def __init__(self):
self.a = 1
Using the call: x = Complex().a in both cases assigns x to 1.
A more in-depth answer about __init__() and self will be appreciated.
When you write a class block, you create class attributes (or class variables). All the names you assign in the class block, including methods you define with def become class attributes.
After a class instance is created, anything with a reference to the instance can create instance attributes on it. Inside methods, the "current" instance is almost always bound to the name self, which is why you are thinking of these as "self variables". Usually in object-oriented design, the code attached to a class is supposed to have control over the attributes of instances of that class, so almost all instance attribute assignment is done inside methods, using the reference to the instance received in the self parameter of the method.
Class attributes are often compared to static variables (or methods) as found in languages like Java, C#, or C++. However, if you want to aim for deeper understanding I would avoid thinking of class attributes as "the same" as static variables. While they are often used for the same purposes, the underlying concept is quite different. More on this in the "advanced" section below the line.
An example!
class SomeClass:
def __init__(self):
self.foo = 'I am an instance attribute called foo'
self.foo_list = []
bar = 'I am a class attribute called bar'
bar_list = []
After executing this block, there is a class SomeClass, with 3 class attributes: __init__, bar, and bar_list.
Then we'll create an instance:
instance = SomeClass()
When this happens, SomeClass's __init__ method is executed, receiving the new instance in its self parameter. This method creates two instance attributes: foo and foo_list. Then this instance is assigned into the instance variable, so it's bound to a thing with those two instance attributes: foo and foo_list.
But:
print instance.bar
gives:
I am a class attribute called bar
How did this happen? When we try to retrieve an attribute through the dot syntax, and the attribute doesn't exist, Python goes through a bunch of steps to try and fulfill your request anyway. The next thing it will try is to look at the class attributes of the class of your instance. In this case, it found an attribute bar in SomeClass, so it returned that.
That's also how method calls work by the way. When you call mylist.append(5), for example, mylist doesn't have an attribute named append. But the class of mylist does, and it's bound to a method object. That method object is returned by the mylist.append bit, and then the (5) bit calls the method with the argument 5.
The way this is useful is that all instances of SomeClass will have access to the same bar attribute. We could create a million instances, but we only need to store that one string in memory, because they can all find it.
But you have to be a bit careful. Have a look at the following operations:
sc1 = SomeClass()
sc1.foo_list.append(1)
sc1.bar_list.append(2)
sc2 = SomeClass()
sc2.foo_list.append(10)
sc2.bar_list.append(20)
print sc1.foo_list
print sc1.bar_list
print sc2.foo_list
print sc2.bar_list
What do you think this prints?
[1]
[2, 20]
[10]
[2, 20]
This is because each instance has its own copy of foo_list, so they were appended to separately. But all instances share access to the same bar_list. So when we did sc1.bar_list.append(2) it affected sc2, even though sc2 didn't exist yet! And likewise sc2.bar_list.append(20) affected the bar_list retrieved through sc1. This is often not what you want.
Advanced study follows. :)
To really grok Python, coming from traditional statically typed OO-languages like Java and C#, you have to learn to rethink classes a little bit.
In Java, a class isn't really a thing in its own right. When you write a class you're more declaring a bunch of things that all instances of that class have in common. At runtime, there's only instances (and static methods/variables, but those are really just global variables and functions in a namespace associated with a class, nothing to do with OO really). Classes are the way you write down in your source code what the instances will be like at runtime; they only "exist" in your source code, not in the running program.
In Python, a class is nothing special. It's an object just like anything else. So "class attributes" are in fact exactly the same thing as "instance attributes"; in reality there's just "attributes". The only reason for drawing a distinction is that we tend to use objects which are classes differently from objects which are not classes. The underlying machinery is all the same. This is why I say it would be a mistake to think of class attributes as static variables from other languages.
But the thing that really makes Python classes different from Java-style classes is that just like any other object each class is an instance of some class!
In Python, most classes are instances of a builtin class called type. It is this class that controls the common behaviour of classes, and makes all the OO stuff the way it does. The default OO way of having instances of classes that have their own attributes, and have common methods/attributes defined by their class, is just a protocol in Python. You can change most aspects of it if you want. If you've ever heard of using a metaclass, all that is is defining a class that is an instance of a different class than type.
The only really "special" thing about classes (aside from all the builtin machinery to make them work they way they do by default), is the class block syntax, to make it easier for you to create instances of type. This:
class Foo(BaseFoo):
def __init__(self, foo):
self.foo = foo
z = 28
is roughly equivalent to the following:
def __init__(self, foo):
self.foo = foo
classdict = {'__init__': __init__, 'z': 28 }
Foo = type('Foo', (BaseFoo,) classdict)
And it will arrange for all the contents of classdict to become attributes of the object that gets created.
So then it becomes almost trivial to see that you can access a class attribute by Class.attribute just as easily as i = Class(); i.attribute. Both i and Class are objects, and objects have attributes. This also makes it easy to understand how you can modify a class after it's been created; just assign its attributes the same way you would with any other object!
In fact, instances have no particular special relationship with the class used to create them. The way Python knows which class to search for attributes that aren't found in the instance is by the hidden __class__ attribute. Which you can read to find out what class this is an instance of, just as with any other attribute: c = some_instance.__class__. Now you have a variable c bound to a class, even though it probably doesn't have the same name as the class. You can use this to access class attributes, or even call it to create more instances of it (even though you don't know what class it is!).
And you can even assign to i.__class__ to change what class it is an instance of! If you do this, nothing in particular happens immediately. It's not earth-shattering. All that it means is that when you look up attributes that don't exist in the instance, Python will go look at the new contents of __class__. Since that includes most methods, and methods usually expect the instance they're operating on to be in certain states, this usually results in errors if you do it at random, and it's very confusing, but it can be done. If you're very careful, the thing you store in __class__ doesn't even have to be a class object; all Python's going to do with it is look up attributes under certain circumstances, so all you need is an object that has the right kind of attributes (some caveats aside where Python does get picky about things being classes or instances of a particular class).
That's probably enough for now. Hopefully (if you've even read this far) I haven't confused you too much. Python is neat when you learn how it works. :)
What you're calling an "instance" variable isn't actually an instance variable; it's a class variable. See the language reference about classes.
In your example, the a appears to be an instance variable because it is immutable. It's nature as a class variable can be seen in the case when you assign a mutable object:
>>> class Complex:
>>> a = []
>>>
>>> b = Complex()
>>> c = Complex()
>>>
>>> # What do they look like?
>>> b.a
[]
>>> c.a
[]
>>>
>>> # Change b...
>>> b.a.append('Hello')
>>> b.a
['Hello']
>>> # What does c look like?
>>> c.a
['Hello']
If you used self, then it would be a true instance variable, and thus each instance would have it's own unique a. An object's __init__ function is called when a new instance is created, and self is a reference to that instance.
Maybe this is more of a style question than a technical one but I have a class with several member variables and I want to have it work so that some of the member variables are initialized when the user first creates an instance of the class (i.e. in the __init__ function) and I want the other member variables to be defined from arguments of member functions that will be called later on. So my question is should I initialize all member variables in the __init__ function (and set the ones that will be defined later on to dummy values) or initialize some in the __init__ function and some in later functions. I realize this might be difficult to understand so here are a couple of examples.
This example has var3 set to 0 initially in the __init__ function, then set to the desired value later on in the my_funct function.
class myClass(object):
def __init__(self,var1,var2):
self.var1=var1
self.var2=var2
self.var3=0
def my_funct(self,var3):
self.var3=var3
and in this example, var3 is not defined at all in the __init__ function
class myClass(object):
def __init__(self,var1,var2):
self.var1=var1
self.var2=var2
def my_funct(self,var3):
self.var3=var3
I don't think either way would make a big difference (maybe a slight difference in memory usage). But I was wondering if one of these is preferred over the other for some reason.
In object-oriented programming it's up to the developer to ensure an object is always in a consistent state after instantiation and after a method finishes. Other than that you're free to develop the class as you wish (keeping in mind certain principles with subclassing / overriding and so on).
A tool such as Pylint will warn when you're setting instance variables outside __init__. It can be argued that setting all instance variables in the __init__ is cleaner but it's not a rule that must be abided by at all times.
I would actually discourage initializing variables you don't always need in __init__ to an arbitrary default value.
I do question your use of OO if this is the case, but I'm sure there is a valid and understandable case where __init__ will not do everything, and the class will want to further modify itself by adding additional attributes with other methods.
The proper way in my opinion to test if a variable was set while running a method that may want to use it would be to use hasattr. This is in the case that this is a valid way to use the method and the test just switches behavior in a sensible way.
Another way would be to try and use it and handle the exception and provide some user friendly information about what the user of your class is doing wrong. This is in the case the method needs the attribute to be set before running.
i.e. Hey man, you did initialize the class, but you need to make sure the z attribute exists by calling the z_init method before running the z_run method.
Another, arguably the more pythonic way, would be to just document how to use the method in the docstring and then let the exception fly when it is used improperly. This is good enough for the first implementation of something and you can then focus on the next task. This is in the same situation as above, the method needs the attribute to be set.
The reason I do not like the idea of initializing variables to arbitrary defaults is this can be confusing (because it is arbitrary) and is line noise.
If the value is not arbitrary and simply a default value that can be changed you should be using a default value in the __init__ method that can be overridden. It can also actually be a valid initial state, which is also not arbitrary and you should set it in the __init__ method.
So the real answer is it depends, and you should probably avoid it and question your use of OO if you are doing this either by adding attributes in other methods or initializing attributes to arbitrary values.
While Simeon Visser is saying to keep your object in a consistent state, he has no basis for what consistency is based on your abstract example. While Pylint warns on this kind of thing, warnings from lint programs are simply so a high level reviewer can be alerted of things that usually indicate code smell. I say high level reviewer because a real reviewer should be reading and understanding all of your code, and thus not really need Pylint.
An example that breaks the rule of thumb:
class Mutant(object):
"""A mutant!"""
def __init__(self):
"""A mutant is born with only 1 eye and 1 mouth"""
self.eyes = 1
self.mouth = 1
self.location = 'Montana'
def roll_to(self, location):
"""If they have limbs, running is less dangerous"""
if hasattr(self, 'limbs'):
print 'Your mutant broke its limbs off!!'
del self.limbs
self.location = location
def run_to(self, location):
"""If they don't have limbs, running is not effective"""
if not hasattr(self, 'limbs'):
print 'Your mutant tries to run but he has no limbs.'
else:
self.location = location
def grow_limbs(self, number_of_limbs):
"""Ah, evolution!"""
assert number_of_limbs > 0, 'Cannot grow 0 or less limbs...'
if hasattr(self, 'limbs'):
self.limbs += number_of_limbs
else:
self.limbs = number_of_limbs
Here is an excerpt from sololearn.com (a free site to learn python)
"Properties provide a way of customizing access to instance attributes.
They are created by putting the property decorator above a method, which means when the instance attribute with the same name as the method is accessed, the method will be called instead.
One common use of a property is to make an attribute read-only."
Example (also from sololearn.com):
class Pizza:
def __init__(self, toppings):
self.toppings = toppings
#property
def pineapple_allowed(self):
return False
pizza = Pizza(["cheese", "tomato"])
print(pizza.pineapple_allowed)
pizza.pineapple_allowed = True
Result:
>>>
False
AttributeError: can't set attribute
>>>
If var3 depends on var1 and var2 you could do
class myClass:
def __init__(self,var1,var2):
self.var1=var1
self.var2=var2
#property
def var3(self):
return(self.var1+self.var2) #var3 depends on var1 and var2
m1=myClass(1,2)
print(m1.var3) # var3 is 3
var3 can also be set to whatever you want using a setter function. Note that you can avoid setting var3 to an arbitrary value by using None.
class myClass2(object):
def __init__(self,var1,var2):
self.var1=var1
self.var2=var2
self._var3=None # None or an initial value that makes sense
#property
def var3(self):
return(self._var3)
#var3.setter
def var3(self,value):
self._var3=value
m2=myClass(1,2)
print(m2.var3) # var3 is none
print(m2.var3(10)) # var3 is set to 10
I have a class sysprops in which I'd like to have a number of constants. However, I'd like to pull the values for those constants from the database, so I'd like some sort of hook any time one of these class constants are accessed (something like the getattribute method for instance variables).
class sysprops(object):
SOME_CONSTANT = 'SOME_VALUE'
sysprops.SOME_CONSTANT # this statement would not return 'SOME_VALUE' but instead a dynamic value pulled from the database.
Although I think it is a very bad idea to do this, it is possible:
class GetAttributeMetaClass(type):
def __getattribute__(self, key):
print 'Getting attribute', key
class sysprops(object):
__metaclass__ = GetAttributeMetaClass
While the other two answers have a valid method. I like to take the route of 'least-magic'.
You can do something similar to the metaclass approach without actually using them. Simply by using a decorator.
def instancer(cls):
return cls()
#instancer
class SysProps(object):
def __getattribute__(self, key):
return key # dummy
This will create an instance of SysProps and then assign it back to the SysProps name. Effectively shadowing the actual class definition and allowing a constant instance.
Since decorators are more common in Python I find this way easier to grasp for other people that have to read your code.
sysprops.SOME_CONSTANT can be the return value of a function if SOME_CONSTANT were a property defined on type(sysprops).
In other words, what you are talking about is commonly done if sysprops were an instance instead of a class.
But here is the kicker -- classes are instances of metaclasses. So everything you know about controlling the behavior of instances through the use of classes applies equally well to controlling the behavior of classes through the use of metaclasses.
Usually the metaclass is type, but you are free to define other metaclasses by subclassing type. If you place a property SOME_CONSTANT in the metaclass, then the instance of that metaclass, e.g. sysprops will have the desired behavior when Python evaluates sysprops.SOME_CONSTANT.
class MetaSysProps(type):
#property
def SOME_CONSTANT(cls):
return 'SOME_VALUE'
class SysProps(object):
__metaclass__ = MetaSysProps
print(SysProps.SOME_CONSTANT)
yields
SOME_VALUE
When I write class in python, most of the time, I am eager to set variables I use, as properties of the object. Is there any rule or general guidelines about which variables should be used as class/instance attribute and which should not?
for example:
class simple(object):
def __init(self):
a=2
b=3
return a*b
class simple(object):
def __init(self):
self.a=2
self.b=3
return a*b
While I completely understand the attributes should be a property of the object. This is simple to understand when the class declaration is simple but as the program goes longer and longer and there are many places where the data exchange between various modules should be done, I get confused on where I should use a/b or self.a/self.b. Is there any guidelines for this?
Where you use self.a you are creating a property, so this can be accessed from outside the class and persists beyond that function. These should be used for storing data about the object.
Where you use a it is a local variable, and only lasts while in the scope of that function, so should be used where you are only using it within the function (as in this case).
Note that __init is misleading, as it looks like __init__ - but isn't the constructor. If you intended them to be the constructor, then it makes no sense to return a value (as the new object is what is returned).
class Person(object):
def __init__(self, name):
# Introduce all instance variables on __init__
self.name = name
self.another = None
def get_name(self):
# get_name has access to the `instance` variable 'name'
return self.name
So if you want a variable to be available on more than one method, make
it an instance variable.
Notice my comment on introducing all instance vars on __init__.
Although the example below is valid python don't do it.
class Person(object):
def __init__(self):
self.a = 0
def foo(self):
self.b = 1 # Whoa, introduced new instance variable
Instead initialize all your instance variables on __init__ and set
them to None if no other value is appropriate for them.
I try to imagine what I want the API of my class to look like prior to implementing it. I think to myself, If I didn't write this class, would I want to read the documentation about what this particular variable does? If reading that documentation would simply waste my time, then it should probably be a local variable.
Occasionally, you need to preserve some information, but you wouldn't necessarily want that to be part of the API, which is when you use the convention of appending an underscore. e.g. self._some_data_that_is_not_part_of_the_api.
The self parameter refers to the object itself. So if you need to use on of the class attributes outside of the class you would it call it as the name of class instance and the attribute name. I don't think there is any guideline on when to use self, it all depends on your need. When you are building a class you should try to think about what you will use the variables you creating for. If you know for sure that you will need that specific attribute in the program you are importing your class, then add self.