Entries for Python

Patrón Singleton en Python3

written by uve

17 July 2012

Existen distintas alternativas para implementar este patrón en Python. Una de ellas consiste en el uso de metaclass, que es la que vamos a ver a continuación. Para ello, es necesario definirnos un nuevo tipo:

class SingletonMetaClass(type):
    def __init__(cls,name,bases,dic):
        super(SingletonMetaClass, cls).__init__(name, bases, dic)
        cls._singleton_instance = None

    def __call__(cls,*args,**kw):
        if cls._singleton_instance is None:
            cls._singleton_instance = \
                super(SingletonMetaClass, cls).__call__(*args, **kw)
        return cls._singleton_instance

Así, nuestra clase SingletonMetaClass será un nuevo tipo, hereda de type, por lo que podemos utilizarlo para la construcción de nuestras clases, como por ejemplo:

class Singleton(metaclass=SingletonMetaClass):
    pass

Así, la construcción de objetos del tipo Singleton están controlados por SingletonMetaClass. A partir de este punto, todas aquellas clases que tengamos interés en que sigan este patrón heredarán de la clase Singleton.

Veamos un ejemplo:

>>> class ExampleNoSingleton(): pass
...
>>> ExampleNoSingleton()
<__main__.ExampleNoSingleton object at 0x7fec6bf2f110>
>>> ExampleNoSingleton()
<__main__.ExampleNoSingleton object at 0x7fec6bf2f1d0>
>>> ExampleNoSingleton()
<__main__.ExampleNoSingleton object at 0x7fec6bf2f110>
>>>
>>> class ExampleSingleton(Singleton): pass
...
>>> ExampleSingleton()
<__main__.ExampleSingleton object at 0x7fec6bf2f210>
>>> ExampleSingleton()
<__main__.ExampleSingleton object at 0x7fec6bf2f210>
>>> ExampleSingleton()
<__main__.ExampleSingleton object at 0x7fec6bf2f210>
>>>

Full entry >>

Cómo simular un módulo en Python

written by uve

16 July 2012

Ahora mismo estoy diseñando unos tests para el Trabajo Fin de Máster y me he visto en la necesidad de hacer que un objeto simule un módulo Python, para que valide el método ismodule de inspect. Por ejemplo:

>>> import sys
>>> import inspect
>>> inspect.ismodule(sys)
True
>>>

Para conseguir pasar esta validación, necesitamos que nuestro objeto herede de types.ModuleType:

>>> import types
>>> class Module(types.ModuleType):
...  pass
...
>>> m = Module('ModuleName')
>>> inspect.ismodule(m)
True
>>>

Full entry >>

Python re: bad character range

written by uve

12 July 2012

Trabajando con expresiones regulares, acabamos de encontrarnos con un "bad character range". Queremos una expresión que sea capaz de reconocer secuencias de letras, guiones y '+'. Así se podrían reconocer patrones como 'xhtml+xml', 'html' ó 'x-dvi'.

Supongamos la siguiente expresión r'[\w-\+]+', que parece completamente válida. Pues este es el resultado:

>>> re.compile('[\w-\+]+')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python3.2/re.py", line 206, in compile
    return _compile(pattern, flags)
  File "/usr/lib/python3.2/re.py", line 255, in _compile
    return _compile_typed(type(pattern), pattern, flags)
  File "/usr/lib/python3.2/functools.py", line 184, in wrapper
    result = user_function(*args, **kwds)
  File "/usr/lib/python3.2/re.py", line 267, in _compile_typed
    return sre_compile.compile(pattern, flags)
  File "/usr/lib/python3.2/sre_compile.py", line 491, in compile
    p = sre_parse.parse(p, flags)
  File "/usr/lib/python3.2/sre_parse.py", line 692, in parse
    p = _parse_sub(source, pattern, 0)
  File "/usr/lib/python3.2/sre_parse.py", line 315, in _parse_sub
    itemsappend(_parse(source, state))
  File "/usr/lib/python3.2/sre_parse.py", line 457, in _parse
    raise error("bad character range")
sre_constants.error: bad character range

El caracter '-' se puede utilizar dentro de los corchetes [ ], como carácter a reconocer. El problema es que si está separando dos caracteres, \w y \+, asume que es un rango.

Distintas soluciones:

>>> re.compile('[\w\+-]')
<_sre.SRE_Pattern object at 0x7fd793a5daf8>
>>> re.compile('[-\w\+]')
<_sre.SRE_Pattern object at 0x7fd793a5dd20>
>>> re.compile('[\w\-\+]')
<_sre.SRE_Pattern object at 0x7fd793a5ddd8>
>>>

Full entry >>

Simular enumeraciones en Python

written by uve

14 May 2012

Estoy ahora mismo trabajando con Python y me acabo de encontrar que disponer de una enumeración me vendría muy bien. Así que, después de investigar un rato, he encontrado dos formas distintas y muy prácticas para hacer enumeraciones.

Estilo C

La primera opción, es hacerlas como se hacen en C. Variables enteras globales:

(GATEWAY_CLASS, FORWARDING_CLASS, PARSE_CLASS) = range(1, 4)

El problema de esta solución, es que en cualquier momento se puede modificar el valor de cualquiera de estas variables, con las consecuencias que esto conlleva.

Estilo Java

En Java, cuando declaramos una enumeración, debemos acceder a través del nombre de la enumeración. Por tanto, para simular este comportamiento en Python, necesitamos una clase:

class RoutingClassType(type):
    (GATEWAY_CLASS,
        FORWARDING_CLASS,
        PARSE_CLASS) = range(1, 4)

Así, ahora tendríamos que acceder así:

RoutingClassType.GATEWAY_CLASS

Aunque esta solución sigue presentando el mismo problema que la solución anterior, lo podemos solucionar creando un nuevo tipo que impida modificar sus atributos:

class EnumType(type):
    def __setattr__(self, name, value):
        raise ValueError

Y ahora bastará con definir nuestra enumeración de la siguiente forma:

class RoutingClassType(type):
    __metaclass__ = EnumType
   
    (GATEWAY_CLASS,
        FORWARDING_CLASS,
        PARSE_CLASS) = range(1, 4)

Full entry >>

SystemError: error return without exception set

written by uve

11 April 2012

Esto se puede deber a que se ha devuelto NULL en una función en la que se debería devolver algo (None por ejemplo):

static PyObject*
example(PyObject *self, PyObject* args, PyObject* kwargs)
{
    // do something
    return NULL;
}

se corrige de la siguiente forma:

static PyObject*
example(PyObject *self, PyObject* args, PyObject* kwargs)
{
    // do something
    Py_RETURN_NONE;
}

o porque al lazar una excepción, no hemos indicado de que excepción se trata:

static PyObject*
example(PyObject *self, PyObject* args, PyObject* kwargs)
{
    PyObject* var;
    // ...
    if(!PyBool_Check(var))
    {
        return NULL;
    }
}

y se corrige:

static PyObject*
example(PyObject *self, PyObject* args, PyObject* kwargs)
{
    PyObject* var;
    // ...
    if(!PyBool_Check(var))
    {
        PyErr_SetString(PyExc_TypeError, "Not boolean");
        return NULL;
    }
}

Full entry >>

Bindings Python para bibliotecas C: Argumentos (Parte 4)

written by uve

28 March 2012

Continuando con el ejemplo de ayer, hoy voy a explicar cómo podemos parsear los parámetros de entrada. El estado actual es que hemos definido unos prototipos y los hemos añadido al módulo. Ahora vamos a darle contenido a las funciones add y hello.

Ejemplo en GitHub: mema_methods.

Full entry >>

Argumentos en Python

written by uve

28 March 2012

Para los programadores de C, C++, Java, ... puede resultar un tanto extraño la forma de gestionar los parámetros que tiene Python.

Voy a explicar en esta entrada los tipos de parámetros y cómo podemos hacer uso de ellos.

Full entry >>

Bindings Python para bibliotecas C: Métodos (Parte 3)

written by uve

27 March 2012

Ayer explicaba cómo se monta una estructura básica para crear un módulo. Pero para que el módulo sirva para algo, tendremos que añadir funciones.

Ahora vamos a ver cómo podemos crear nuevas funciones y cómo integrarlas al módulo mema. El objetivo para hoy será crear dos funciones: hello y add.

El resultado debería ser algo similar a lo siguiente:

>>> import mema
>>> mema.hello()
Hello mema!
>>> mema.hello('Vicente')
Hello Vicente!
>>>
>>> from mema import add
>>> add(1, 2)
3
>>> add(400, 4)
404
>>>

Ejemplo en GitHub: mema_methods.

Full entry >>

Bindings Python para bibliotecas C: Módulos y compilación (Parte 2)

written by uve

26 March 2012

La semana pasada empecé ha hablar sobre los Bindings en Python. Hoy vamos a ver cómo es una estructura muy básica, cómo compilar y probar que todo funciona.

Un problema que me estoy encontrando, es que el API C de Python ha ido cambiando con las versiones. Entonces, muchos ejemplos que he encontrado no compilan y hay código muy diferente por ahí.

Inicialmente voy a centrarme en Python 2.7 (última versión de la rama 2.x) y si encuentro tiempo, haré lo mismo para Python 3.

Ejemplo en GitHub: mema_bare.

Full entry >>

Bindings Python para bibliotecas C: ¿Qué son? (Parte 1)

written by uve

23 March 2012

Hoy voy a hablar acerca de bindings para Python. Un binding es un módulo Python, escrito en lenguaje C, que permite realizar llamadas a funciones en C desde un script hecho en Python. Se puede ver como un "puente" desde C a Python.

