<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>El Diario de Aleth &#187; programación</title>
	<atom:link href="http://blog.viricmind.org/category/programacion/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.viricmind.org</link>
	<description>Programando un nuevo mundo...</description>
	<lastBuildDate>Tue, 24 Aug 2010 16:35:18 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Creando un framework con PHP ( II ) : Introspección</title>
		<link>http://blog.viricmind.org/2010/08/11/creando-un-framework-con-php-ii-introspeccion/</link>
		<comments>http://blog.viricmind.org/2010/08/11/creando-un-framework-con-php-ii-introspeccion/#comments</comments>
		<pubDate>Wed, 11 Aug 2010 14:59:10 +0000</pubDate>
		<dc:creator>castarco</dc:creator>
				<category><![CDATA[desarrollo web]]></category>
		<category><![CDATA[framework]]></category>
		<category><![CDATA[internet]]></category>
		<category><![CDATA[introspección]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[programación]]></category>
		<category><![CDATA[reflexión]]></category>

		<guid isPermaLink="false">http://blog.viricmind.org/?p=695</guid>
		<description><![CDATA[A la hora de usar frameworks los programadores esperan cierta magia, que las cosas funcionen sin tener que preocuparse por ciertos detalles nimios, y eso en gran parte se consigue gracias a los métodos de introspección (o reflexión, aunque prefiero el primer término), que en este caso nos son brindados por PHP. Se podría decir [...]]]></description>
			<content:encoded><![CDATA[<p style="text-align: justify;">A la hora de usar frameworks los programadores esperan cierta magia, que las cosas funcionen sin tener que preocuparse por ciertos detalles nimios, y eso en gran parte se consigue gracias a los métodos de introspección (o reflexión, aunque prefiero el primer término), que en este caso nos son brindados por PHP.</p>
<p style="text-align: justify;">Se podría decir que en PHP hay dos caminos para usar la introspección, el uso de ciertas funciones que aparecieron a partir de la versión 4 de PHP (siguiendo el paradigma de la programación estructurada) , o bien el uso de ciertas clases (y sus respectivos objetos, obviamente) que hicieron su aparición estelar con PHP 5.</p>
<p style="text-align: justify;">Por diversos motivos, en el framework que estoy desarrollando he escogido el segundo camino (en realidad un mix, pero predomina la segunda opción), pero aquí comentaré los dos.</p>
<h2 style="text-align: justify;">Introspección al estilo de PHP 4</h2>
<p style="text-align: justify;">Los primeros métodos que deberíamos conocer son los que nos permiten saber qué clases hay declaradas, o si una determinada clase está cargada ya en el contexto en el que nos encontramos, tenemos estos métodos:</p>
<ul style="text-align: justify;">
<li> <em>get_declared_classes ()</em> : retorna una lista que contiene los nombres de todas las clases declaradas.</li>
<li><em>class_exists ($nombre_clase)</em> : retorna verdadero o falso en función de si la clase pasada como parametro ha sido declarada o no. Como parámetro podemos pasar una cadena, o la propia clase si ya la conocemos. Ejemplo:
<pre>class Prueba {
}
class_exists ('Prueba'); // Retorna verdadero
class_exists (Prueba);   // También retorna verdadero</pre>
</li>
</ul>
<p style="text-align: justify;">Una vez sabemos qué clases hay declaradas, también podríamos querer cómo son éstas por dentro, tenemos los siguientes métodos (creo que esta lista no es exhaustiva):</p>
<ul style="text-align: justify;">
<li> <em>get_class_methods ($nombre_clase)</em> : Nos devuelve una lista con los nombres de todos los métodos de la clase</li>
<li><em>get_class_vars ($nombre_clase)</em> : Nos devuelve una lista asociativa con los nombres de las propiedades como claves, y los respectivos valores de las propiedades como elementos de la lista.</li>
<li><em>property_exists ($nombre_clase, $nombre_propiedad)</em> : Nos indica si la clase tiene la propiedad que buscamos</li>
<li><em>get_parent_class ($nombre_clase)</em> : Nos devuelve el nombre de la clase padre (si no hay clase padre, entonces devuelve una cadena vacía). También podemos usar objetos en este caso, no solo clases.</li>
<li><em>is_subclass_of ($nombre_clase, $nombre_clase_padre)</em> : Nos indica si la clase hereda de la clase padre, también podemos usar objetos en este caso, no solo clases.</li>
</ul>
<p style="text-align: justify;">Podemos hacer prácticamente lo mismo, pero con objetos:</p>
<ul style="text-align: justify;">
<li> <em>get_object_vars ($objeto)</em> : Se parece mucho a get_class_vars , pero se diferencia en que los valores de las propiedades de los objetos pueden variar en tiempo de ejecución, y además se pueden añadir propiedades también en tiempo de ejecución.</li>
<li>method_exists ($objeto, $nombre_metodo) : Nos indica si el objeto tiene o no un método concreto</li>
</ul>
<p style="text-align: justify;">Y aquí nos quedamos, más o menos eso es todo. Antes había ciertas funciones que completaban la parrilla y eran bastante útiles, que servían, básicamente, para hacer uso de callbacks o ejecutar métodos de forma &#8220;dinámica&#8221;, pero fueron marcadas como obsoletas a partir de la versión 4.1 de PHP, por lo que no las comentaré.  El hecho de que &#8220;falten&#8221; ciertas funciones nos podría obligar a agudizar el ingenio.. o a abusar de funciones como <em>eval</em> , pero por suerte, en PHP 5 se introdujo una nueva forma de trabajar.</p>
<h2>Introspección al estilo de PHP 5 ( clase Reflection )</h2>
<p style="text-align: justify;">En PHP 5 se introdujeron diversas mejoras, entre otras el tratamiento de errores se ha orientado más hacia el manejo de excepciones con bloques try-catch , y se han creado más clases que permiten trabajar de una forma mucho más orientada al paradigma de Orientación a Objetos, aumentando en cierta medida la cohesión del código resultante.</p>
<p style="text-align: justify;">Una de las clases que fueron introducidas en esta versión fue la clase Reflection (y algunas otras que derivan de ésta). Todas ellas, cuando se produce algún error, lo que hacen es lanzar una excepción, simplificando la gestión y evitando que tengamos que interpretar el significado de los valores de retorno. Estas son las clases de las que hablaremos (un poco por encima):</p>
<ul style="text-align: justify;">
<li style="text-align: justify;"><a href="http://www.php.net/manual/en/class.reflectionclass.php">ReflectionClass</a> : La usaremos para analizar las clases</li>
<li><a href="http://www.php.net/manual/en/class.reflectionobject.php">ReflectionObject</a> : La usaremos para analizar los objetos</li>
<li><a href="http://www.php.net/manual/en/class.reflectionproperty.php">ReflectionProperty</a> : La usaremos para analizar las propiedades de las clases</li>
<li><a href="http://www.php.net/manual/en/class.reflectionmethod.php">ReflectionMethod</a> : La usaremos para analizar los métodos de las clases</li>
<li><a href="http://www.php.net/manual/en/class.reflectionfunction.php">ReflectionFunction</a> : La usaremos para analizar las funciones</li>
<li><a href="http://www.php.net/manual/en/class.reflectionparameter.php">ReflectionParameter</a> : La usaremos para analizar los parámetros de los métodos y funciones</li>
</ul>
<p style="text-align: justify;">Para hacer introspección o reflexión lo que debemos es construir un objeto a partir de una de estas clases, usando como parámetro en el constructor aquello que queramos &#8220;ver por dentro&#8221;. Por ejemplo:</p>
<pre style="text-align: justify;">$metainformacion_clase = new ReflectionClass ("nombre_de_la_clase");</pre>
<p style="text-align: justify;">a partir de aquí contamos con un montón de métodos (muchos más que los que había disponibles en PHP 4) que nos servirán para conocer todo cuanto queramos sobre la susodicha clase. Podéis ver los métodos disponibles en los enlaces que he hecho para cada una de ellas. Es interesante comentar que, algunos métodos devuelven objetos que a su vez también sirven para aplicar introspección, como <em>getMethod ($name)</em> o <em>getProperty ($name)</em> , que devuelven sendos ReflectionMethod i ReflectionProperty.</p>
<p style="text-align: justify;">Uno de los métodos más interesantes de ReflectionMethod es el método <em>invoke ($object, $params)</em> , al cual le podemos pasar un objeto para el que queremos que se ejecute el método reflejado con los parámetros indicados. Esto sería &#8220;equivalente&#8221; a hacer la llamada (atentos, el ==== no es código, lo uso para indicar una cierta equivalencia):</p>
<pre>$metainformacion_metodo-&gt;invoke($object, $params); ====  $object-&gt;metodo_reflejado($params);</pre>
<p style="text-align: justify;">Con ésto no es que se pueda zanjar el asunto de la introspección o reflexión, pero hay poco más interesante por decir, casi todo lo demás es simplemente conocer los nombres de las funciones y aplicarlas, así pues, deberíamos pensar en cómo toda esta parafernalia nos puede resultar útil para crear un framework con PHP. Lo veremos en el siguiente artículo, que este ya es suficientemente largo.</p>
 <img src="http://blog.viricmind.org/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?view=1&post_id=695" width="1" height="1" style="display: none;" />]]></content:encoded>
			<wfw:commentRss>http://blog.viricmind.org/2010/08/11/creando-un-framework-con-php-ii-introspeccion/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Jugando con jQuery</title>
		<link>http://blog.viricmind.org/2010/02/08/jugando-con-jquery/</link>
		<comments>http://blog.viricmind.org/2010/02/08/jugando-con-jquery/#comments</comments>
		<pubDate>Mon, 08 Feb 2010 13:54:15 +0000</pubDate>
		<dc:creator>castarco</dc:creator>
				<category><![CDATA[desarrollo web]]></category>
		<category><![CDATA[internet]]></category>
		<category><![CDATA[jquery]]></category>
		<category><![CDATA[programación]]></category>

		<guid isPermaLink="false">http://blog.viricmind.org/?p=643</guid>
		<description><![CDATA[Por motivos varios estoy aprendiendo a manejar la librería jQuery, que sirve para dar dinamismo a páginas y aplicaciones web con una buena mezcla de Javascript, AJAX y CSS, y a modo de guinda, nos abstrae de las incompatibilidades entre navegadores. No voy a escribir una introducción a jQuery aquí porque todavía me falta bastante [...]]]></description>
			<content:encoded><![CDATA[<p>Por motivos varios estoy aprendiendo a manejar la librería<a href="http://es.wikipedia.org/wiki/JQuery"> jQuery</a>, que sirve para dar dinamismo a páginas y aplicaciones web con una buena mezcla de <a href="http://es.wikipedia.org/wiki/JavaScript">Javascript</a>, <a href="http://es.wikipedia.org/wiki/AJAX">AJAX</a> y <a href="http://es.wikipedia.org/wiki/Hojas_de_estilo_en_cascada">CSS</a>, y a modo de guinda, nos abstrae de las incompatibilidades entre navegadores. No voy a escribir una introducción a jQuery aquí porque todavía me falta bastante por aprender, pero sí os dejaré un enlace a una página repleta de &#8220;chuletas&#8221; sobre jQuery y librerías similares, como <a href="http://es.wikipedia.org/wiki/Prototype">Prototype</a>, <a href="http://script.aculo.us/">Scriptaculous</a> o <a href="http://mootools.net/">MooTools</a>.</p>
<p><a href="http://www.scottklarr.com/topic/95/javascriptajax-cheat-sheets/">http://www.scottklarr.com/topic/95/javascriptajax-cheat-sheets/</a></p>
<p>Personalmente la que más me gusta a mí es la de colorines xD, tengo muco de niño pequeño todavía. Saludos!</p>
 <img src="http://blog.viricmind.org/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?view=1&post_id=643" width="1" height="1" style="display: none;" />]]></content:encoded>
			<wfw:commentRss>http://blog.viricmind.org/2010/02/08/jugando-con-jquery/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Como mejorar el trabajo en equipo gracias a Gobby</title>
		<link>http://blog.viricmind.org/2009/12/03/como-mejorar-el-trabajo-en-equipo-gracias-a-gobby/</link>
		<comments>http://blog.viricmind.org/2009/12/03/como-mejorar-el-trabajo-en-equipo-gracias-a-gobby/#comments</comments>
		<pubDate>Thu, 03 Dec 2009 22:16:50 +0000</pubDate>
		<dc:creator>castarco</dc:creator>
				<category><![CDATA[internet]]></category>
		<category><![CDATA[programación]]></category>
		<category><![CDATA[software libre]]></category>

		<guid isPermaLink="false">http://blog.viricmind.org/?p=607</guid>
		<description><![CDATA[Ahora mismo estamos dando los retoques finales a las prácticas de la asignatura Gràfics per Computador I , dado que no disponemos de mucho tiempo para trabajar (pues tenemos muchas asignaturas y en todas hay muucho trabajo) preferimos programar toda la práctica con Python y python-opengl por encima de lenguajes más eficientes como C o [...]]]></description>
			<content:encoded><![CDATA[<p style="text-align: justify;">Ahora mismo estamos dando los retoques finales a las prácticas de la asignatura <em>Gràfics per Computador I</em> , dado que no disponemos de mucho tiempo para trabajar (pues tenemos muchas asignaturas y en todas hay muucho trabajo) preferimos programar toda la práctica con Python y python-opengl por encima de lenguajes más eficientes como C o C++. Obviamente el rendimiento ha mermado de forma impresionante si lo comparamos con lo que hubiéramos obtenido haciéndolo con los otros lenguajes mencionados&#8230; pero nos da absolutamente igual, simplemente tenemos que demostrar que sabemos hacer lo que nos han pedido, no es nada que tenga que entrar en producción.</p>
<p style="text-align: justify;">El caso es que cuando digo lo de poco tiempo lo digo con todas las de la ley, tan poco que no hemos podido encontrar ningún hueco para coincidir en persona, así que hemos tenido que optar por trabajar a distancia con casi todo lo que eso comporta normalmente. Y digo con casi todo porque en este caso <a href="http://gobby.0x539.de/trac/">Gobby</a> nos ha puesto las cosas fáciles <img src='http://blog.viricmind.org/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' />  . Gracias a este programa podemos editar documentos simultániamente (viendo los cambios en tiempo real, omitiendo el pequeño retardo claro) mientras podemos charlar y comentar los cambios a través del chat integrado.</p>
<p style="text-align: justify;">Su sistema de funcionamiento es sencillo, uno de los que participa en el proceso de edición de los documentos inicia una sesión, lo que viene a significar que crea la instancia de un servidor al que otros se pueden conectar, los demás se conectan.. y listos <img src='http://blog.viricmind.org/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' />   (se pueden establecer claves de acceso por si se quieren grupos cerrados <img src='http://blog.viricmind.org/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' />  ). Por otro lado, por el momento solo se puede trabajar con ficheros de texto plano, así que para ciertas tareas está un poco limitadito. Habría que ver si se quiere &#8220;mejorar&#8221; ese aspecto o si ya se diseñó el programa con la idea de que funcionara tal y como funciona para no hacer nada más en un futuro. Sea como sea, ya sabéis, si os interesa podéis intentar añadir funcionalidad al programa y me haréis un favor xD&#8230; y si no, talvez un día me ponga a ver si puedo hacer algo yo con mis propias manos <img src='http://blog.viricmind.org/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' />  .</p>
<p style="text-align: justify;">Saludos! (Voy a seguir con la práctica&#8230; )</p>
<p style="text-align: justify;">P.D.: Para los KDE-adictos (aunque cada vez quedan menos gracias a las regresiones de KDE4) hay un programa que realiza la misma función que Gobby (y puede interactuar con éste) que se llama Kobby, aun está en fase de desarrollo, pero seguro que a los aventureros eso no os asusta. Lo podéis encontrar en <a href="http://greghaynes.github.com/kobby/">http://greghaynes.github.com/kobby/</a> .</p>
 <img src="http://blog.viricmind.org/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?view=1&post_id=607" width="1" height="1" style="display: none;" />]]></content:encoded>
			<wfw:commentRss>http://blog.viricmind.org/2009/12/03/como-mejorar-el-trabajo-en-equipo-gracias-a-gobby/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Bucles rápidos en Python</title>
		<link>http://blog.viricmind.org/2009/11/18/bucles-rapidos-en-python/</link>
		<comments>http://blog.viricmind.org/2009/11/18/bucles-rapidos-en-python/#comments</comments>
		<pubDate>Wed, 18 Nov 2009 20:56:39 +0000</pubDate>
		<dc:creator>castarco</dc:creator>
				<category><![CDATA[programación]]></category>
		<category><![CDATA[python]]></category>

		<guid isPermaLink="false">http://blog.viricmind.org/?p=559</guid>
		<description><![CDATA[Como algunos habréis notado, siento cierta afición por Python. Ésto es así porque programar en Python es (por lo general) mucho más divertido que programar con la mayoría de lenguajes existentes. Aún así tengo ciertos problemas de conciencia al respecto, Python es un lenguaje interpretado y eso se nota en el rendimiento de los programas [...]]]></description>
			<content:encoded><![CDATA[<p style="text-align: justify;">Como algunos habréis notado, siento cierta afición por <a href="http://es.wikipedia.org/wiki/Python">Python</a>. Ésto es así porque programar en Python es (por lo general) mucho más divertido que programar con la mayoría de lenguajes existentes. Aún así tengo ciertos problemas de conciencia al respecto, Python es un <a href="http://es.wikipedia.org/wiki/Lenguaje_de_programación_interpretado">lenguaje interpretado</a> y eso se nota en el rendimiento de los programas que se hacen con él. Yo recomendaría Python para algunas cosas muy concretas: aprendizaje, prototipado, usarlo como &#8220;<a href="http://es.wikipedia.org/wiki/Lenguaje_pegamento">lenguaje pegamento</a>&#8221; para unir programas o librerías hechas en otros lenguajes más eficientes, o por último, como lenguaje de scripting del sistema (mucho mejor que <a href="http://es.wikipedia.org/wiki/Bash">Bash</a> o <a href="http://es.wikipedia.org/wiki/C_Shell">Csh</a>).</p>
<p style="text-align: justify;">Aun así, puede darse el caso de que nos dé la gana de hacer una aplicación de uso común en la que sería deseable que el rendimiento fuera bueno, lo que no será posible si no conocemos algunos detalles de Python. Hoy comentaré como hacer bucles lo más rápidos posible.</p>
<p style="text-align: justify;">En principio tenemos 2 formas de crear bucles en Python, con el bucle <em>for</em> y con el bucle <em>while</em>. El bucle <em>for</em> ejecuta un bloque de código por cada elemento de un objeto iterable.</p>
<pre lang="python">L = [1 2 3 4]
for i in L:
  accion(i)
</pre>
<p style="text-align: justify;">Mientras que el bucle <em>while</em> ejecuta un trozo de código mientras se cumpla una condición concreta:</p>
<pre lang="python">i = 1
while i <= 4:
  accion(i)
  i += 1</pre>
<p style="text-align: justify;">Los objetos iterables pueden ser de muchos tipos, pueden ser listas (que consumen memoria por cada uno de sus elementos) o pueden ser también generadores, objetos que devuelven un elemento nuevo cada vez que se llama a su método <em>__iter__</em>, también se pueden crear métodos generadores que actúan como objetos iterables. Así que podemos crear un método que hará algo parecido a la función <em>range</em>:</p>
<pre lang="python">def generador(n):
  i = 0
  while i < n:
    yield i
    i += 1</pre>
<p style="text-align: justify;">Que podemos usar en un bucle:</p>
<pre lang="python">  for i in generador(5):
    print i</pre>
<p style="text-align: justify;"><strong>Nota:</strong> <em>por si alguien no sabe lo que hace la función <strong>range</strong>, crea una lista de <strong>0</strong> a <strong>n</strong> y la devuelve (donde <strong>n</strong> es el parámetro que se le pasa). </em></p>
<p style="text-align: justify;">¿Qué ventajas tienen los generadores sobre la función <em>range</em>? Pues para empezar, no consumen tanta memoria, no hace falta crear un array de <em>n</em> elementos para hacer un bucle con <em>n</em> iteraciones. Aun así, si experimentamos con nuestros generadores y comparamos tiempos de ejecución veremos que la función <em>range</em> funciona significativamente más rápida. La razón es que está programada internamente en <a href="http://es.wikipedia.org/wiki/Lenguaje_de_programación_C">C</a> y nuestro generador está programado en Python.</p>
<p style="text-align: justify;">Ésto nos puede hacer pensar que la mejor alternativa, entonces, es usar un bucle <em>while</em> (aunque sea más feo) ya que evitaremos la sobrecarga de llamar a una función, no gastaremos tanta memoria como con <em>range</em> y sólo haremos una comparación al principio y una suma al final de cada iteración. Pero... nos equivocaríamos otra vez. Resulta que la función <em>range</em> da mejores resultados que el típico bucle <em>while</em> en cuanto a tiempo, la razón, otra vez, es que está programada internamente en C. De hecho es esperable que si el array creado por <em>range</em> fuera lo suficientemente grande, los resultados cambiaran (porque se tendría que recurrir a la <a href="http://es.wikipedia.org/wiki/Memoria_virtual">memoria virtual</a> y habría fallos de página), pero para que eso se dé hacen falta muuchas iteraciones, sobretodo ahora, cuando tenemos tanta <a href="http://es.wikipedia.org/wiki/Memoria_de_acceso_aleatorio">memoria RAM</a>.</p>
<p style="text-align: justify;">Después de todo, podemos acabar un poco desanimados, pues no hemos visto ninguna solución que nos aporte todo lo que queremos. Pero está ahí <img src='http://blog.viricmind.org/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' />  , y se llama <em>xrange</em>. Funciona de manera análoga a la función <em>range</em>, sólo que en vez de devolvernos un array lo que hace es devolvernos un generador sobre el que podrá iterar el bucle <em>for</em> de forma elegante y aprovechando el rendimiento de C (pues está programada internamente en C). Así pues, la manera más eficiente de hacer un bucle viene a ser algo como ésto:</p>
<pre lang="python">for i in xrange(5):
  print i</pre>
<p style="text-align: justify;">No pongo aquí los tiempos porque haría demasiado largo el artículo y lo podéis calcular vosotros mismos de forma fácil con el comando <em>time</em> de UNIX. Saludos!</p>
 <img src="http://blog.viricmind.org/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?view=1&post_id=559" width="1" height="1" style="display: none;" />]]></content:encoded>
			<wfw:commentRss>http://blog.viricmind.org/2009/11/18/bucles-rapidos-en-python/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>PdfMod 0.8 publicado</title>
		<link>http://blog.viricmind.org/2009/11/12/pdfmod-0-8-publicado/</link>
		<comments>http://blog.viricmind.org/2009/11/12/pdfmod-0-8-publicado/#comments</comments>
		<pubDate>Thu, 12 Nov 2009 08:37:13 +0000</pubDate>
		<dc:creator>castarco</dc:creator>
				<category><![CDATA[pdf]]></category>
		<category><![CDATA[pdfmod]]></category>
		<category><![CDATA[programación]]></category>
		<category><![CDATA[software]]></category>
		<category><![CDATA[software libre]]></category>

		<guid isPermaLink="false">http://blog.viricmind.org/?p=548</guid>
		<description><![CDATA[Por fin se ha liberado la nueva versión 0.8 de PdfMod, hace tiempo que no se realizaba ningún cambio en el proyecto y ya iba siendo hora que los cambios realizados a finales de Septiembre y principios de Octubre se publicaran bajo una nueva versión . Parece ser que se han añadido a última hora [...]]]></description>
			<content:encoded><![CDATA[<p style="text-align: justify;">Por fin se ha liberado la nueva versión 0.8 de <a href="http://live.gnome.org/PdfMod">PdfMod</a>, hace tiempo que no se realizaba ningún cambio en el proyecto y ya iba siendo hora que los cambios realizados a finales de Septiembre y principios de Octubre se publicaran bajo una nueva versión <img src='http://blog.viricmind.org/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> . Parece ser que se han añadido a última hora mejoras en el estilo del código, pero hay que decir que eso no tiene repercusión alguna para el usuario final, al menos no en esta versión, puede que en versiones futuras facilite la programación y se acelere el trabajo.</p>
<p style="text-align: justify;">Como en otras versiones, los que hemos colaborado somos unos cuantos, principalmente se han añadido traducciones, se ha añadido la posibilidad de cargar más de un documento a la vez a través del diálogo de fichero y se ha mejorado levemente la usabilidad, asociando la combinación Ctrl-Shift-Z a &#8220;rehacer&#8221; y añadiendo un asterisco al nombre de fichero mostrado cada vez que tenga modificaciones no guardadas.</p>
<p style="text-align: justify;">Podéis ver el changelog en esta dirección: <a href="http://git.gnome.org/cgit/pdfmod/plain/NEWS">http://git.gnome.org/cgit/pdfmod/plain/NEWS</a> y el anuncio oficial de Gabriel Burt en su blog: <a href="http://gburt.blogspot.com/2009/11/pdf-mod-08.html">http://gburt.blogspot.com/2009/11/pdf-mod-08.html</a> .</p>
 <img src="http://blog.viricmind.org/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?view=1&post_id=548" width="1" height="1" style="display: none;" />]]></content:encoded>
			<wfw:commentRss>http://blog.viricmind.org/2009/11/12/pdfmod-0-8-publicado/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Wt : C++ Webtoolkit, un gran descubrimiento</title>
		<link>http://blog.viricmind.org/2009/09/19/wt-c-webtoolkit-un-gran-descubrimiento/</link>
		<comments>http://blog.viricmind.org/2009/09/19/wt-c-webtoolkit-un-gran-descubrimiento/#comments</comments>
		<pubDate>Sat, 19 Sep 2009 22:27:24 +0000</pubDate>
		<dc:creator>castarco</dc:creator>
				<category><![CDATA[C/C++]]></category>
		<category><![CDATA[internet]]></category>
		<category><![CDATA[programación]]></category>

		<guid isPermaLink="false">http://blog.viricmind.org/?p=511</guid>
		<description><![CDATA[Hoy he descubierto a través del planet de gnome ( planet.gnome.org -&#62; http://jaap.haitsma.org/ -&#62; Make AJAX Web Applications with C++ ) las librerías Wt (Webtoolkit) que permiten crear aplicaciones web AJAX con el lenguaje de programación C++. Me ha resultado muy interesante porque la velocidad de ejecución de C++ es mucho mayor que la de [...]]]></description>
			<content:encoded><![CDATA[<p style="text-align: justify;">Hoy he descubierto a través del planet de gnome ( <a href="http://planet.gnome.org">planet.gnome.org</a> -&gt; <a href="http://jaap.haitsma.org/">http://jaap.haitsma.org/</a> -&gt; <a href="http://jaap.haitsma.org/2009/09/19/make-ajax-web-applications-with-c/">Make AJAX Web Applications with C++</a> ) las librerías Wt (<a href="http://www.webtoolkit.eu">Webtoolkit</a>) que permiten crear aplicaciones web <a href="http://es.wikipedia.org/wiki/AJAX">AJAX</a> con el lenguaje de programación <a href="http://es.wikipedia.org/wiki/C++">C++</a>. Me ha resultado muy interesante porque la velocidad de ejecución de C++ es mucho mayor que la de la mayoría de lenguajes interpretados, ya sea con simples intérpretes, con bytecodes o incluso con <a href="http://es.wikipedia.org/wiki/Compilación_JIT">JIT</a>s, hay que añadir que el consumo de memoria también acostumbra a ser inferior. Otras ventajas podrían ser la facildad para usar casi cualquier librería imaginable</p>
<p style="text-align: justify;">Por otro lado tenemos que considerar los inconvenientes: el manejo de memoria con sus punteros, la asignación y la liberación de memoria puede resultar un engorro. Y no solo eso, la sintaxis de C++ es mucho más compleja de lo que puede ser la de <a href="http://es.wikipedia.org/wiki/Python">Python</a>, <a href="http://es.wikipedia.org/wiki/Ruby">Ruby</a>, <a href="http://es.wikipedia.org/wiki/C_Sharp">C#</a>, <a href="http://es.wikipedia.org/wiki/PHP">PHP</a> u otros lenguajes más modernos, hay que tener verdadera paciencia con él.</p>
<p style="text-align: justify;">Voy a ver que tal es trabajar con ella, ya os diré algo <img src='http://blog.viricmind.org/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' />  , pero parece que promete.</p>
<h2 style="text-align: justify;">Referencias</h2>
<ul>
<li>(Minitutorial) <a href="http://www.ddj.com/cpp/206401952">http://www.ddj.com/cpp/206401952</a></li>
</ul>
 <img src="http://blog.viricmind.org/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?view=1&post_id=511" width="1" height="1" style="display: none;" />]]></content:encoded>
			<wfw:commentRss>http://blog.viricmind.org/2009/09/19/wt-c-webtoolkit-un-gran-descubrimiento/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Java: String vs StringBuffer vs StringBuilder</title>
		<link>http://blog.viricmind.org/2009/09/11/java-string-vs-stringbuffer-vs-stringbuilder/</link>
		<comments>http://blog.viricmind.org/2009/09/11/java-string-vs-stringbuffer-vs-stringbuilder/#comments</comments>
		<pubDate>Fri, 11 Sep 2009 12:58:22 +0000</pubDate>
		<dc:creator>castarco</dc:creator>
				<category><![CDATA[java]]></category>
		<category><![CDATA[programación]]></category>

		<guid isPermaLink="false">http://blog.viricmind.org/?p=491</guid>
		<description><![CDATA[Actualmente trabajo de becario (programador) modificando algunos programas escritos en Java (que funcionarán sobre OpenJDK) y debido a las tareas que me encargan me acabé preguntando sobre el rendimiento en el tratamiento de cadenas. Buscando por internet encontré este artículo [1] que aclaró bastante las cosas. Yo lo voy a reescribir aquí por si algún [...]]]></description>
			<content:encoded><![CDATA[<p style="text-align: justify;">Actualmente trabajo de becario (programador) modificando algunos programas escritos en <a href="http://es.wikipedia.org/wiki/Lenguaje_de_programación_Java">Java</a> (que funcionarán sobre <a href="http://es.wikipedia.org/wiki/OpenJDK">OpenJDK</a>) y debido a las tareas que me encargan me acabé preguntando sobre el rendimiento en el tratamiento de cadenas. Buscando por internet encontré este artículo [1] que aclaró bastante las cosas. Yo lo voy a reescribir aquí por si algún día desaparece ese artículo, además voy a fijarme en algún otro aspecto no comentado allí.</p>
<p style="text-align: justify;">En Java podemos encontrar tres clases diferentes que nos permiten trabajar con cadenas, la archiconocida <em>String</em>, <em>StringBuffer</em> y <em>StringBuilder</em>. Debido a que los objetos <em>String</em> son inmutables, cada vez que se hace una concatenación con el operador <strong>+</strong> se debe crear un nuevo objeto que albergue el resultado (y en caso de que las cadenas anteriores no esten referenciadas, eliminar los objetos correspondientes). Por eso también existe la clase <em>StringBuffer</em> que nos permite añadir a la cadena que contiene otras cadenas con su método <em>append</em> sin tener que construir ni destruir ningún objeto. Con ello se consigue una mejora de rendimiento considerable cuando se hacen muchas concatenaciones, luego si se quiere trabajar con un objeto String solo tenemos que usar el método <em>toString</em> y listos.</p>
<p style="text-align: justify;">La clase <em>StringBuffer</em> está diseñada para ser segura en un entorno concurrente, por lo que tiene código extra para gestionar los bloqueos y demás. Esta característica no siempre nos es útil y puede hacer decrecer el rendimiento en demasía, por lo que también se creó la clase <em>StringBuilder</em> que no es segura para operaciones concurrentes pero puede ser el doble de rápida que <em>StringBuffer</em> (además, casi siempre que trabajamos con cadenas es de forma no concurrente).</p>
<p style="text-align: justify;">Tanto StringBuffer como StringBuilder escalan linealmente a medida que aumentamos el número de concatenaciones, no siendo así en el caso de la clase String que parece mostrar un incremento supralineal en el consumo de recursos. Aquí os dejo las tablas de resultados, para String no están completas porque tardaba demasiado y me he cansado.</p>
<pre>run:
StringBuffer (100): 0
StringBuffer (1000): 3
StringBuffer (10000): 19
StringBuffer (100000): 13
StringBuffer (1000000): 75
StringBuffer (10000000): 642
StringBuffer (50000000): 2738

StringBuilder (100): 0
StringBuilder (1000): 0
StringBuilder (10000): 4
StringBuilder (100000): 70
StringBuilder (1000000): 32
StringBuilder (10000000): 342
StringBuilder (50000000): 1706

String (100): 1
String (1000): 67
String (10000): 777
String (100000): 80040</pre>
<p style="text-align: justify;">Los números indican la cantidad de milisegundos consumidos para la cantidad indicada de concatenaciones. El código que he usado es éste:</p>
<pre lang="Java">
public static void main(String[] args) {
        // StringBuffer
        System.out.println("StringBuffer (100): "+cSBuffer(100));
        System.out.println("StringBuffer (1000): "+cSBuffer(1000));
        System.out.println("StringBuffer (10000): "+cSBuffer(10000));
        System.out.println("StringBuffer (100000): "+cSBuffer(100000));
        System.out.println("StringBuffer (1000000): "+cSBuffer(1000000));
        System.out.println("StringBuffer (10000000): "+cSBuffer(10000000));
        System.out.println("StringBuffer (50000000): "+cSBuffer(50000000));
        // END StringBuffer

        System.out.println();

        // StringBuilder
        System.out.println("StringBuilder (100): "+cSBuilder(100));
        System.out.println("StringBuilder (1000): "+cSBuilder(1000));
        System.out.println("StringBuilder (10000): "+cSBuilder(10000));
        System.out.println("StringBuilder (100000): "+cSBuilder(100000));
        System.out.println("StringBuilder (1000000): "+cSBuilder(1000000));
        System.out.println("StringBuilder (10000000): "+cSBuilder(10000000));
        System.out.println("StringBuilder (50000000): "+cSBuilder(50000000));
        // END StringBuilder

        System.out.println();

        // StringBuilder
        System.out.println("String (100): "+cS(100));
        System.out.println("String (1000): "+cS(1000));
        System.out.println("String (10000): "+cS(10000));
        System.out.println("String (100000): "+cS(100000));
        System.out.println("String (1000000): "+cS(1000000));
        System.out.println("String (10000000): "+cS(10000000));
        System.out.println("String (50000000): "+cS(50000000));
        // END StringBuilder
    }

    static private long cSBuffer(long num)
    {
        long ini = System.currentTimeMillis();

        StringBuffer sbuffer = new StringBuffer();

        for(int i=0; i<num ; i++)
        {
            sbuffer.append("abc");
        }

        long fin = System.currentTimeMillis();

        return fin-ini;
    }

    static private long cSBuilder(long num)
    {
        long ini = System.currentTimeMillis();

        StringBuilder sbuffer = new StringBuilder();

        for(int i=0; i<num; i++)
        {
            sbuffer.append("abc");
        }

        long fin = System.currentTimeMillis();

        return fin-ini;
    }

    static private long cS(long num)
    {
        long ini = System.currentTimeMillis();

        String sbuffer = "";

        for(int i=0; i<num; i++)
        {
            sbuffer += "abc";
        }

        long fin = System.currentTimeMillis();

        return fin-ini;
    }
</pre>
<p style="text-align: justify;">Por cierto, y esto tiene poco que ver con lo de las clases. Lo he probado con <a href="http://es.wikipedia.org/wiki/IKVM.NET">IKVM</a> también... y bueno, tengo que decir que va el doble de lento que con OpenJDK (no lo he probado con la máquina Hotspot de Sun).</p>
<h2 style="text-align: justify;">Referencias</h2>
<ol>
<li><a href="http://www.dosideas.com/java/339-string-vs-stringbuffer-vs-stringbuilder.html">http://www.dosideas.com/java/339-string-vs-stringbuffer-vs-stringbuilder.html</a></li>
</ol>
<p></num></pre>
 <img src="http://blog.viricmind.org/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?view=1&post_id=491" width="1" height="1" style="display: none;" />]]></content:encoded>
			<wfw:commentRss>http://blog.viricmind.org/2009/09/11/java-string-vs-stringbuffer-vs-stringbuilder/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Python Bytecode Disassembler ( dis )</title>
		<link>http://blog.viricmind.org/2009/08/26/python-bytecode-disassembler-dis/</link>
		<comments>http://blog.viricmind.org/2009/08/26/python-bytecode-disassembler-dis/#comments</comments>
		<pubDate>Wed, 26 Aug 2009 12:36:06 +0000</pubDate>
		<dc:creator>castarco</dc:creator>
				<category><![CDATA[programación]]></category>
		<category><![CDATA[python]]></category>

		<guid isPermaLink="false">http://blog.viricmind.org/?p=440</guid>
		<description><![CDATA[El artículo que sigue es una traducción de un artículo escrito en la página web Python Module of the Week, que es una especie de recopilatorio de artículos sobre módulos de Python escritos por Doug Hellman. Sus textos se publican bajo la licencia Creative Commons By-Nc-Sa ( como los míos, por si alguien no lo [...]]]></description>
			<content:encoded><![CDATA[<p style="text-align: justify;">El artículo que sigue es una traducción de un artículo escrito en la página web <a href="http://www.doughellmann.com/PyMOTW/">Python Module of the Week</a>, que es una especie de recopilatorio de artículos sobre módulos de Python escritos por Doug Hellman. Sus textos se publican bajo la licencia <a href="http://creativecommons.org/">Creative Commons</a> <a href="http://creativecommons.org/licenses/by-nc-sa/3.0/es/">By-Nc-Sa</a> ( como los míos, por si alguien no lo había notado todavía con el logo de la página ).</p>
<h3 style="text-align: justify;">Python Bytecode Disassembler ( dis )</h3>
<p style="text-align: justify;">El módulo que trataremos se llama <em>dis</em> y su principal utilidad es convertir código objeto a una representación de bytecode que sea entendible para los seres humanos (o almenos para aquellos que hayan perdido un poco de su tiempo en intentar entender éstas cosas). Éste texto está indicado para versiones de Python iguales o superiores a la versión 1.4, por lo que no tendréis ningún problema (ahora todo el casi mundo usa versiones iguales o superiores a la 2.4).</p>
<p style="text-align: justify;">El módulo <em>dis</em> incluye funciones para <a href="http://es.wikipedia.org/wiki/Desensamblador">desensamblar</a> <a href="http://es.wikipedia.org/wiki/Bytecode">bytecode</a> de Python (que se genera durante la interpretación del código para acelerar el funcionamiento de los scripts).Observar el código bytecode ejecutado por el <a href="http://es.wikipedia.org/wiki/Intérprete_(informática)">intérprete</a> es una buena forma de optimizar a mano bucles y otras secuencias de código. También es útil para encontrar condiciones de carrera en aplicaciones <a href="http://es.wikipedia.org/wiki/Hilo_de_ejecución">multihilo</a> ya que mirando el bytecode se puede ver en qué &#8220;momento&#8221; es más probable que haya un cambio de hilo.</p>
<h2 style="text-align: justify;">Desensamblado básico</h2>
<p>La función <code>dis.dis()</code> muestra por pantalla la representación del desensamblado de código fuente Python (módulo, clase, método, función, o código objeto). Podemos desensamblar código como el siguiente:</p>
<pre lang="python">#!/usr/bin/env python
# encoding: utf-8

my_dict = { 'a':1 }</pre>
<p>ejecutando dis desde la línea de comandos. La salida está organizada en columnas con el número de línea original del código fuente, la “dirección” dentro del código objeto, el nombre de <a href="http://es.wikipedia.org/wiki/Opcode">opcode</a> y los argumentos pasados al opcode.</p>
<pre>$ python -m dis codigo.py
  4           0 BUILD_MAP                1
              3 LOAD_CONST               0 (1)
              6 LOAD_CONST               1 ('a')
              9 STORE_MAP
             10 STORE_NAME               0 (my_dict)
             13 LOAD_CONST               2 (None)
             16 RETURN_VALUE</pre>
<p style="text-align: justify;">En este caso el código se traduce a 5 operaciones para inicializar el diccionario (crearlo y llenarlo), luego guarda los resultados en una variable global. Como el intérprete de Python está basado en un esquema de pila, los primeros pasos consisten en poner las constantes en la pila siguiendo el orden correcto con la operación <code>LOAD_CONST</code>, y luego usar <code>STORE_MAP</code> para sacar la clave y el valor que se añadirán al diccionario (no nos olvidemos de que antes se ha hecho la operación <code>BUILD_MAP</code>, los valores añadidos entre la ejecución de <code>BUILD_MAP</code> y <code>STORE_MAP</code> serán las claves y los valores del diccionario que estamos creando). El objeto resultante se enlaza con el nombre &#8220;my_dict&#8221; con la operación <code>STORE_NAME</code>.</p>
<h2 style="text-align: justify;">Desensamblando funciones</h2>
<p style="text-align: justify;">Desafortunadamente desensamblar el módulo entero no lo hace con las funciones que hay en él automáticamente. Por ejemplo, si desensamblamos éste módulo:</p>
<pre lang="python">#!/usr/bin/env python
# encoding: utf-8

def f(*args):
    nargs = len(args)
    print nargs, args

if __name__ == '__main__':
    import dis
    dis.dis(f)</pre>
<p style="text-align: justify;">los resultados muestran como se carga el código objeto en la pila y luego se salta dentro de la función (LOAD_CONST, MAKE_FUNCTION), pero el cuerpo de la función <em>no</em> está.</p>
<pre>$ python -m dis dis_function.py
  4           0 LOAD_CONST               0 (<code>)
              3 MAKE_FUNCTION            0
              6 STORE_NAME               0 (f)

  8           9 LOAD_NAME                1 (__name__)
             12 LOAD_CONST               1 ('__main__')
             15 COMPARE_OP               2 (==)
             18 JUMP_IF_FALSE           29 (to 50)
             21 POP_TOP

  9          22 LOAD_CONST               2 (-1)
             25 LOAD_CONST               3 (None)
             28 IMPORT_NAME              2 (dis)
             31 STORE_NAME               2 (dis)

 10          34 LOAD_NAME                2 (dis)
             37 LOAD_ATTR                2 (dis)
             40 LOAD_NAME                0 (f)
             43 CALL_FUNCTION            1
             46 POP_TOP
             47 JUMP_FORWARD             1 (to 51)
        &gt;&gt;   50 POP_TOP
        &gt;&gt;   51 LOAD_CONST               3 (None)
             54 RETURN_VALUE
</code></pre>
<p style="text-align: justify;">Para ver dentro de la función tenemos que pasarla como argumento a <code>dis.dis()</code>.</p>
<pre>$ python dis_function.py
  5           0 LOAD_GLOBAL              0 (len)
              3 LOAD_FAST                0 (args)
              6 CALL_FUNCTION            1
              9 STORE_FAST               1 (nargs)

  6          12 LOAD_FAST                1 (nargs)
             15 PRINT_ITEM
             16 LOAD_FAST                0 (args)
             19 PRINT_ITEM
             20 PRINT_NEWLINE
             21 LOAD_CONST               0 (None)
             24 RETURN_VALUE</pre>
<h2 style="text-align: justify;">Clases</h2>
<p style="text-align: justify;">Se pueden pasar también clases a la función <code>dis</code>, en este caso todos sus métodos son desensamblados a la vez.</p>
<pre lang="python">#!/usr/bin/env python
# encoding: utf-8

import dis

class MyObject(object):
    """Example for dis."""

    CLASS_ATTRIBUTE = 'some value'

    def __init__(self, name):
        self.name = name

    def __str__(self):
        return 'MyObject(%s)' % self.name

dis.dis(MyObject)</pre>
<pre style="text-align: left;">$ python dis_class.py
Disassembly of __init__:
 12           0 LOAD_FAST                1 (name)
              3 LOAD_FAST                0 (self)
              6 STORE_ATTR               0 (name)
              9 LOAD_CONST               0 (None)
             12 RETURN_VALUE

Disassembly of __str__:
 15           0 LOAD_CONST               1 ('MyObject(%s)')
              3 LOAD_FAST                0 (self)
              6 LOAD_ATTR                0 (name)
              9 BINARY_MODULO
             10 RETURN_VALUE</pre>
<h2 style="text-align: left;">Desensamblando para debuggear</h2>
<p style="text-align: justify;">A veces puede ser útil ver qué bytecode causó el problema cuando se está debuggeando una excepción.  Hay un par de formas de desensamblar el código que encierra el error.</p>
<p style="text-align: justify;">La primera forma consiste en usar <code>dis.dis()</code> dentro del intérprete interactivo para que analize la última excepción ocurrida. Si no se le pasa ningún argumento a <code>dis</code>, ésta busca la última excepción ocurrida y muestra el desensamblado de la parte &#8220;más alta&#8221; de la pila que la causó.</p>
<pre>$ python
Python 2.6.2 (r262:71600, Apr 16 2009, 09:17:39)
[GCC 4.0.1 (Apple Computer, Inc. build 5250)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
&gt;&gt;&gt; import dis
&gt;&gt;&gt; j = 4
&gt;&gt;&gt; i = i + 4
Traceback (most recent call last):
  File "", line 1, in
NameError: name 'i' is not defined
&gt;&gt;&gt; dis.distb()
  1 --&gt;       0 LOAD_NAME                0 (i)
              3 LOAD_CONST               0 (4)
              6 BINARY_ADD
              7 STORE_NAME               0 (i)
             10 LOAD_CONST               1 (None)
             13 RETURN_VALUE
&gt;&gt;&gt;</pre>
<p style="text-align: justify;">Notad la flecha <code>--&gt;</code> indicando el opcode que causó el error. La variable “i” no está definida, por lo que el valor asociado con el nombre no puede ser cargado en la pila.</p>
<p style="text-align: justify;">Desde tu propio código puedes mostrar por pantalla información sobre el <em>traceback</em> pasándolodirectamente como argumento a dis.distb(). En este ejemplo hay una excepción DivideByZero, pero como la fórmula tiene dos partes, no está claro cual de los elementos es el cero.</p>
<pre style="text-align: justify;" lang="python">#!/usr/bin/env python
# encoding: utf-8

i = 1
j = 0
k = 3

# ... many lines removed ...

try:
    result = k * (i / j) + (i / k)
except:
    import dis
    import sys
    exc_type, exc_value, exc_tb = sys.exc_info()
    dis.distb(exc_tb)</pre>
<p style="text-align: justify;">El valor incorrecto es fácil de detectar cuando está cargado en la pila dentro del desensamblado. La operación incorrecta está remarcada con la flecha <code>--&gt;</code>, y sólo tenemos que mirar unas cuantas líneas hacia arriba para encontrar dónde se ha cargado el valor 0 en la pila.</p>
<pre>$ python dis_traceback.py
  4           0 LOAD_CONST               0 (1)
              3 STORE_NAME               0 (i)

  5           6 LOAD_CONST               1 (0)
              9 STORE_NAME               1 (j)

  6          12 LOAD_CONST               2 (3)
             15 STORE_NAME               2 (k)

 10          18 SETUP_EXCEPT            26 (to 47)

 11          21 LOAD_NAME                2 (k)
             24 LOAD_NAME                0 (i)
             27 LOAD_NAME                1 (j)
    --&gt;      30 BINARY_DIVIDE
             31 BINARY_MULTIPLY
             32 LOAD_NAME                0 (i)
             35 LOAD_NAME                2 (k)
             38 BINARY_DIVIDE
             39 BINARY_ADD
             40 STORE_NAME               3 (result)
             43 POP_BLOCK
             44 JUMP_FORWARD            65 (to 112)

 12     &gt;&gt;   47 POP_TOP
             48 POP_TOP
             49 POP_TOP

 13          50 LOAD_CONST               3 (-1)
             53 LOAD_CONST               4 (None)
             56 IMPORT_NAME              4 (dis)
             59 STORE_NAME               4 (dis)

 14          62 LOAD_CONST               3 (-1)
             65 LOAD_CONST               4 (None)
             68 IMPORT_NAME              5 (sys)
             71 STORE_NAME               5 (sys)

 15          74 LOAD_NAME                5 (sys)
             77 LOAD_ATTR                6 (exc_info)
             80 CALL_FUNCTION            0
             83 UNPACK_SEQUENCE          3
             86 STORE_NAME               7 (exc_type)
             89 STORE_NAME               8 (exc_value)
             92 STORE_NAME               9 (exc_tb)

 16          95 LOAD_NAME                4 (dis)
             98 LOAD_ATTR               10 (distb)
            101 LOAD_NAME                9 (exc_tb)
            104 CALL_FUNCTION            1
            107 POP_TOP
            108 JUMP_FORWARD             1 (to 112)
            111 END_FINALLY
        &gt;&gt;  112 LOAD_CONST               4 (None)
            115 RETURN_VALUE</pre>
<h2 style="text-align: justify;">Análisis de rendimiento en bucles</h2>
<p style="text-align: justify;">Además de para localizar errores, <em>dis</em> también puede ayudar a encontrar problemas de rendimiento en nuestro código. Examinar el código desensamblado es especialmente útil con pequeños bucles en los que el número de líneas de código Python es pequeño pero éstas se  ejecutan lentamente ya que se traducen a un conjunto ineficiente de bytecodes. Veremos como el desensamblado nos ayuda a examinar unas pocas implementaciones de una clase, <em>Dictionary</em>, que lee un conjunto de palabras y las agrupa por su primera letra.</p>
<p>Antes de nada, la aplicación que usaremos para hacer los tests:</p>
<pre lang="python">import dis
import sys
import timeit

module_name = sys.argv[1]
module = __import__(module_name)
Dictionary = module.Dictionary

dis.dis(Dictionary.load_data)
print
t = timeit.Timer(
    'd = Dictionary(words)',
    """from %(module_name)s import Dictionary
words = [l.strip() for l in open('/usr/share/dict/words', 'rt')]
    """ % locals()
    )
iterations = 10
print 'TIME: %0.4f' % (t.timeit(iterations)/iterations)</pre>
<p style="text-align: justify;">Podemos usar <em>dis_test_loop.py</em> para ejecutar cada versión de la clase <em>Dictionary</em> que hagamos.</p>
<p>Una implementación sencilla de la classe Dictionary puede ser algo así:</p>
<pre lang="python">#!/usr/bin/env python
# encoding: utf-8

class Dictionary(object):

    def __init__(self, words):
        self.by_letter = {}
        self.load_data(words)

    def load_data(self, words):
        for word in words:
            try:
                self.by_letter[word[0]].append(word)
            except KeyError:
                self.by_letter[word[0]] = [word]</pre>
<p style="text-align: justify;">La salida muestra que esta versión ha tomado 0.1074 segundos para cargar las 234936 palabras en mi copia de  /usr/share/dict/words en OS X [Recordad que es una traducción y no lo hice directamente yo ésto]. No está demasiado mal, pero como podemos ver en el desensamblado de abajo, el bucle. está haciendo más trabajo del necesario. Tal como entra en el bucle en el opcode 13, se instala el contexto de una excepción (SETUP_EXCEPT). Entonces usa 6 opcodes para encontrar self.by_letter[word[0]] antes de añadir la palabra a la lista. Si se lanza una excepción porque word[0] todavía no está en el diccionario, el manejador de excepciones hace otra vez el mismo trabajo para  determinar word[0] (3 opcodes) y inicializa self.by_letter[word[0]] como una nueva lista que contiene la palabra.</p>
<pre>$ python dis_test_loop.py dis_slow_loop
 11           0 SETUP_LOOP              84 (to 87)
              3 LOAD_FAST                1 (words)
              6 GET_ITER
        &gt;&gt;    7 FOR_ITER                76 (to 86)
             10 STORE_FAST               2 (word)

 12          13 SETUP_EXCEPT            28 (to 44)

 13          16 LOAD_FAST                0 (self)
             19 LOAD_ATTR                0 (by_letter)
             22 LOAD_FAST                2 (word)
             25 LOAD_CONST               1 (0)
             28 BINARY_SUBSCR
             29 BINARY_SUBSCR
             30 LOAD_ATTR                1 (append)
             33 LOAD_FAST                2 (word)
             36 CALL_FUNCTION            1
             39 POP_TOP
             40 POP_BLOCK
             41 JUMP_ABSOLUTE            7

 14     &gt;&gt;   44 DUP_TOP
             45 LOAD_GLOBAL              2 (KeyError)
             48 COMPARE_OP              10 (exception match)
             51 JUMP_IF_FALSE           27 (to 81)
             54 POP_TOP
             55 POP_TOP
             56 POP_TOP
             57 POP_TOP

 15          58 LOAD_FAST                2 (word)
             61 BUILD_LIST               1
             64 LOAD_FAST                0 (self)
             67 LOAD_ATTR                0 (by_letter)
             70 LOAD_FAST                2 (word)
             73 LOAD_CONST               1 (0)
             76 BINARY_SUBSCR
             77 STORE_SUBSCR
             78 JUMP_ABSOLUTE            7
        &gt;&gt;   81 POP_TOP
             82 END_FINALLY
             83 JUMP_ABSOLUTE            7
        &gt;&gt;   86 POP_BLOCK
        &gt;&gt;   87 LOAD_CONST               0 (None)
             90 RETURN_VALUE

TIME: 0.1074</pre>
<p style="text-align: justify;">Una técnica para elimnar la excepción es rellenar self.by_letter con una lista para cada letra del alfabeto antes de empezar a llenar el diccionario. Esto significa que siempre podremos hacer la operación append satisfactoriamente sin necesidad de manejar ninguna excepción.</p>
<pre lang="python">#!/usr/bin/env python
# encoding: utf-8

import string

class Dictionary(object):

    def __init__(self, words):
        self.by_letter = dict( (letter, [])
                                for letter in string.letters)
        self.load_data(words)

    def load_data(self, words):
        for word in words:
            self.by_letter[word[0]].append(word)</pre>
<p style="text-align: justify;">El cambio reduce el número de opcodes aproximadamente a la mitad, pero solo se reduce el tiempo a 0.0984 segundos. Obviamente el manejo de la excepción añadía un cierto overhead pero tampoco demasiado.</p>
<pre>$ python dis_test_loop.py dis_faster_loop
 14           0 SETUP_LOOP              38 (to 41)
              3 LOAD_FAST                1 (words)
              6 GET_ITER
        &gt;&gt;    7 FOR_ITER                30 (to 40)
             10 STORE_FAST               2 (word)

 15          13 LOAD_FAST                0 (self)
             16 LOAD_ATTR                0 (by_letter)
             19 LOAD_FAST                2 (word)
             22 LOAD_CONST               1 (0)
             25 BINARY_SUBSCR
             26 BINARY_SUBSCR
             27 LOAD_ATTR                1 (append)
             30 LOAD_FAST                2 (word)
             33 CALL_FUNCTION            1
             36 POP_TOP
             37 JUMP_ABSOLUTE            7
        &gt;&gt;   40 POP_BLOCK
        &gt;&gt;   41 LOAD_CONST               0 (None)
             44 RETURN_VALUE

TIME: 0.0984</pre>
<p style="text-align: justify;">Podemos optimizar aún más el rendimiento moviendo el acceso a self.by_letter fuera del bucle (dado que el valor no cambia en ningún momento).</p>
<pre lang="python">#!/usr/bin/env python
# encoding: utf-8

import collections

class Dictionary(object):

    def __init__(self, words):
        self.by_letter = collections.defaultdict(list)
        self.load_data(words)

    def load_data(self, words):
        by_letter = self.by_letter
        for word in words:
            by_letter[word[0]].append(word)</pre>
<p style="text-align: justify;">Los opcodes 0-6 ahora encuentran el valor de self.by_letter y lo guardan como la variable local by_letter. Usar variables locales solo requiere un opcode en vez de 2 (en la posición 22 se usa LOAD_FAST para almacenar dictionary en la pila). Después de este cambio el tiempo de ejecución se reduce a 0.0842 segundos.</p>
<pre>$ python dis_test_loop.py dis_fastest_loop
 13           0 LOAD_FAST                0 (self)
              3 LOAD_ATTR                0 (by_letter)
              6 STORE_FAST               2 (by_letter)

 14           9 SETUP_LOOP              35 (to 47)
             12 LOAD_FAST                1 (words)
             15 GET_ITER
        &gt;&gt;   16 FOR_ITER                27 (to 46)
             19 STORE_FAST               3 (word)

 15          22 LOAD_FAST                2 (by_letter)
             25 LOAD_FAST                3 (word)
             28 LOAD_CONST               1 (0)
             31 BINARY_SUBSCR
             32 BINARY_SUBSCR
             33 LOAD_ATTR                1 (append)
             36 LOAD_FAST                3 (word)
             39 CALL_FUNCTION            1
             42 POP_TOP
             43 JUMP_ABSOLUTE           16
        &gt;&gt;   46 POP_BLOCK
        &gt;&gt;   47 LOAD_CONST               0 (None)
             50 RETURN_VALUE

TIME: 0.0842</pre>
<p style="text-align: justify;">Una mayor optimización sugerida por Brandon Rhodes es eliminar la versión Python del bucle por completo. Si usamos <code>groupby()</code> del módulo <em>itertools</em> para agrupar la entrada, la iteración es movida a código <a href="http://es.wikipedia.org/wiki/Lenguaje_de_programación_C">C</a>. Podemos hacer ésto porque sabemos que la entrada está ordenada. En caso de no saber si está ordenada o no, deberíamos ordenarla por si acaso.</p>
<pre lang="python">#!/usr/bin/env python
# encoding: utf-8

import operator
import itertools

class Dictionary(object):

    def __init__(self, words):
        self.by_letter = {}
        self.load_data(words)

    def load_data(self, words):
        # Arrange by letter
        grouped = itertools.groupby(words, key=operator.itemgetter(0))
        # Save arranged sets of words
        self.by_letter = dict((group[0][0], group) for group in grouped)</pre>
<p style="text-align: justify;">La versión con <em>itertools</em> solo tarda 0.0543 segundos en ejecutarse, más o menos la mitad del tiempo original.</p>
<pre>$ python dis_test_loop.py dis_eliminate_loop
 15           0 LOAD_GLOBAL              0 (itertools)
              3 LOAD_ATTR                1 (groupby)
              6 LOAD_FAST                1 (words)
              9 LOAD_CONST               1 ('key')
             12 LOAD_GLOBAL              2 (operator)
             15 LOAD_ATTR                3 (itemgetter)
             18 LOAD_CONST               2 (0)
             21 CALL_FUNCTION            1
             24 CALL_FUNCTION          257
             27 STORE_FAST               2 (grouped)

 17          30 LOAD_GLOBAL              4 (dict)
             33 LOAD_CONST               3 (<code> at 0x7e7b8, file "/Users/dhellmann/Documents/PyMOTW/dis/PyMOTW/dis/dis_eliminate_loop.py", line 17&gt;)
             36 MAKE_FUNCTION            0
             39 LOAD_FAST                2 (grouped)
             42 GET_ITER
             43 CALL_FUNCTION            1
             46 CALL_FUNCTION            1
             49 LOAD_FAST                0 (self)
             52 STORE_ATTR               5 (by_letter)
             55 LOAD_CONST               0 (None)
             58 RETURN_VALUE

TIME: 0.0543
</code></pre>
<h3 style="text-align: justify;">Referencias:</h3>
<ul>
<li><strong>Artículo original: </strong><a href="http://www.doughellmann.com/PyMOTW/dis/">http://www.doughellmann.com/PyMOTW/dis/</a></li>
<li><strong>Módulo dis: </strong><a href="http://docs.python.org/library/dis.html">http://docs.python.org/library/dis.html</a></li>
<li><strong>Módulo itertools</strong>: <a href="http://docs.python.org/library/itertools.html">http://docs.python.org/library/itertools.html</a></li>
</ul>
<div id="_mcePaste" style="overflow: hidden; position: absolute; left: -10000px; top: 8680px; width: 1px; height: 1px;">
<pre>$ python dis_test_loop.py dis_eliminate_loop
 15           0 LOAD_GLOBAL              0 (itertools)
              3 LOAD_ATTR                1 (groupby)
              6 LOAD_FAST                1 (words)
              9 LOAD_CONST               1 ('key')
             12 LOAD_GLOBAL              2 (operator)
             15 LOAD_ATTR                3 (itemgetter)
             18 LOAD_CONST               2 (0)
             21 CALL_FUNCTION            1
             24 CALL_FUNCTION          257
             27 STORE_FAST               2 (grouped)

 17          30 LOAD_GLOBAL              4 (dict)
             33 LOAD_CONST               3 (&lt;code object &lt;genexpr&gt; at 0x7e7b8, file "/Users/dhellmann/Documents/PyMOTW/dis/PyMOTW/dis/dis_eliminate_loop.py", line 17&gt;)
             36 MAKE_FUNCTION            0
             39 LOAD_FAST                2 (grouped)
             42 GET_ITER
             43 CALL_FUNCTION            1
             46 CALL_FUNCTION            1
             49 LOAD_FAST                0 (self)
             52 STORE_ATTR               5 (by_letter)
             55 LOAD_CONST               0 (None)
             58 RETURN_VALUE

TIME: 0.0543</pre>
</div>
 <img src="http://blog.viricmind.org/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?view=1&post_id=440" width="1" height="1" style="display: none;" />]]></content:encoded>
			<wfw:commentRss>http://blog.viricmind.org/2009/08/26/python-bytecode-disassembler-dis/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Urwid i les meves esperpèntiques proves</title>
		<link>http://blog.viricmind.org/2009/08/19/urwid-i-les-meves-esperpentiques-proves/</link>
		<comments>http://blog.viricmind.org/2009/08/19/urwid-i-les-meves-esperpentiques-proves/#comments</comments>
		<pubDate>Wed, 19 Aug 2009 18:22:27 +0000</pubDate>
		<dc:creator>castarco</dc:creator>
				<category><![CDATA[personal]]></category>
		<category><![CDATA[programación]]></category>

		<guid isPermaLink="false">http://blog.viricmind.org/?p=426</guid>
		<description><![CDATA[Una de les millors proves que he fet mai per provar el meu codi.. xD, siusplau no em jutjeu. El meu nom es Andreu i us explicaré una de les histories més extrañes del món. Un dia vaig començar a escriure un programet que&#8230; bé, realment no li veia cap futur. Però vanar creixent i [...]]]></description>
			<content:encoded><![CDATA[<p style="text-align: justify;">Una de les millors proves que he fet mai per provar el meu codi.. xD, siusplau no em jutjeu.</p>
<blockquote>
<p style="text-align: justify;"><span style="color: #003300;"><em>El meu nom es Andreu i us explicaré una de les histories més extrañes del món. Un dia vaig començar a escriure un programet que&#8230; bé, realment no li veia cap futur. Però vanar creixent i creixent.. ¿Qui ho hagués dit? Doncs sí, va arribar a ser el programa més conegut del món, ningú utilitzaba la linia de comandes fins llavors&#8230; però el fet que el meu programa esdevingués tan popular va promoure l&#8217;adopció de la linia de comandes com la interficie per defecte per interactuar amb els ordinadors&#8230; doncs.. si tots els programes per linia de comandes havien de ser tan genials com el que havia fet jo.. era clar que les interficies gràfiques caurien en desús, no valien res comparades amb el munt de lletres que ara m&#8217;està mostrant l&#8217;editor de linia de comandes que estic fent servir per explicar-vos aquesta historia.. i la veritat, ja m&#8217;agradaria que alguna cosa del que estic dient fos certa. El meu programa es una cagada impresionant.. i dificilment conseguiré més de 10 usuaris a tot el món, però necessito escriure la major quantitat de text possible per comprovar certes característiques d&#8217;una llibreria que es diu urwid i està basada en lesllibreries nCurses. Vull veure si apareix una barra de desplaçament o quelcom semblant per poder veure el text que he escrit i que no es visible a la pantalla&#8230; Però sembla ser que he d&#8217;escriure molt més del que m&#8217;agradaria i ja n&#8217;estic fart. Podria tirarme del balcó, fotrem un tret al cap o pendrem una pastilleta de cianur.. i tot això seria sens cap mena de dubte millor que el fet d&#8217;haver d&#8217;estar perdent el temps escrivint tonteries com aquestes&#8230; ara fa un moment m&#8217;ho he rellegit i la veritat es que passo de semblar un narcisista acabat a semblar un desequilibrat mental que necessita ser internat el mes aviat possible per assegurar que no s&#8217;autolesioni i prengui mal&#8230; em sembla que ja he aconseguit el que volia, ara no caldrà que patiu per la meva integritat física.. tot i així podeu seguir patint per la meva integritat mental, no n&#8217;estic segur.. de mantenirla intacta.</em></span></p>
</blockquote>
 <img src="http://blog.viricmind.org/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?view=1&post_id=426" width="1" height="1" style="display: none;" />]]></content:encoded>
			<wfw:commentRss>http://blog.viricmind.org/2009/08/19/urwid-i-les-meves-esperpentiques-proves/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Novedades en CMD Twitt</title>
		<link>http://blog.viricmind.org/2009/08/19/novedades-en-cmd-twitt/</link>
		<comments>http://blog.viricmind.org/2009/08/19/novedades-en-cmd-twitt/#comments</comments>
		<pubDate>Wed, 19 Aug 2009 15:34:18 +0000</pubDate>
		<dc:creator>castarco</dc:creator>
				<category><![CDATA[cmd-twitt]]></category>
		<category><![CDATA[programación]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[software libre]]></category>

		<guid isPermaLink="false">http://blog.viricmind.org/?p=424</guid>
		<description><![CDATA[No hay mucho que decir pero ha habido algunos avances significativos desde que escribí el primer post. He añadido algunas opciones más para que el programa sea más útil, he corregido dos pequeños bugs relativos a la gestión de errores y he simplificado la gestión de la codificación de texto gracias a una característica de [...]]]></description>
			<content:encoded><![CDATA[<p>No hay mucho que decir pero ha habido algunos avances significativos desde que escribí el primer post. He añadido algunas opciones más para que el programa sea más útil, he corregido dos pequeños bugs relativos a la gestión de errores y he simplificado la gestión de la codificación de texto gracias a una característica de la librería python-twitter que me había pasado desapercibida. También he creado alguna función más que me ha permitido simplificar un poco más el código.</p>
<p><strong>Lo que me queda por hacer:<br />
</strong></p>
<ol>
<li>Añadir un modo interactivo, lo programaré con la librería <a href="http://es.wikipedia.org/wiki/Curses">curses</a></li>
<li>Aprovechar la capacidad de internacionalización del programa y traducirlo al castellano y al catalán</li>
<li>Empaquetarlo para Debian</li>
<li>Si a alguien se le ocurre algo más, tiene todo el derecho del mundo a decirlo <img src='http://blog.viricmind.org/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' />  .</li>
</ol>
<p><strong>Algunas cosillas más <img src='http://blog.viricmind.org/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' />  :</strong></p>
<p>Añadí el proyecto a <a href="http://www.launchpad.net">Launchpad</a> ( <a href="https://launchpad.net/cmd-twitt">CMD Twitt</a> ) ya que gracias a ésto ahora tengo un <a href="http://es.wikipedia.org/wiki/Sistema_de_seguimiento_de_errores">bug tracker</a> donde todo el mundo puede indicar los bugs que encuentre en el programa <img src='http://blog.viricmind.org/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' />  y también dejar sugerencias de mejora en los <a href="https://blueprints.launchpad.net/cmd-twitt">Blue Prints</a>.</p>
<p>Saludos!</p>
 <img src="http://blog.viricmind.org/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?view=1&post_id=424" width="1" height="1" style="display: none;" />]]></content:encoded>
			<wfw:commentRss>http://blog.viricmind.org/2009/08/19/novedades-en-cmd-twitt/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
