Wednesday, June 11, 2008

O'Reilly's Learning Python

Google Books has a lot of O'Reilly's Learning Python. I found the following useful for getting myself back into Python:
  • Dynamic Typing: variables aren't typed, objects are:
    • variables are entries in a system table, with spaces for links to objects
    • objects are pieces of allocated memory, with enough space to represent the values for which they stand
    • references are automatically followed pointers from variables to objects
    "variables are always pointers to objects, not labels of changeable memory areas: setting a variable to a new value does not alter the original object, but rather causes the variable to reference an entirely different object."
  • Modules: highest-level program organizational unit which typically correspond to other python files. import finds the module's file, compiles it into byte code and runs the module's code to build the objects it defines (it's not just a textual substitution).

    Python forbids import foo.py or import /bar/foo.py. A platform independent module search path (print sys.path) abstracts this away. An import foo will use foo.py, provided it exists in the program's home directory: where the top-level program resides or where the REPL was started. To cross directories set the PYTHONPATH environment variable in your shell:

    $ cat modules/my_mod.py
    def f():
            print "I'm f"
    $ cat my_program.py
    import my_mod
    my_mod.f()
    $ cat shell_wrapper.sh
    #!/bin/sh
    export PYTHONPATH=${PYTHONPATH}:modules/
    /usr/bin/python my_program.py
    $ 
    
    In the example above running python my_program.py will fail but ./shell_wrapper.sh works. See also Python Tutorial: Modules.
  • Class Coding: Python's OOP supports:
    • Inheritance: based on attribute (method or variable) lookup. E.g. in X.name expressions, X is an instance of a class with attribute name. Inheritance comes up with respect to instances of classes as well as derived classes.
    • Polymorphism: in X.method(), the meaning of method depends on the type (class) of X.
    • Encapsulation: Methods and operators implement behavior; data hiding is more of a convention than the rule
    The object self is passed as the first argument of a Method. Because classes generate multiple instances, methods must go through the self argument to get to the instance to be processed.

    The book provides a quick example of defining a class and two instances:

    $ python
    Python 2.5.2 (r252:60911, Apr 21 2008, 11:17:30) 
    [GCC 4.2.3 (Ubuntu 4.2.3-2ubuntu7)] on linux2
    Type "help", "copyright", "credits" or "license" for more information.
    >>> class FirstClass:
    ...     def setdata(self, value):
    ...             self.data = value
    ...     def display(self):
    ...             print self.data
    ... 
    >>> x = FirstClass()
    >>> y = FirstClass()
    >>> x.setdata("King Arthur")
    >>> y.setdata(3.14159)
    >>> x.display()
    King Arthur
    >>> y.display()
    3.14159
    
    It then goes on to create a second class which inherits from the first class:
    >>> class SecondClass(FirstClass):
    ...     def display(self):
    ...             print 'Current value = "%s"' % self.data
    ... 
    >>> z = SecondClass()
    >>> z.setdata(42)
    >>> z.display()
    Current value = "42"
    >>> 
    
    We used the inherited setdata() method but that the display() method was overrided.

    Python also supports operator overloading via __<HOOKS>__. For example, __init__ is the constructor hook that most classes should have. You can also get creative and support operators like + or * based on the hooks available:

    >>> class ThirdClass(SecondClass):
    ...     def __init__(self, value):
    ...             self.data = value
    ...     def __add__(self, other):
    ...             return ThirdClass(self.data + other)
    ...     def __mul__(self, other):
    ...             self.data = self.data * other
    ... 
    >>> a = ThirdClass("abc")
    >>> a.display()
    Current value = "abc"
    >>> b = a + 'xyz'
    >>> b.display()
    Current value = "abcxyz"
    >>> a * 3
    >>> a.display()
    Current value = "abcabcabc"
    >>> 
    
    Note that we're not using a setdata() method since we're just using the constructor. What's more interesting is that we're just adding and multiplying on our new object with standard operators and that they have meaning relative to the object.
It seems that Google Books will omit different pages based on a different host somewhat randomly (handy for missing pages).

No comments: