Entries for Python
Patrón Singleton en Python3
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>
>>>
Cómo simular un módulo en Python
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
>>>
Python re: bad character range
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>
>>>
Simular enumeraciones en Python
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)
SystemError: error return without exception set
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;
}
}
Bindings Python para bibliotecas C: Argumentos (Parte 4)
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.
Argumentos en Python
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.
Bindings Python para bibliotecas C: Métodos (Parte 3)
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.
Bindings Python para bibliotecas C: Módulos y compilación (Parte 2)
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.
Bindings Python para bibliotecas C: ¿Qué son? (Parte 1)
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
Validación de NIFs y CIFs en Python 3
24 February 2012
OnlyGL
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.
Capturar señales en Python
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
$
Analizar los parámetros de consulta de URL en Python
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'}
Soporte para JPEG, Zlib y FreeType2 en PIL
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/
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é.