Pueden existir distintos motivos para desear hacer un binding. En principio, puede parecer un poco contraproducente, ya que se pierde portablidad

Entonces, ¿por qué crear un binding? Bien es sabido por todos que C es más eficiente que Python, por tanto, si se trata de una parte crítica de una aplicación, perfectametne se puede hacer el procesamiento en C y dejar Python para la lógica.

Otra razón es aprovechar código existente en C. Como comenté, estoy trabajando en libemqtt, la cuál está escrita en C. Podría hacer una nueva implementación completa en Python, pero teniendo el código disponible, lo lógico es hacer un binding.

Los próximos días intentaré escribir una pequeña guía sobre cómo hacer un binding para esta bibliotecta.

Actualización (27/03/2012): He creado un repositorio en GitHub con los ejemplos que estoy implementando:

https://github.com/menudoproblema/menudoproblema-examples/tree/master/python/bindings

Full entry >>

Validación de NIFs y CIFs en Python 3

written by uve

24 February 2012

Hace más de un año escribí un par de entradas acerca de cómo realizar la validación de NIFs y CIFs en Python. He adaptado ese código para Python 3k y modificado un par de detalles.

Full entry >>

OnlyGL

written by uve

2 February 2012

Últimamente he estado bastante liado, entre el trabajo, la carrera y el máster apenas tengo tiempo para escribir.

Como resultado de unas prácticas de una asignatura, Diseño Asistido por Computador, he desarrollado un pequeño Framework en Python con OpenGL cuyo objetivo es desarrollar escenas 3D de forma rápida y sencilla. En unas pocas líneas de código podemos ver los resultados rápidamente.

He liberado el código fuente del Framework y está disponible en GitHub: OnlyGL. Aunque en principio no tengo intención de seguir evolucionando OnlyGL, acepto sugerencias y no tengo problema en invertir algún tiempo si alguien está interesado en algo concreto.

Full entry >>

Capturar señales en Python

written by uve

9 December 2011

A continuación dejo un pequeño ejemplo de como se pueden capturar señales con Python:

import signal
import time
import sys

def signal_handler(sig, func=None):
    print 'SignalHandler. Saliendo...'
    sys.exit(0)

if __name__=='__main__':
    signal.signal(signal.SIGTERM, signal_handler)

    print 'Esperando 15 segundos...'
    time.sleep(15)
    print 'Finalizado'

La idea es muy simple, el programa espera 15 segundos y finaliza. Si se envía la señal SIGTERM (señal 15) el proceso terminará sin esperar. Veamos como se ejecuta de forma normal:

$ python test.py 
Esperando 15 segundos...
Finalizado

Y aquí podemos ver cómo se capturan las señales y se finaliza antes el proceso:

$ python test.py &
[1] 8172
Esperando 15 segundos...
$ kill -15 8172
SignalHandler. Saliendo...
[1]+  Hecho                   python test.py
$

Full entry >>

Analizar los parámetros de consulta de URL en Python

written by uve

11 August 2011

>>> from urlparse import urlparse
>>> url = urlparse('http://www.google.com/search?client=ubuntu&channel=fs&q=python')
>>> params = dict([part.split('=') for part in url[4].split('&')])
>>> params
   {'channel': 'fs', 'client': 'ubuntu', 'q': 'python'}

Full entry >>

Soporte para JPEG, Zlib y FreeType2 en PIL

written by uve

26 April 2011

Hace unos días escribía como Compilar PIL dentro de VirtualEnv, pero realicé la compilación sin soporte para JPEG, Zlib o FreeType2. Ahora mismo estaba probando un script y me he encontrado el siguiente error:

ImportError: The _imagingft C module is not installed

Este error se debe a que no hay soporte para FreeType2. Revisando el directorio de instalación (donde están los fuentes) me he econtrado con lo siguiente:

--------------------------------------------------------------------
PIL 1.1.7 SETUP SUMMARY
--------------------------------------------------------------------
version       1.1.7
platform      linux2 2.7.1+ (r271:86832, Apr 11 2011, 18:13:53)
              [GCC 4.5.2]
--------------------------------------------------------------------
*** TKINTER support not available
*** JPEG support not available
*** ZLIB (PNG/ZIP) support not available
*** FREETYPE2 support not available
*** LITTLECMS support not available
--------------------------------------------------------------------

Al final he optado por la solución más sencilla. Instalarlo en el sistema y utilizarlo dentro de VirtualEnv. Para ello:

$ cd /path/to/virtualenv
$ ln -s /usr/lib/python2.7/dist-packages/PIL/ lib/python2.7/site-packages/

Full entry >>

La teoría es cuando crees saber algo, pero no funciona.
La práctica es cuando algo funciona, pero no sabes por qué.
Los programadores combinan la teoría y la práctica:
Nada funciona y no saben por qué.