This question already has answers here:
Usage of __slots__?
(14 answers)
Can't set attributes on instance of "object" class
(7 answers)
Closed 7 months ago.
For example, this code is Python:
a = object()
a.b = 3
throws AttributeError: 'object' object has no attribute 'b'
But, this piece of code:
class c(object): pass
a = c()
a.b = 3
is just fine. Why can I assign property b, when class x does not have that property? How can I make my classes have only properties defined?
The object type is a built-in class written in C and doesn't let you add attributes to it. It has been expressly coded to prevent it.
The easiest way to get the same behavior in your own classes is to use the __slots__ attribute to define a list of the exact attributes you want to support. Python will reserve space for just those attributes and not allow any others.
class c(object):
__slots__ = "foo", "bar", "baz"
a = c()
a.foo = 3 # works
a.b = 3 # AttributeError
Of course, there are some caveats with this approach: you can't pickle such objects, and code that expects every object to have a __dict__ attribute will break. A "more Pythonic" way would be to use a custom __setattr__() as shown by another poster. Of course there are plenty of ways around that, and no way around setting __slots__ (aside from subclassing and adding your attributes to the subclass).
In general, this is not something you should actually want to do in Python. If the user of your class wants to store some extra attributes on instances of the class, there's no reason not to let them, and in fact a lot of reasons why you might want to.
You can override the behavior of the __setattr__ magic method like so.
class C(object):
def __setattr__(self, name, value):
allowed_attrs = ('a', 'b', 'c')
if name not in allowed_attrs:
# raise exception
# or do something else
pass
self.__dict__[name] = value
Of course, this will only prevent you from setting attributes like a.b (the dot form). You can still set the attributes using a.__dict__[b] = value. In that case, you should override the __dict__ method too.
Python generally allows you to set any attribute on any object. This is a special case where the object class acts differently. There are also some modules implemented in C that act similarly.
If you want your object to behave like this, you can define a __setattr__(self, name, value) method that explicitly does a raise AttributeError() if you try to set a member that's not on the "approved list" (see http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/389916)
Creating an object instance has no features. Therefore setting attributes on an instance of a the base object type is expressly disabled. You must subclass it to be able to create attributes.
Hint: If you want a simple object to use as something on which to store properties, you can do so by creating an anonymous function with lambda. Functions, being objects, are able to store attributes as well, so this is perfectly legit:
>>> a = lambda: None
>>> a.b = 3
>>> a.b
3
This happens because when you say a.b = 3, it creates a variable in a that represents b. For example,
class a: pass
print a.b
returns AttributeError: class a has no attribute b
However this code,
class a: pass
a.b = 3
print a.b
returns 3 as it sets the value of b in a, to 3.
Related
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.
From what I understand, each instance of a class stores references to the instance's methods.
I thought, in concept, all instances of a class have the same instance methods. If so, both memory savings and logical clarity seem to suggest that instance methods should be stored in the class object rather than the instance object (with the instance object looking them up through the class object; of course, each instance has a reference to its class). Why is this not done?
A secondary question. Why are instance methods not accessible in a way similar to instance attributes, i.e., through __dict__, or through some other system attribute? Is there any way to look at (and perhaps change) the names and the references to instance methods?
EDIT:
Oops, sorry. I was totally wrong. I saw the following Python 2 code, and incorrectly concluded from it that instance methods are stored in the instances. I am not sure what it does, since I don't use Python 2, and new is gone from Python 3.
import new
class X(object):
def f(self):
print 'f'
a = X()
b = X()
def g(self):
print 'g'
# I thought this modified instance method just in a, not in b
X.f = new.instancemethod(g, a, X)
Attribute lookup on objects in Python is non-trivial. But instance methods are certainly not stored on the instance object!
The default behavior for attribute access is to get, set, or delete the attribute from an object’s dictionary. For instance, a.x has a lookup chain starting with a.__dict__['x'], then type(a).__dict__['x'], and continuing through the base classes of type(a) excluding metaclasses.
(docs)
Note that it is possible to store a function on an instance. But that's not an instance method! When the interpreter looks up an attribute and finds that it is (a) a function and (b) on the class object, it automatically wraps it in a bound method object which passes self.
Is there any way to look at (and perhaps change) the names and the references to instance methods?
Well, you can certainly modify the class object after defining it. But I assume what you mean is "can you make the x method of a particular instance do something different?"
This being Python, the answer is "yes": just define a.x to be some new function. Then you will get that function back before looking on the class.
This may cause you a lot of confusion when you're trying to understand the code, though!
From what I understand, each instance of a class stores references to the instance's methods.
I don't know where you got this from, but it's wrong. They don't.
Why are instance methods not accessible in a way similar to instance attributes, i.e., through __dict__, or through some other system attribute?
Well, because they are not stored on the instance.
Is there any way to look at (and perhaps change) the names and the references to instance methods?
Since these references don't exist, you cannot change them. You can of course create any attribute you want by normal assignments, but note that functions stored on the instance are not treated like ordinary methods -- the mechanism that implicitly passes the self parameter does not apply for them.
Incorrect. Instances do not store references to each method.
For example:
class Foo():
def bar(self):
print 'bar'
f = Foo()
def alternate_bar(self):
print 'alternate bar'
f.bar()
Foo.bar = alternate_bar # modifies the class!
f.bar()
prints
bar
alternate bar
This is also why you provide a self to each method you define in a class. Without a reference to self, the method has no idea which instance it is working on.
Another example
class Point:
def __init__(self, xcoord, ycoord):
self.x = xcoord
self.y = ycoord
def draw(self):
print self.x, " ", self.y
p = Point(205.12, 305.21)
#draw the coordinates of the point instance
p.draw()
# now define a new point drawing function vdraw()
def vdraw(q):
print "[",q.x,",",q.y,"]"
#p.draw()
#now reassign the draw() method to vdraw()
Point.draw = vdraw
# now print the coordinates of the point instance
print p.x
print p.y
#now draw the coordinates of the point instance
p.draw()
I am a complete Python novice so my question might seem to be dumb. I've seen there are two ways of assigning values to object attributes in Python:
Using __dict__:
class A(object):
def __init__(self,a,b):
self.__dict__['a'] = a
self.__dict__['b'] = b
Without __dict__:
class A(object):
def __init__(self,a,b):
self.a = a
self.b = b
Can anyone explain where is the difference?
Unless you need set attributes dynamically and bypass descriptors or the .__setattr__() hook, do not assign attributes directly to .__dict__.
Not all instances have a .__dict__ attribute even, not if the class defined a .__slots__ attribute to save memory.
If you do need to set attributes dynamically but don't need to bypass a descriptor or a .__setattr__() hook, you'd use the setattr() function normally.
From the Python documentation:
Both class types (new-style classes) and class objects
(old-style/classic classes) are typically created by class definitions
(see section Class definitions). A class has a namespace implemented
by a dictionary object. Class attribute references are translated to
lookups in this dictionary, e.g., C.x is translated to C.__dict__["x"]
(although for new-style classes in particular there are a number of
hooks which allow for other means of locating attributes).
The much more typical way of assigning a new element to a class is your second example, which allows for a number of customizations (__seattr__, __getattr__, etc.).
Example
class A:
foo = 1
class B:
foo = 2
class C:
foo = 3
class D(A, B, C):
pass
def collect_foo(cls):
import inspect
foos = []
for c in inspect.getmro(cls):
if hasattr(c, 'foo'):
foos.append(c.foo)
return foos
Now collect_foo(D) returns [1, 1, 2, 3] - 1 is doubled as D derives it from A. The question is - how to get unique foos. First thing which came to my mind was checking if property is derived or declared in given class - is it possible? How to do that?
Just check
'foo' in c.__dict__
instead of
hasattr(c, 'foo')
This will only yield True if the attribute is defined in c itself.
I believe this will work... Look to see if it is in the __dict__ attribute of the class. But, be sure you really want to do this first.
Example:
if name in cls.__dict__:
# ... your code here ...
pass
"The thing is there are some attributes which I don't want to be overriden but mixed in and available for derived class"
This is exactly what the namespace mangling in Python does. The attributes that should not be overridden like this should start with two underscores. That way they don't get overridden, but remain unique for each class.
I agree with the accepted answer, but a #classmethod did not match my case...
I found it useful to check the class dict from the context of a base class or mix-in, where I only want to execute some code path if it applies to the derived class, such as if a particular method is overridden.
i.e. (in Python 3.6):
if method_name in self.__class__.__dict__.keys():
# do something
I rationalized it as follows.
self is the instance
__class__ is that instance's actual type
therefore, dict only contains the methods actually overridden in the derived class.
A random class definition:
class ABC:
x = 6
Setting some values, first for the abc instance, later for the static variable:
abc = ABC()
abc.x = 2
ABC.x = 5
and then print the results:
print abc.x
print ABC.x
which prints
2
5
Now, I don't really get what is going on, because if i replace in the class definition x = 6 for "pass", it will just output the same thing. My question is, what is the purpose of defining a variable in the class definition in python if it seems like i can anyone set at any time any variable without doing so?
Also, does python know the difference between instance and static variables? From what I saw, I'd say so.
Warning: the following is an oversimplification; I'm ignoring __new__() and a bunch of other special class methods, and handwaving a lot of details. But this explanation will get you pretty far in Python.
When you create an instance of a class in Python, like calling ABC() in your example:
abc = ABC()
Python creates a new empty object and sets its class to ABC. Then it calls the __init__() if there is one. Finally it returns the object.
When you ask for an attribute of an object, first it looks in the instance. If it doesn't find it, it looks in the instance's class. Then in the base class(es) and so on. If it never finds anybody with the attribute defined, it throws an exception.
When you assign to an attribute of an object, it creates that attribute if the object doesn't already have one. Then it sets the attribute to that value. If the object already had an attribute with that name, it drops the reference to the old value and takes a reference to the new one.
These rules make the behavior you observe easy to predict. After this line:
abc = ABC()
only the ABC object (the class) has an attribute named x. The abc instance doesn't have its own x yet, so if you ask for one you're going to get the value of ABC.x. But then you reassign the attribute x on both the class and the object. And when you subsequently examine those attributes you observe the values you put there are still there.
Now you should be able to predict what this code does:
class ABC:
x = 6
a = ABC()
ABC.xyz = 5
print(ABC.xyz, a.xyz)
Yes: it prints two fives. You might have expected it to throw an AttributeError exception. But Python finds the attribute in the class--even though it was added after the instance was created.
This behavior can really get you in to trouble. One classic beginner mistake in Python:
class ABC:
x = []
a = ABC()
a.x.append(1)
b = ABC()
print(b.x)
That will print [1]. All instances of ABC() are sharing the same list. What you probably wanted was this:
class ABC:
def __init__(self):
self.x = []
a = ABC()
a.x.append(1)
b = ABC()
print(b.x)
That will print an empty list as you expect.
To answer your exact questions:
My question is, what is the purpose of defining a variable in the class definition in python if it seems like i can anyone set at any time any variable without doing so?
I assume this means "why should I assign members inside the class, instead of inside the __init__ method?"
As a practical matter, this means the instances don't have their own copy of the attribute (or at least not yet). This means the instances are smaller; it also means accessing the attribute is slower. It also means the instances all share the same value for that attribute, which in the case of mutable objects may or may not be what you want. Finally, assignments here mean that the value is an attribute of the class, and that's the most straightforward way to set attributes on the class.
As a purely stylistic matter it's shorter code, as you don't have all those instances of self. all over. Beyond that it doesn't make much difference. However, assigning attributes in the __init__ method ensures they are unambiguously instance variables.
I'm not terribly consistent myself. The only thing I'm sure to do is assign all the mutable objects that I don't want shared in the __init__ method.
Also, does python know the difference between instance and static variables? From what I saw, I'd say so.
Python classes don't have class static variables like C++ does. There are only attributes: attributes of the class object, and attributes of the instance object. And if you ask for an attribute, and the instance doesn't have it, you'll get the attribute from the class.
The closest approximation of a class static variable in Python would be a hidden module attribute, like so:
_x = 3
class ABC:
def method(self):
global _x
# ...
It's not part of the class per se. But this is a common Python idiom.
class SomeClass:
x=6 # class variable
def __init__(self):
self.y = 666 # instance variable
There is virtue in declaring a class scoped variable: it serves as default for one. Think of class scoped variable as you would think of "static" variables in some other languages.
Python makes a distinction between the two. The purpose could be multiple, but one example is this:
class token(object):
id = 0
def __init__(self, value):
self.value = value
self.id = token.id
token.id += 1
Here, the class variable token.id is automatically incremented at each new instance, and this instance can take a unique ID at the same time, which will be put in self.id. Both are stored at different places - in the class object, or in the instance object, you can indeed compare that to static and instance variables in some OO languages like C++ or C#.
In that example, if you do:
print token.id
you will see the next ID to be assigned, whereas:
x = token(10)
print x.id
will give the id of that instance.
Everyone can also put other attributes in an instance or in a class, that's right, but that wouldn't be interesting since the class code is not intended to use them. The interest with an exemple as above is that the class code uses them.
A class-level variable (called "static" in other languages) is owned by the class, and shared by all instances of the class.
A instance variable is part of by each distinct instance of the class.
However.
You can add a new instance variable any time you want.
So getting abc.x requires first checking for an instance variable. If there is no instance variable, it will try the class variable.
And setting abc.x will create (or replace) an instance variable.
Every object has a __dict__. The class ABC and its instance, abc, are both objects, and so each has their own separate __dict__:
In [3]: class ABC:
...: x=6
Notice ABC.__dict__ has a 'x' key:
In [4]: ABC.__dict__
Out[4]: {'__doc__': None, '__module__': '__main__', 'x': 6}
In [5]: abc=ABC()
In [6]: abc.__dict__
Out[6]: {}
Notice that if 'x' is not in abc.__dict__, then the __dict__'s of abc's superclass(es) are searched. So abc.x is "inherited" from ABC:
In [14]: abc.x
Out[14]: 6
But if we set abc.x then we are changing abc.__dict__, not ABC.__dict__:
In [7]: abc.x = 2
In [8]: abc.__dict__
Out[8]: {'x': 2}
In [9]: ABC.__dict__
Out[9]: {'__doc__': None, '__module__': '__main__', 'x': 6}
Of course, we can change ABC.__dict__ if we wish:
In [10]: ABC.x = 5
In [11]: ABC.__dict__
Out[11]: {'__doc__': None, '__module__': '__main__', 'x': 5}
The benefit of a "static" or in Python a "class attribute" is that each instance of the class will have access to the same class attribute. This is not true for instance attributes as you may be aware.
Take for example:
class A(object):
b = 1
A.b # => 1
inst = A()
inst2 = A()
inst.b # => 1
inst2.b # => 1
A.b = 5
inst.b # => 5
inst2.b # => 5
As you can see the instance of the class has access to the class attribute which can be set by specifying the class name and then the class attribute.
The tricky part is when you have a class attribute and instance attribute named the same thing. This requires an understanding of what is going on under the hood.
inst.__dict__ # => {}
A.__dict__ # => {..., 'b': 5}
Notice how the instance does not have b as an attribute? Above, when we called inst.b Python actually checks inst.__dict__ for the attribute, if it cannot be found, then it searches A.__dict__ (the class's attributes). Of course, when Python looks up b in the class's attributes it is found and returned.
You can get some confusing output if you then set an instance attribute with the same name.
For example:
inst.b = 10
inst.__dict__ #=> {'b': 10}
A.b # => 5
inst.b # => 10
You can see that the instance of the class now has the b instance attribute and therefore Python returns that value.