Giving an object full list capability

_getitem_is one of many Python special function attributes that may be defined in a class, to permit instances of that class to display special behavior. To see how this can be carried further, effectively integrating new abilities into Python in a seamless manner, we'll look at another, more comprehensive example.

When lists are used, it's common that any particular list will contain elements of only one type such as a list of strings or a list of numbers. Some languages, such as C++, have the ability to enforce this. In large programs, this ability to declare a list as containing a certain type of element can help you track down errors. An attempt to add an element of the wrong type to a typed list will result in an error message, potentially identifying a problem at an earlier stage of program development than would otherwise be the case.

Python doesn't have typed lists built in, and most Python coders don't miss them; but if you're concerned about enforcing the homogeneity of a list, special method attributes make it easy to create a class that behaves like a typed list. Here's the beginning of such a class (which makes extensive use of the Python built-in type and isin-stance functions, to check the type of objects):

class TypedList:

def _init_(self, example_element, initial_list=[]):

self.type = type(example_element) if not isinstance(initial_list, list):

raise TypeError("Second argument of TypedList must " "be a list.") for element in initial_list:

if not isinstance(element, self.type):

raise TypeError("Attempted to add an element of " "incorrect type to a typed list.") self.elements = initial_list[:]

The example_element argument defines the type this list can contain by providing an example of the type of element O.

The TypedList class, as defined here, gives us the ability to make a call of the form x = TypedList('Hello', ["List", "of", "strings"])

The first argument, 'Hello', isn't incorporated into the resulting data structure at all. It's used as an example of the type of element the list must contain (strings, in this case). The second argument is an optional list that can be used to give an initial list of values. The_init_function for the TypedList class checks that any list elements passed in when a TypedList instance is created are of the same type as the example value given. If there are any type mismatches, an exception is raised.

This version of the TypedList class can't be used as a list, because it doesn't respond to the standard methods for setting or accessing list elements. To fix this, we need to define the _setitem_ and _getitem__special method attributes. The

_setitem_method will be called automatically by Python anytime a statement of the form TypedListlnstance [i] = value is executed, and the__getitem_method

will be called anytime the expression TypedListInstance[i] is evaluated to return the value in the ┬┐th slot of TypedListInstance. Here is the next version of the TypedList class. Because we'll be type-checking a lot of new elements, we've abstracted this function out into the new private method __check:

class TypedList:

def _init_(self, example_element, initial_list=[]):

self.type = type(example_element) if not isinstance(initial_list, list):

raise TypeError("Second argument of TypedList must " "be a list.") for element in initial_list:

self._check(element)

self.elements = initial_list[:]

def _check(self, element):

if type(element) != self.type:

raise TypeError("Attempted to add an element of " "incorrect type to a typed list.")

self._check(element)

self.elements[i] = element def _getitem_(self, i):

return self.elements[i]

Now, instances of the TypedList class look more like lists. For example, the following code is valid:

>>> x = TypedList("", 5 * [""])

Hello There

The accesses of elements of x in the print statement are handled by__getitem__, which passes them down to the list instance stored in the TypedList object. The assignments to x[2] and x[3] are handled by_setitem_, which checks that the element being assigned into the list is of the appropriate type and then performs the assignment on the list contained in self.elements. The last line uses_getitem_to unpack the first four items in x and then pack them into the variables a, b, c, d, and e, respectively.

The calls to_getitem__and_setitem_are made automatically by Python.

Completion of the TypedList class, so that TypedList objects behave in all respects like list objects, requires more code. The special method attributes

_setitem_ and _getitem_ should be defined so that TypedList instances can handle slice notation as well as single item access. __add__ should be defined so that list addition (concatenation) can be performed, and __mul_should be defined so that list multiplication can be performed._len__should be defined so that calls of len(TypedListInstance) are evaluated correctly.__delitem_should be defined so that the TypedList class can handle del statements correctly. Also, an append method should be defined so that elements can be appended to TypedList instances using the standard list-style append, and similarly for an insert method.

Was this article helpful?

0 0

Post a comment