< BACKMake Note | BookmarkCONTINUE >
156135250194107072078175030179198180025031194137176049106218111004231203005074078234144246

Built-in Functions for Classes, Instances, and Other Objects

issubclass()

The issubclass() Boolean function determines if one class is a subclass or descendant of another class. It has the following syntax:

						
issubclass(sub, sup)
					

issubclass() returns 1 if the given subclass sub is indeed a subclass of the superclass sup. This function allows for an "improper" subclass, meaning that a class is viewed as a subclass of itself, so the function returns 1 if sub is either the same class as sup or derived from sup. (A "proper" subclass is strictly a derived subclass of a class.)

If we were to implement the issubclass() built-in function ourselves, it may look something like the following:

						
def my_issubclass(sub, sup):
    if sub is sup or sup in sub.__bases__:
        return 1
    for cls in sub.__bases__:
        if my_issubclass(cls, sup):
            return 1
        else:
            return 0
    return 0

					

We first check to see if they are both the same class. Since we allow for improper subclasses, then we would indicate a successful inquiry if both classes are the same. We also return 1 if sup is a parent class of sub. This check is accomplished by looking at the __bases__ attribute of sub.

If both of those tests fail, then we need to start moving up the family tree to see if sup is an ancestor of sub. This is accomplished by checking the parent classes of sub to see if they are subclasses of sup. If that fails, then we check the grandparent classes, and so on, moving up the tree to see if any of those classes are subclasses of sup. This is a depth-first recursive check where all ancestors are checked. If all return a negative result, we return 0 for failure.

isinstance()

The isinstance() Boolean function is useful for determining if an object is an instance of a given class and has the following syntax:

						
isinstance(obj1, obj2)
					

isinstance() returns 1 if obj1 is an instance of class obj2 or is an instance of a subclass of obj2, as indicated in the following examples:

						
>>> class C1: pass
…
>>> class C2: pass
…
>>> c1 = C1()
>>> c2 = C2()
>>> isinstance(c1, C1)
1
>>> isinstance(c2, C1)
0
>>> isinstance(c1, C2)
0
>>> isinstance(c2, C2)
1
>>> isinstance(C2, c2)
Traceback (innermost last):
  File "<stdin>", line 1, in ?
    isinstance(C2, c2)
TypeError: second argument must be a class

					

Note that the second argument should be a class; otherwise, you get a TypeError. The only exception is if the second argument is a type object. This is allowed because you can also use isinstance() to check if an object obj1 is of the type obj2, i.e.,

						
>>> isinstance(4, type(4))
1
>>> isinstance(4, type(''))
0
>>> isinstance('4', type(''))
1

					

If we were to implement the isinstance() built-in function ourselves, it may look something like the following:

						
def my_isinstance(obj1, obj2):
  if obj2 is type(type(0)):       # check if obj2 is type obj
    return type(obj1) is obj2
  if obj1.__class__ is obj2:      # check if obj1 inst of obj2
    return 1
return my_issubclass(obj1.__class__, obj2)

					

isinstance() may appear simpler than issubclass(), but you will notice that we use issubclass(). Without it, we would have to reimplement issubclass(), so in actuality, isinstance() is a bit longer than issubclass().

Our rendition of isinstance() works like this: We first check to see if we are dealing with objects and types by confirming whether obj2 is a type object. If so, then we perform the check and return the result. Otherwise, we are dealing with classes and instances, so the test proceeds to check if instance obj1 is actually a real instance of class obj2. If it is, then we are done. Otherwise, we recursively check to see if the class of which obj1 is an instance is a descendant of obj2. If it is, then we return 1 for yes and 0 otherwise.

Proxy for Missing Functionality

Both is*() built-in functions (issubclass() and isinstance()) are new to Python as of version 1.5. Prior to 1.5, you would have to implement them yourself, as we did above, as well as create your own routine which proxies for the missing functions. While new functions are not always part of Python updates, it is quite possible that due to uncontrollable forces, you are required to use older versions of Python which do not support the new functionality. The solution would be to implement your own solutions and integrate them into your code so that your system at least behaves like a more recent version of the interpreter.

We present one possible solution below, which attempts to import the __builtin__ module (hopefully loading issubclass() and isinstance()), but if not, creates aliases for our homebrewed functions which reference the code we implemented above:

							
if '__builtins__' not in dir() and __import__ in dir():
     __builtins__ = __import__('__builtin__')

if 'issubclass' not in dir(__builtins__):
     issubclass = my_issubclass

if 'isinstance' not in dir(__builtins__):
     isinstance = my_isinstance

						

We will now invoke these functions on the classes and instance we defined in the previous section. Recall that the P* classes are parent classes, the C* classes are child classes, and the GC class is the "grandchild" class.

							
>>> for eachCls in (P1, P2, C1, C2, GC):
…       print "is GC subclass of", eachCls.__name__, '?', \
…               issubclass(GC, eachCls)
…       print "is 'gc' an instance of", eachCls, '?', \
…               isinstance(gc, eachCls)

