Section 13.5. Instances


13.5. Instances

Whereas a class is a data structure definition type, an instance is a declaration of a variable of that type. In other words, instances are classes brought to life. Once a blueprint is provided, the next step to bring them to fruition. Instances are the objects that are used primarily during execution, and the types of all instances are the class from which they were instantiated. Prior to Python 2.2, instances were "instance types," regardless of which class they came from.

13.5.1. Instantiation: Creating Instances by Invoking Class Object

Many other OO languages provide a new keyword with which to create an instance of a class. Python's approach is much simpler. Once a class has been defined, creating an instance is no more difficult than calling a functionliterally. Instantiation is realized with use of the function operator, as in the following example:

    >>> class MyClass(object):   # define class     ...     pass     >>> mc = MyClass()           # instantiate class


As you can see, creating instance mc of class MyClass consists of "calling" the class: MyClass(). The returned object is an instance of the class you called. When you "call" a class using the functional notation, the interpreter instantiates the object, and calls the closest thing Python has to a constructor (if you have written one [see the next section]) to perform any final customization such as setting instance attributes, and finally returns the instance to you.

Core Note: Classes and instances before and after Python 2.2

Classes and types were unified in 2.2, making Python behave more like other object-oriented languages. Instances of any class or type are objects of those types. For example, if you ask Python to tell you, it will say that an instance mc of the MyClass class is an instance of the MyClass class. Redundant yes, but the interpreter will not lie. Likewise, it will tell you that 0 is an instance of the integer type:

    >>> mc = MyClass()     >>> type(mc)     <class '__main__.MyClass'>     >>> type(0)     <type 'int'>


But if you look carefully and compare MyClass with int, you will find that both are indeed types:

    >>> type(MyClass)     <type 'type'>     >>> type(int)     <type 'type'>


In contrast for those of you using classic classes and Python versions earlier than 2.2, classes are class objects and instances are instance objects. There is no further relationship between the two object types other than an instance's __class__ attribute refers to the class from which it was instantiated. Redefining MyClass as a classic class and running the same calls in Python 2.1 (note that int() has not been turned into a factory function yet... it was still only a regular built-in function):

    >>> type(mc)     <type 'instance'>     >>> type(0)     <type 'int'>     >>>     >>> type(MyClass)     <type 'class'>     >>> type(int)     <type 'builtin_function_or_method'>


To avoid any confusion, just keep in mind that when you define a class, you are not creating a new type, just a new class object; and for 2.2 and after, when you define a (new-style) class you are creating a new type.


13.5.2. __init__() "Constructor" Method

When the class is invoked, the first step in the instantiation process is to create the instance object. Once the object is available, Python checks if an __init__() method has been implemented. By default, no special actions are enacted on the instance without the definition of (or the overriding) of the special method __init__(). Any special action desired requires the programmer to implement __init__(), overriding its default behavior. If __init__() has not been implemented, the object is then returned and the instantiation process is complete.

However, if __init__() has been implemented, then that special method is invoked and the instance object passed in as the first argument (self), just like a standard method call. Any arguments passed to the class invocation call are passed on to __init__(). You can practically envision the call to create the instance as a call to the constructor.

In summary, (a) you do not call new to create an instance, and you do not define a constructor: Python creates the object for you; and (b) __init__(), is simply the first method that is called after the interpreter creates an instance for you in case you want to prep the object a little bit more before putting it to use.

__init__() is one of many special methods that can be defined for classes. Some of these special methods are predefined with inaction as their default behavior, such as __init__(), and must be overridden for customization while others should be implemented on an as-needed basis. We will cover many more of these special methods throughout this chapter. You will find use of __init__() everywhere, so we will not present an example here.

13.5.3. __new__() "Constructor" Method

The __new__() special method bears a much closer resemblance to a real constructor than __init__(). With the unification of types and classes in 2.2, Python users now have the ability to subclass built-in types, and so there needed to be a way to instantiate immutable objects, e.g., subclassing strings, numbers, etc.

In such cases, the interpreter calls __new__(), a static method, with the class and passing in the arguments made in the class instantiation call. It is the responsibility of __new__() to call a superclass __new__() to create the object (delegating upward).

The reason why we say that __new__() is more like a constructor than __init__() is that it has to return a valid instance so that the interpreter can then call __init__() with that instance as self. Calling a superclass __new__() to create the object is just like using a new keyword to create an object in other languages.

__new__() and __init__() are both passed the (same) arguments as in the class creation call. For an example of using __new__(), see Section 13.11.3.

13.5.4. __del__() "Destructor" Method

Likewise, there is an equivalent destructor special method called __del__(). However, due to the way Python manages garbage collection of objects (by reference counting), this function is not executed until all references to an instance object have been removed. Destructors in Python are methods that provide special processing before instances are deallocated and are not commonly implemented since instances are seldom deallocated explicitly. If you do override __del__(), be sure to call any parent class __del__() first so those pieces can be adequately deallocated.

Example

In the following example, we create (and override) both the __init__() and __del__() constructor and destructor functions, respectively, then instantiate the class and assign more aliases to the same object. The id() built-in function is then used to confirm that all three aliases reference the same object. The final step is to remove all the aliases by using the del statement and discovering when and how many times the destructor is called.

class C(P):              # class declaration     def __init__(self):          # "constructor"          print 'initialized'     def __del__(self):           # "destructor"          P.__del__(self)    # call parent destructor          print 'deleted' >>> c1 = C()               # instantiation initialized >>> c2 = c1                # create additional alias >>> c3 = c1                # create a third alias >>> id(c1), id(c2), id(c3)  # all refer to same object (11938912, 11938912, 11938912) >>> del c1              # remove one reference >>> del c2              # remove another reference >>> del c3              # remove final reference deleted                      # destructor finally invoked


Notice how, in the above example, the destructor was not called until all references to the instance of class C were removed, e.g., when the reference count has decreased to zero. If for some reason your __del__() method is not being called when you are expecting it to be invoked, this means that somehow your instance object's reference count is not zero, and there may be some other reference to it that you are not aware of that is keeping your object around.

Also note that the destructor is called exactly once, the first time the reference count goes to zero and the object deallocated. This makes sense because any object in the system is allocated and deallocated only once. Summary:

  • Do not forget to call a superclass __del__() first.

  • Invoking del x does not call x.__del__()as you saw above, it just decrements the reference count of x.

  • If you have a cycle or some other cause of lingering references to an instance, an object's __del__() may never be called.

  • Uncaught exceptions in __del__() are ignored (because some variables used in __del__() may have already been deleted). Try not to do anything in __del__() not related to an instance.

  • Implementing __del__() is not a common occurrenceonly do it if you really know what you are doing.

  • If you define __del__, and instance is part of a cycle, the garbage collector will not break the cycleyou have to do it yourself by explicitly using del.

Core Note: Keeping track of instances

Python does not provide any internal mechanism to track how many instances of a class have been created or to keep tabs on what they are. You can explicitly add some code to the class definition and perhaps __init__() and __del__() if such functionality is desired. The best way is to keep track of the number of instances using a static member. It would be dangerous to keep track of instance objects by saving references to them, because you must manage these references properly or else your instances will never be deallocated (because of your extra reference to them)! An example follows:

class InstCt(object):     count = 0              # count is class attr     def __init__(self):         # increment count          InstCt.count += 1     def __del__(self):          # decrement count          InstCt.count -= 1     def howMany(self):          # return count         return InstCt.count >>> a = InstTrack() >>> b = InstTrack() >>> b.howMany() 2 >>> a.howMany() 2 >>> del b >>> a.howMany() 1 >>> del a >>> InstTrack.count 0





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