Document Actions
Send this page to somebody Print this page
Parte 4

1. Introspección

En Python, todo es un objeto. Instrospección es cuando cierto código observa otros módulos o funciones en la memoria como objetos, obteniendo información de ellos o manipulándolos.

2. Ejemplo apihelper.py

def info(object, spacing=10, collapse=1):  
"""Print methods and doc strings.

Takes module, class, list, dictionary, or string."""
methodList = [method for method in dir(object) if callable(getattr(object, method))]
processFunc = collapse and (lambda s: " ".join(s.split())) or (lambda s: s)
print "\n".join(["%s %s" %
(method.ljust(spacing),
processFunc(str(getattr(object, method).__doc__)))
for method in methodList])

if __name__ == "__main__":
print info.__doc__
Repaso de secciones anteriores
  • info es una función con tres parámetros.
  • info tiene documentación multilínea. No tiene ningún return, esta función se usará por sus efectos mas que por sus valores
  • El código dentro de la función está indentado
  • El truco if __name__ permite que el módulo provea una funcionalidad cuando se lo corre por si mismo, sin interferir en casos que sea usado por otros módulos
  • La expresión if usa == para comparación, los paréntesis no son necesarios

Uso de apihelper.py

>>> from apihelper import info
>>> li = []
>>> info(li)
append L.append(object) -- append object to end
count L.count(value) -> integer -- return number of occurrences of value
extend L.extend(list) -- extend list by appending list elements
index L.index(value) -> integer -- return index of first occurrence of value
insert L.insert(index, object) -- insert object before index
pop L.pop([index]) -> item -- remove and return item at index (default last)
remove L.remove(value) -- remove first occurrence of value
reverse L.reverse() -- reverse *IN PLACE*
sort L.sort([cmpfunc]) -- sort *IN PLACE*; if given, cmpfunc(x, y) -> -1, 0, 1
>>> import odbchelper
>>> info(odbchelper)
buildConnectionString Build a connection string from a dictionary Returns string.
>>> info(odbchelper, 30)
buildConnectionString Build a connection string from a dictionary Returns string.
>>> info(odbchelper, 30, 0)
buildConnectionString Build a connection string from a dictionary

Returns string.

3. Usando argumentos opcionales y con nombres

Python permite definir valores por defecto para los argumentos de funciones. Cuando la función es llamada sin argumentos, estos toman los valores por defecto.

Ejemplo:

def info(object, spacing=10, collapse=1):
info(odbchelper)                    
info(odbchelper, 12)
info(odbchelper, collapse=0)
info(spacing=15, object=odbchelper)

Casos como la última línea pueden generar mucha confusión hasta que uno descubre que los argumentos son simples diccionarios.

Mas Lectura


4. Using type, str, dir, and Other Built-In Functions


4.1. La función type

La función type devuelve el tipo de un objeto arbitrario. La lista de tipos posibles son listados en el módulo type. Este método es de mucha ayuda cuando existen funciones que pueden tomar distintos tipos.

>>> type(1)           
<type 'int'>
>>> li = []
>>> type(li)
<type 'list'>
>>> import odbchelper
>>> type(odbchelper)
<type 'module'>
>>> import types
>>> type(odbchelper) == types.ModuleType
True

4.2. La función str

str convierte datos en un string. Todos los tipos de datos soportan str.

>>> str(1)          
'1'
>>> horsemen = ['war', 'pestilence', 'famine']
>>> horsemen
['war', 'pestilence', 'famine']
>>> horsemen.append('Powerbuilder')
>>> str(horsemen)
"['war', 'pestilence', 'famine', 'Powerbuilder']"
>>> str(odbchelper)
"<module 'odbchelper' from 'c:\\docbook\\dip\\py\\odbchelper.py'>"
>>> str(None)
'None'

4.3. La función dir

>>> li = []
>>> dir(li)
['append', 'count', 'extend', 'index', 'insert',
'pop', 'remove', 'reverse', 'sort']
>>> d = {}
>>> dir(d)
['clear', 'copy', 'get', 'has_key', 'items', 'keys', 'setdefault', 'update', 'values']
>>> import odbchelper
>>> dir(odbchelper)
['__builtins__', '__doc__', '__file__', '__name__', 'buildConnectionString']

4.4. La función callable


>>> import string
>>> string.punctuation
'!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~'
>>> string.join
<function join at 00C55A7C>
>>> callable(string.punctuation)
False
>>> callable(string.join)
True
>>> print string.join.__doc__
join(list [,sep]) -> string

Return a string composed of the words in list, with
intervening occurrences of sep. The default separator is a
single space.

(joinfields and join are synonymous)

4.5. Otras funciones built-in

type, str, dir, y todas las funciones internas de python están agrupadas en un módulo especial llamado __builtin__

