Monday, April 26, 2010

Decorators & OO in Python

Jack Diederich
[Python-3000] PEP Draft: Class Decorators

Cesar Otero - IBM DevelopWorks White Paper
Python 3 primer, Part 2: Advanced topics
Metaclasses, decorators, and other strange creatures

Python Introspection/Reflection Utility Class

So the code below is for a python module 'mir.py', and contains a class 'Mir' and a rather thin main method 'run()' which demos the class.


class Mir:
"""mirror introspection/reflection class"""

meth_lookup_token_len = len('<function')
meth_type_lookup = {
'<bound me' : 'instance',
'<function' : 'static',
'<method-wr' : 'wrapper',
'<built-in ' : 'built-in'
}

def __init__(self):
"""docstring for initializer"""
pass

@staticmethod
def ins(target,show_magic_meths=False):

lines = []

"""provide basic information on the target"""

# column widthss
c1 = 20
c2 = 20
c3 = 40

field_names = []
method_names = []
mangled_field_names = []

dir_list = dir(target)

for ob in dir_list:

if (callable(getattr(target, ob))):
method_names.append(ob)
else:
field_names.append(ob)

# FIELDS --------------------------------------

# double leading and trailing underscore
magic_fields = []
# starts and ends with alphabetic
normal_fields = []

# double leading underscore # mangledFields = []
# single leading underscore # privateFields = []

for field_name in field_names:

a = getattr(target, field_name)
l = len(field_name)

# magic fields
if (field_name[0:2] == '__'):
if (field_name[l - 2 : l] == '__'):
magic_fields.append(field_name)
else:
mangled_field_names.append(field_names)
else:
normal_fields.append(field_name)

if '__doc__' in magic_fields:
docstring = getattr(target, '__doc__')
else:
docstring = 'no doc string'

if '__module__' in magic_fields:
moduleName = getattr(target, '__module__')
else:
moduleName = 'no module'

# METHODS

# class methods
# instance methods
# - constructor
# - vanilla

static_methods = []
instance_methods = []

magic_methods = []

meth_info = []

for method_name in method_names:

# DETERMINE METHOD TYPE = INSTANCE, STATIC

a = getattr(target, method_name)
try:
s = (str(a))
token = s[0:Mir.meth_lookup_token_len+1]
meth_type = Mir.meth_type_lookup[token]
except:
meth_type = s[0:c2]
else:
pass

# GET METHOD DOC-STRING

meth_docstring = getattr(a, '__doc__')

if (meth_docstring == None):
meth_docstring = ''
else:
meth_docstring = meth_docstring.replace('\n', ' | ')

if (meth_type == 'static'):
static_methods.append((method_name, meth_docstring))
elif (meth_type == 'instance'):
instance_methods.append((method_name, meth_docstring))
else:
pass

L = len(method_name)
prefix = (method_name[0:2] == '__')
suffix = (method_name[L-2:L] == '__')
if (prefix and suffix):
magic_methods.append(method_name)

meth_info.append((method_name, meth_type, meth_docstring))

lines.append('----------------------------------------------------------------------')
lines.append('target = ' + str(target))
lines.append('target type = ' + str(type(target)))
lines.append('source module: %s' % moduleName)
lines.append('----------------------------------------------------------------------')
lines.append('docstring: %s' % docstring)
lines.append('')
lines.append('----------------------------------------------------------------------')
lines.append('FIELDS')
lines.append('---------------')
# static
# class
# instance

for field_name in normal_fields:
a = getattr(target, field_name)
lines.append(field_name.ljust(20) + str(a).ljust(30))

if (show_magic_meths):
lines.append('----------------------------------------------------------------------')
lines.append('METHODS - MAGIC')
lines.append('---------------')
for (meth_name, meth_type, methDoc) in meth_info:
if (meth_name in magic_methods):
lines.append(meth_name.ljust(c1) + meth_type.ljust(c2) + methDoc.ljust(c3))

lines.append('----------------------------------------------------------------------')
lines.append('METHODS - NON-MAGIC')
lines.append('---------------')
for (meth_name, meth_type, methDoc) in meth_info:
if (meth_name not in magic_methods):
lines.append(meth_name.ljust(c1) + meth_type.ljust(c2) + methDoc.ljust(c3))

return lines