is GC subclass of P1 ? 1
is 'gc' an instance of __main__.P1 ? 1
is GC subclass of P2 ? 1
is 'gc' an instance of __main__.P2 ? 1
is GC subclass of C1 ? 1
is 'gc' an instance of __main__.C1 ? 1
is GC subclass of C2 ? 1
is 'gc' an instance of __main__.C2 ? 1
is GC subclass of GC ? 1
is 'gc' an instance of __main__.GC ? 1

						

hasattr(), getattr(), setattr(), delattr()

The *attr() functions can work with all kinds of objects, not just classes and instances. However, since they are most often used with those objects, we present them here.

The hasattr(obj, attr) function is Boolean and its only function is to determine whether or not an object has a particular attribute, presumably used as a check before actually trying to access that attribute. The getattr() and setattr() functions retrieve and assign values to object attributes, respectively. getattr() will raise an AttributeError exception if you attempt to read an object that does not have the requested attribute. setattr() will either add a new attribute to the object or replace a pre-existing one. The delattr() function removes an attribute from an object.

Here are some examples using all the *attr() BIFs:

						
>>> class myClass:
…       def __init__(self):
…           self.foo = 100
…
>>> myInst = myClass()
>>> dir(myInst)
['foo']
>>> hasattr(myInst, 'foo')
1
>>> getattr(myInst, 'foo')
100
>>> hasattr(myInst, 'bar')
0
>>> setattr(myInst, 'bar', 'my attr')
>>> dir(myInst)
['bar', 'foo']
>>> getattr(myInst, 'bar')
'my attr'
>>> delattr(myInst, 'foo')
>>> dir(myInst)
['bar']
>>> hasattr(myInst, 'foo')
0

					

dir()

We first experienced dir() in Exercises 2-12, 2-13, and 4-7. In those exercises, we used dir() to give us information about all the attributes of a module. We now know that dir() can be applied to any other objects with attributes—these include classes, class instances, files, lists, complex numbers, and so on. As long as an object has a __dict__ attribute dictionary, and/or the __members__ and __methods__ lists, dir() will work. Built-in types do not have a __dict__ attribute dictionary and rely primarily on __members__ and __methods__ as a convention:

						
>>> dir(3+3j)              # complex number attributes
['conjugate', 'imag', 'real']
>>>
>>> (3+3j).__dict__
Traceback (innermost last):
File "<stdin>", line 1, in ?
AttributeError: __dict__
>>>
>>> (3+3j).__members__
['imag', 'real']
>>>
>>> (3+3j).__methods__
['conjugate']
>>>
>>> f = open('/etc/motd')
>>> dir(f)            # file oject attributes
['close', 'closed', 'fileno', 'flush', 'isatty', 'mode',
'name', 'read', 'readinto', 'readline', 'readlines',
'seek', 'softspace', 'tell', 'truncate', 'write',
'writelines]
>>> f.__dict__
Traceback (innermost last):
  File "<stdin>", line 1, in ?
AttributeError: __dict__
>>> f.__members__
['closed', 'mode', 'name', 'softspace']
>>> f.__methods__
['close', 'fileno', 'flush', 'isatty', 'read',
'readinto', 'readline', 'readlines', 'seek', 'tell',
'truncate', 'write', 'writelines]
>>> f.close()

					

vars()

The vars() built-in function is similar to dir() except that any object given as the argument must have a __dict__ attribute. vars() will return a dictionary of the attributes (keys) and values of the given object based on the values in its __dict__ attribute. If the object provided does not have such an attribute, an TypeError exception is raised. If no object is provided as an argument to vars(), it will display the dictionary of attributes (keys) and the values of the local namespace, i.e., locals(). We present below an example of calling vars() with a class instance:

						
>>> class C:
…        pass

>>> c=C()
>>> c.foo = 100
>>> c.bar = 'Python'
>>> c.__dict__
{'foo': 100, 'bar': 'Python'}
>>> vars(c)
{'foo': 100, 'bar': 'Python'}

					

Table 13.3 summarizes the built-in functions for classes and class instances.

Table 13.3. Built-in Functions for Classes, Instances, and Other Objects

Built-in Function

Description

issubclass(sub, sup)

returns 1 if class sub is a subclass of class sup, 0 otherwise

isinstance(obj1, obj2)

returns 1 if instance obj1 is an instance of class obj2 or is an instance of a subclass of obj2; will also return 1 if obj1 is of type obj2

hasattr(obj, attr)

returns 1 if obj has attribute attr (given as a string)

getattr(obj, attr)

retrieves attribute attr of obj; same as return obj.attr; AttributeError exception raised if attr is not an attribute of obj

setattr(obj, attr, val)

sets attribute attr of obj to value val, overriding any previously-existing attribute value, otherwise, attribute is created; same as obj.attr = val

delattr(obj, attr)

removes attribute attr (given as a string) from obj; same as del obj.attr

dir(obj=None)

returns a list of the attributes of obj; if obj not given, dir() displays local namespace attributes, i.e., locals().keys()

vars(obj=None)

returns a dictionary of the attributes and values of obj; if obj not given, vars() displays local namespace dictionary (attributes and values), i.e., locals()


Last updated on 9/14/2001
Core Python Programming, © 2002 Prentice Hall PTR

< BACKMake Note | BookmarkCONTINUE >

© 2002, O'Reilly & Associates, Inc.