>>> from apihelper import info
>>> import __builtin__
>>> info(__builtin__, 20)
ArithmeticError Base class for arithmetic errors.
AssertionError Assertion failed.
AttributeError Attribute not found.
EOFError Read beyond end of file.
EnvironmentError Base class for I/O related errors.
Exception Common base class for all exceptions.
FloatingPointError Floating point operation failed.
IOError I/O operation failed.

[...snip...]

Mas lectura de funciones Built-In


5. Obteniendo referencias de objetos con getattr

Las funciones son objetos en Python. Usando el método getattr es posible obtener una referencia de una función sin saber su nombre hasta estar en tiempo de ejecución.
>>> li = ["Larry", "Curly"]
>>> li.pop
<built-in method pop of list object at 010DF884>
>>> getattr(li, "pop")
<built-in method pop of list object at 010DF884>
>>> getattr(li, "append")("Moe")
>>> li
["Larry", "Curly", "Moe"]
>>> getattr({}, "clear")
<built-in method clear of dictionary object at 00F113D4>
>>> getattr((), "pop")
Traceback (innermost last):
File "<interactive input>", line 1, in ?
AttributeError: 'tuple' object has no attribute 'pop'

>>> li = [1,2,3,4,5]
>>> pop = getattr(li, "pop")
>>> li.append(6)
>>> li.append(7)
>>> li.append(8)
>>> pop()
8
>>> li
[1, 2, 3, 4, 5, 6, 7]

getattr y módulos

>>> import odbchelper
>>> odbchelper.buildConnectionString
<function buildConnectionString at 00D18DD4>
>>> getattr(odbchelper, "buildConnectionString")
<function buildConnectionString at 00D18DD4>
>>> object = odbchelper
>>> method = "buildConnectionString"
>>> getattr(object, method)
<function buildConnectionString at 00D18DD4>
>>> type(getattr(object, method))
<type 'function'>
>>> import types
>>> type(getattr(object, method)) == types.FunctionType
True
>>> callable(getattr(object, method))
True

getattr como dispatcher

Un uso comun de getattr es como implementación del patron dispatcher. Por ejemplo, si se posee un programa cuya salida soporta diferentes formatos, se puede definir una función para cada formato y una sola función dispatcher para llamar a la función adecuada.

Supongamos que tenemos un módulo statsout defines con tres funciones output_html, output_xml, and output_text. Y luego, se define una función:
import statsout

def output(data, format="text"):
output_function = getattr(statsout, "output_%s" % format)
return output_function(data)
statsout.py
def output_text(data):
return data

def output_html(data):
return '<html><head></head><body>' + data + '</body></html>'

def output_xml(data):
return '<xml>' + data + '</xml>'

Valores por defecto de getattr

import statsout

def output(data, format="text"):
output_function = getattr(statsout, "output_%s" % format, statsout.output_text)
return output_function(data)

6. Filtrando listas

Las listas por comprensión pueden combinarse con un mecanismo de filtrado y como resultado unos elementos son mapeados y otros removidos.

[mapping-expression for element in source-list if filter-expression]

Ejemplo

>>> li = ["a", "mpilgrim", "foo", "b", "c", "b", "d", "d"]
>>> [elem for elem in li if len(elem) > 1]
['mpilgrim', 'foo']
>>> [elem for elem in li if elem != "b"]
['a', 'mpilgrim', 'foo', 'c', 'd', 'd']
>>> [elem for elem in li if li.count(elem) == 1]
['a', 'mpilgrim', 'foo', 'c']
Volviendo a apihelper.py
methodList = [method for method in dir(object) if callable(getattr(object, method))]

Mas lectura


7. La peculiar naturaleza de and y or

En python, and y or realizan operaciones lógicas, pero no retornan valores booleanos; en lugar de ellos devuelven uno de los valores comparados.
>>> 'a' and 'b'         
'b'
>>> '' and 'b'
''
>>> 'a' and 'b' and 'c'
'c'
  • and evalua de izquierda a derecha. 0, '', [], (), {}, None son False en un contexto booleano, todo lo demás True.
  • Si cualquier valor es false, and devuelve el primer atributo falso
  • Si todos son verdaderos se devuelve el último valor
>>> 'a' or 'b'        
'a'
>>> '' or 'b'
'b'
>>> '' or [] or {}
{}
>>> def sidefx():
... print "in sidefx()"
... return 1
>>> 'a' or sidefx()
'a'
  • or evalua todo los elementos de izquierda a derecha. Si un valor es verdadero, or lo retorna inmediatamente
  • si todos los elementos son falsos, or devuelve el último elemento

Mas Lectura


8. Funciones lambda