@staticmethod
def inspect(target):

lines = Mir.ins(target)

for line in lines:
print(line)

@staticmethod
def ins2f(target, fname):

file = open(fname, 'w')
for line in Mir.ins(target):
file.write(line + '\n')
file.close()


# #########################################################

def run():

lis = []
Mir.inspect(lis)

if __name__ == '__main__':

Sunday, April 25, 2010

Some OO Concepts in Python

PRIVATE VS PUBLIC

the short answer is no - in other words, this is not productively supported.

use the convention of prefixing 'would otherwise be private if the dumb language supported it' fields with an underscore, e.g.

class TheClass:

def __init__(self):
self._nominallyPrivateField = 'private'

CLASS vs INSTANCE OBJECTS

Class Objects support
- instantiation
- attribute referencing

class TheClass:

classLevelField = 'class level field'

def __init__(self):
self.instanceLevelField = 'instance level field'


Making our descriptively named class more accurately self-referential:

class TheClass:

classLevelField = 'class level field'

def __init__(self):
self._nominallyPrivateInstanceLevelField = 'only nominally private instance level field'

Finally, just to avoid any lurking confusion, THE FOLLOWING IS FLAWED

class TheClass:

classLevelField = 'class level field'

self._nominallyPrivateInstanceLevelField = 'only nominally private instance level field'

def __init__(self):
pass

and fails miserably, raising a NameError exception;

NameError: name 'self' is not defined


-------

So, annotating a method with the @classmethod produces something quite similar to a C# static method. In other words, within the class method only local and class level references are possible, or rather, no instance level field or method is accessible (short of instantiating an object of that class within the class method, and calling the method on that instance).

Where C# and python differ, however, is that in C# to call the static method DoStuff() on class TheClass, you would have something like this

TheClass.DoStuff()

In other words, you can't have something like this, where you call the class method on an instance variable

TheClass myClass = new TheClass();
myClass.DoStuff();

The compiler will kick you in the head.

In python, however, there is no such limitation. You can happily call a class method on an instance variable (the class method still won't have access to the instance level scope).

ABSTRACT BASE CLASSES & QUASI-INTERFACES
- ABCs - PEP 3119 = http://www.python.org/dev/peps/pep-3119/
- from the pythondocs: http://docs.python.org/library/abc.html
- James Tauber's take on interfaces: http://jtauber.com/blog/2007/03/04/interfaces_versus_abstract_base_classes_in_python/

Thursday, April 15, 2010

To Force a Line-Break in a VS2008 Method Summary Comment

enclose the target text in tags.
this will force a line-break afterwards.

note that a line with will simply be ignored, and will not produce and empty line as might be expected.

Saturday, April 10, 2010

Python Resources

WHAT IS PYTHON ?
- interpreted
- compiled to intermediate bytecode
- dynamically typed
- functional, object oriented and imperative paradigms

SOME PYTHON USERS
- google
- facebook ?
- nasa

A COUPLE OF NOTES ON VERSIONING
- latest release = 3.?
- 2.7 = offers features from 3.0 but and backwards compatibility with 2.x
get the latest version from the OFFICIAL DOWNLOAD PAGE

Python-specific Integrated Development Environments (IDE's)
- #1 - GEANY Light-Weight w. Introspective Predictive Text !!
- netbeans 6.5 python early-access stand-alone
- netbeans java with python plugin
- eclipse with pydev plugin
- SCITE text editor


TUTORIALS

Good places to start
- The Official Docs
- Dive into Python

STYLE GUIDEs
- PEP 8 - an Official Style Guide
- official google python style guide
- 'Coding Like a Pythonista' - Idiomatic Python

UNIT TESTING
- unittest

OBJECT ORIENTED PARADIGM
- decorators, decorators
- abstract base classes
- meta_classes
- properties, properties
- staticmethods & classmethods

FUNCTIONAL PROGRAMMING PARADIGM
- map, reduce, filter @ pythontips.com

WIDGET KITS
- pygtk
- wxpython
- light-weight - tkinter

WEB
- django

NUMERIC AND SCIENTIFIC LIBRARIES
- numpy and scipy

PLOTTING
- matplotlib

LOGGING and other timber-related activities

Why Python ?
by Eric S Raymond, author of 'The Cathedral and the Bazaar"