Section 13.4. Class Attributes


13.4. Class Attributes

What is an attribute? An attribute is a data or functional element that belongs to another object and is accessed via the familiar dotted-attribute notation. Some Python types such as complex numbers have data attributes (real and imag), while others such as lists and dictionaries have methods (functional attributes).

One interesting side note about attributes is that when you are accessing an attribute, it is also an object and may have attributes of its own which you can then access, leading to a chain of attributes, i.e., myThing.subThing.subSubThing, etc. Some familiar examples are:

  • sys.stdout.write('foo')

  • print myModule.myClass.__doc__

  • myList.extend(map(upper, open('x').readlines()))

Class attributes are tied only to the classes in which they are defined, and since instance objects are the most commonly used objects in everyday OOP, instance data attributes are the primary data attributes you will be using. Class data attributes are useful only when a more "static" data type is required which is independent of any instances, hence the reason we are making the next section advanced, optional reading. (If you are unfamiliar with static, it just means a value that hangs around a function for each call, or a piece of data in a class that is the same across all instances. More about static data in the next subsection.)

In the succeeding subsection, we will briefly describe how methods in Python are implemented and invoked. In general, all methods in Python have the same restriction: they require an instance before they can be called.

13.4.1. Class Data Attributes

Data attributes are simply variables of the class we are defining. They can be used like any other variable in that they are set when the class is created and can be updated either by methods within the class or elsewhere in the main part of the program.

Such attributes are better known to OO programmers as static members, class variables, or static data. They represent data that is tied to the class object they belong to and are independent of any class instances. If you are a Java or C++ programmer, this type of data is the same as placing the static keyword in front of a variable declaration.

Static members are generally used only to track values associated with classes. In most circumstances, you would be using instance attributes rather than class attributes. We will compare the differences between class and instance attributes when we formally introduce instances.

Here is an example of using a class data attribute (foo):

    >>> class C(object):     ...     foo = 100     >>> print C.foo     100     >>> C.foo = C.foo + 1     >>> print C.foo     101


Note that nowhere in the code above do you see any references to class instances.

13.4.2. Methods

A method, such as the myNoActionMethod method of the MyClass class in the example below, is simply a function defined as part of a class definition (thus making methods class attributes). This means that myNoActionMethod applies only to objects (instances) of MyClass type. Note how myNoActionMethod is tied to its instance because invocation requires both names in the dotted attribute notation:

>>> class MyClass(object):         def myNoActionMethod(self):             pass >>> mc = MyClass() >>> mc.myNoActionMethod()


Any call to myNoActionMethod by itself as a function fails:

    >>> myNoActionMethod()     Traceback (innermost last):       File "<stdin>", line 1, in ?         myNoActionMethod()     NameError: myNoActionMethod


A NameError exception is raised because there is no such function in the global namespace. The point is to show you that myNoActionMethod is a method, meaning that it belongs to the class and is not a name in the global namespace. If myNoActionMethod was defined as a function at the top-level, then our call would have succeeded.

We show you below that even calling the method with the class object fails.

   >>> MyClass.myNoActionMethod()    Traceback (innermost last):      File "<stdin>", line 1, in ?        MyClass.myNoActionMethod()    TypeError: unbound method must be called with class    instance 1st argument


This TypeError exception may seem perplexing at first because you know that the method is an attribute of the class and so are wondering why there is a failure. We will explain this next.

Binding (Bound and Unbound Methods)

In keeping with OOP tradition, Python imposes the restriction that methods cannot be invoked without instances. An instance must be used to perform method calls. This restriction describes Python's concept of binding, where methods must be bound (to an instance) in order to be invoked directly. Unbound methods may also be called, but an instance object must be provided explicitly in order for the invocation to succeed. However, regardless of binding, methods are inherently attributes of the class they are defined in, even if they are almost always invoked via an instance. We will further explore bound and unbound methods later in Section 13.7.

13.4.3. Determining Class Attributes

There are two ways to determine what attributes a class has. The simplest way is to use the dir() built-in function. An alternative is to access the class dictionary attribute __dict__, one of a number of special attributes that is common to all classes. Let us take a look at an example:

    >>> class MyClass(object):     ...     'MyClass class definition'     ...   myVersion = '1.1'            # static data     ... def showMyVersion(self):     # method     ...          print MyClass.myVersion     ...


Using the class defined above, let us use dir() and the special class attribute __dict__ to see this class's attributes:

    >>> dir(MyClass)     ['__class__', '__delattr__', '__dict__', '__doc__',     '__getattribute__', '__hash__', '__init__', '__module__',     '__new__', '__reduce__', '__reduce_ex__', '__repr__',     '__setattr__', '__str__', '__weakref__', 'myVersion',     'showMyVersion']     >>> MyClass.__dict__     <dictproxy object at 0x62090>     >>> print MyClass.__dict__     {'showMyVersion': <function showMyVersion at 0x59370>,     '__dict__': <attribute '__dict__' of 'MyClass' objects>,     'myVersion': '1.1', '__weakref__': <attribute     '__weakref__' of 'MyClass' objects>, '__doc__':     'MyClass class definition'}


There are a few more attributes added for new-style classes as well as a more robust dir() function. Just for comparison, here is what you would see for classic classes:

    >>> dir(MyClass)     ['__doc__', '__module__', 'showMyVersion', 'myVersion']     >>>     >>> MyClass.__dict__     {'__doc__': None, 'myVersion': 1, 'showMyVersion':     <function showMyVersion at 950ed0>, '__module__':     '__main__'}


As you can tell, dir() returns a list of (just the) names of an object's attributes while __dict__ is a dictionary whose attribute names are the keys and whose values are the data values of the corresponding attribute objects.

The output also reveals two familiar attributes of our class MyClass, showMyVersion and myVersion, as well as a couple of new ones. These attributes, __doc__ and __module__, are special class attributes that all classes have (in addition to __dict__). The vars() built-in function returns the contents of a class's __dict__ attribute when passed the class object as its argument.

13.4.4. Special Class Attributes

For any class C, Table 13.1 represents a list of all the special attributes of C:

Table 13.1. Special Class Attributes

C.__name__

String name of class C

C.__doc__

Documentation string for class C

C.__bases__

Tuple of class C's parent classes

C.__dict__

Attributes of C

C.__module__

Module where C is defined (new in 1.5)

C.__class__

Class of which C is an instance (new-style classes only)


Using the class MyClass we just defined above, we have the following:

    >>> MyClass.__name__     'MyClass'     >>> MyClass.__doc__     'MyClass class definition'     >>> MyClass.__bases__     (<type 'object'>,)     >>> print MyClass.__dict__     {'__doc__': None, 'myVersion': 1, 'showMyVersion':     <function showMyVersion at 950ed0>, '__module__': '__main__'}     >>> MyClass.__module__     '__main__'     >>> MyClass.__class__     <type 'type'>


__name__ is the string name for a given class. This may come in handy in cases where a string is desired rather than a class object. Even some built-in types have this attribute, and we will use one of them to showcase the usefulness of the __name__ string.

The type object is an example of one built-in type that has a __name__ attribute. Recall that type() returns a type object when invoked. There may be cases where we just want the string indicating the type rather than an object. We can use the __name__ attribute of the type object to obtain the string name. Here is an example:

    >>> stype = type('What is your quest?')     >>> stype                          # stype is a type object     <type 'string'>     >>> stype.__name__                 # get type as a string     'string'     >>>     >>> type(3.14159265)               # also a type object     <type 'float'>     >>> type(3.14159265).__name__      # get type as a string     'float'


__doc__ is the documentation string for the class, similar to the documentation string for functions and modules, and must be the first unassigned string succeeding the header line. The documentation string is not inherited by derived classes, an indication that they must contain their own documentation strings.

__bases__ deals with inheritance, which we will cover later in this chapter; it contains a tuple that consists of a class's parent classes.

The aforementioned __dict__ attribute consists of a dictionary containing the data attributes of a class. When accessing a class attribute, this dictionary is searched for the attribute in question. If it is not found in __dict__, the hunt continues in the dictionary of base classes, in "depth-first search" order. The set of base classes is searched in sequential order, left-to-right in the same order as they are defined as parent classes in a class declaration. Modification of a class attribute affects only the current class's dictionary; no base class __dict__ attributes are ever modified.

Python supports class inheritance across modules. To better clarify a class's description, the __module__ was introduced in version 1.5 so that a class name is fully qualified with its module. We present the following example:

    >>> class C(object):     ...     pass     ...     >>> C     <class __main__.C at 0x53f90>     >>> C.__module__     '__main__'


The fully qualified name of class C is "__main__.C", i.e., source_ module.class_name. If class C was located in an imported module, such as mymod, we would see the following:

    >>> from mymod import C     >>> C     <class mymod.C at 0x53ea0>     >>> C.__module__     'mymod'


In previous versions of Python without the special attribute __module__, it was much more difficult to ascertain the location of a class simply because classes did not use their fully qualified names.

Finally, because of the unification of types and classes, when you access the __class__ attribute of any class, you will find that it is indeed an instance of a type object. In other words, a class is a type now! Because classic classes do not share in this equality (a classic class is a class object, and a type is a type object), this attribute is undefined for those objects.



Core Python Programming
Core Python Programming (2nd Edition)
ISBN: 0132269937
EAN: 2147483647
Year: 2004
Pages: 334
Authors: Wesley J Chun

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net