Differences between data attributes and method attributes
An attribute is a variable that is looked up on another object using dot syntax: obj.attribute
. The way Python is designed, attribute lookups can do a variety of things, and that variety can sometimes lead to bugs if you don't really understand what is happening (this is what the documentation you linked to warns about).
The most basic issue is that an attribute lookup can find either a value stored in the object's instance dictionary, or it can find something from the object's class (or a base class, if there's inheritance going on). Methods are functions stored in the class, but you usually use them by looking them up on an instance (which "binds" the method, inserting the object as the first arguemnt when the method is called).
The exact sequence of what is checked when is a bit complicated (I described the full process in an answer to another question), but at the most basic level, instance attributes usually take precedence over class attribute.
If an instance attribute and a class attribute with the same name both exist, usually only the instance attribute will be accessible. This can be very confusing if it is unintended.
Consider the following code:
class Foo(object):
def __init__(self, lst):
self.lst = lst
def sum(self):
self.sum = sum(self.lst)
return self.sum
f = Foo([1,2,3])
print(f.sum())
print(f.sum())
At the bottom of this code, we make two identical calls. The first works just fine, but the second will raise an exception.
This is because the first time we look up f.sum
we find a method in the Foo
class. We can call the method with no problems. The trouble comes from the fact that the sum
method assigns the result of its calculation (the sum of the elements in self.lst
) to an instance attribute also named sum
. This hides the sum
method from view.
When second f.sum()
call looks up f.sum
, it finds the instance attribute, containing the integer 6
, rather than the expected method. An integer is not callable, so we get an exception.
The solution, of course, is not to use the same name for the method and attribute. The code above is a pretty trivial example. The bugs caused by this sort of thing in more complex code can be much more difficult to figure out.
If you're writing code that adds attributes to objects you don't know much about, you should be careful to avoid common names. If you're writing a mixin class, consider using two leading underscores in the attribute names to trigger Python's name mangling, which is designed for exactly this sort of situation.
Addendum: It's also possible that the distinction the documentation is trying to make is between data and non-data descriptors. Methods are the most common kind of non-data descriptor, so it might make a degree of sense to call them "method attributes" (especially in contrast to "data attributes" which would be the corresponding name for data descriptors), though I'm not aware of that language being used more widely. The important difference between the two kinds of descriptors is that data descriptors (like property
) get processed before the instance dictionary is checked for an ordinary instance variable. As discussed above, non-data descriptors like methods get processed only after the instance dictionary is checked, so they can be shadowed by data stored on the instance.
An attribute is any thing for the lack of a better word that is bound to an object, for example:
class Dog:
def __init__(self):
self.name = "Rufus"
def bark(self):
print "Woof Woof!"
In this case the data attribute is the name, which is simply a value that is bound to the instance of the Dog. As for a method attribute, one answer would be the bark method, as it's not so much a value as it is an action. It's just as it is in English. A data attribute is exactly as it sounds; it's data, it is simply a property. A method is a procedure, an action, and this is exactly what a method attribute is.
An attribute is basically anything that you can do instance.attribute_name
with. For instance in:
class Hello(object):
def __init__(self, word):
self.word = word
def greet(self):
print "Hello: "+self.word
__init__
, greet
and word
would all be attributes. I would guess that a method is anything that is declared with def at the class scope (as opposed to doing self.func = lambda x:x*x for instance). In this case you get into bound vs unbound methods and the like. The important part being that for a member attribute when you do instance.method_name
you get back a bound method, which when you call it will call the original method with the instance as the first argument.
Also, after reading some of that section their wording is somewhat confusing/erroneous. For instance they say "Data attributes override method attributes with the same name", which as far as I know would be better put as instance attribute override class attributes with the same name. From the example I gave if we expanded this to:
class Hello(object):
greeting = "Hello: "
def __init__(self, word):
self.word = word
def greet(self):
print self.greeting+self.word
Then we could do:
>>> a = Hello("world")
>>> a.greeting = "Goodbye "
>>> a.greet()
"Goodbye world"
This due to the fact that we put an instance attribute of greeting over the class attribute of greeting. Since methods defined in the class (the usual way) are class attributes they will be overridden by any instance attributes (data or otherwise).