Python soporta una funcionalidad interesante que permite definir mini-funciones de una línea. Tomado de Lisp, las funciones lambda pueden usarse en cualquier sitio que se requiera una función.
>>> def f(x):
... return x*2
...
>>> f(3)
6
>>> g = lambda x: x*2
>>> g(3)
6
>>> (lambda x: x*2)(3)
6
  processFunc = collapse and (lambda s: " ".join(s.split())) or (lambda s: s)
>>> s = "this   is\na\ttest"  
>>> print s
this is
a test
>>> print s.split()
['this', 'is', 'a', 'test']
>>> print " ".join(s.split())
'this is a test'

Mas lectura sobre funciones lambda


9. Integrando todo

    print "\n".join(["%s %s" %
(method.ljust(spacing),
processFunc(str(getattr(object, method).__doc__)))
for method in methodList])
for method in methodList
>>> import odbchelper
>>> object = odbchelper
>>> method = 'buildConnectionString'
>>> getattr(object, method)
<function buildConnectionString at 010D6D74>
>>> print getattr(object, method).__doc__
Build a connection string from a dictionary of parameters.

Returns string.


¿ Por qué usar str en una doc string ?

>>> def foo(): print 2
>>> foo()
2
>>> foo.__doc__
>>> foo.__doc__ == None
True
>>> str(foo.__doc__)
'None'
>>> s = 'buildConnectionString'
>>> s.ljust(30)
'buildConnectionString '
>>> s.ljust(20)
'buildConnectionString'

Imprimiendo una lista

>>> li = ['a', 'b', 'c']
>>> print "\n".join(li) 1
a
b
c

Ahora se deberia entender sin problemas

    print "\n".join(["%s %s" %
(method.ljust(spacing),
processFunc(str(getattr(object, method).__doc__)))
for method in methodList])

10. Resumen

Apihelper deberia tener sentido ahora:

def info(object, spacing=10, collapse=1):
"""Print methods and doc strings.
Takes module, class, list, dictionary, or string."""
methodList = [method for method in dir(object) if callable(getattr(object, method))]
processFunc = collapse and (lambda s: " ".join(s.split())) or (lambda s: s)
print "\n".join(["%s %s" %
(method.ljust(spacing),
processFunc(str(getattr(object, method).__doc__)))
for method in methodList])

if __name__ == "__main__":
print info.__doc__


Uso de apihelper.py

>>> from apihelper import info
>>> li = []
>>> info(li)
append L.append(object) -- append object to end
count L.count(value) -> integer -- return number of occurrences of value
extend L.extend(list) -- extend list by appending list elements
index L.index(value) -> integer -- return index of first occurrence of value
insert L.insert(index, object) -- insert object before index
pop L.pop([index]) -> item -- remove and return item at index (default last)
remove L.remove(value) -- remove first occurrence of value
reverse L.reverse() -- reverse *IN PLACE*
sort L.sort([cmpfunc]) -- sort *IN PLACE*; if given, cmpfunc(x, y) -> -1, 0, 1


Ejemplo: usando gettattr para ejecutar métodos de listas en tiempo de ejecución

def codigo():
    lista = []
    while len(lista) < 3:
        lista.append(raw_input('un numero: ') )

    orden = ''
    while orden != 'end':
        orden = raw_input('++ >>> ')
        f = getattr(lista,orden, dir(lista) )
        if type(f)==type([]):
            print 'No es un comando de lista, los validos son: \n',  f
        else:
            print 'f: ', str(f())
            print 'lista: ', lista



Ejercicios

  1. Escribir los méteodos output_html, output_xml y output_text. Los dos primeros métodos toman como parámetros opcionales los campos en los cuales está el texto, por ejemplo:
    >>> output_html('data')
    '<html><head>data</head><body>data</body></html>'
    >>> output_xml('data',)
    '<xml>data</xml>'
    >>> output_text('data', 'title')
    'data'
    >>> output_html('data', 'b')
    '<html><head>data</head><body><b>data</b></body></html>'
    >>> output_xml('data', 'title')
    '<xml><title>data</title></xml>'
    >>> output_text('data', 'title')
    'Title: data'
  2. Verificar str con valores de los diferentes tipos definidos en el módulo de type.

  3. Usando listas por compresión, filtrado y range hacer y una expresión para calcular lo que esta en italica:

    • un programa que calcule el producto de los números pares del 0 al 100
    • un programa que calcule el producto de los números impares del 0 al 100
    • un programa que calcule el producto de los números primos del 0 al 100 (Opcional)
  4. suc es una función que dado un número n retorna n+1, usando una función lambda escribir suc
  5. Usando la función cmp escribir un método que permita comparar si 3 o 2 números a, b, c cumplen a < b < c y tambien a < b. No usar el operador < ni >


Copyright (C) 2004-2007 Menttes - All Rights Reserved