<?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>The Raging Che &#187; Python</title>
	<atom:link href="http://theragingche.com/blog/category/python/feed/" rel="self" type="application/rss+xml" />
	<link>http://theragingche.com/blog</link>
	<description>Fee! Fi! Fo! Fum! I smell the blood of a silly man!</description>
	<lastBuildDate>Wed, 28 Jul 2010 18:28:42 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0</generator>
		<item>
		<title>Mi problema con las listas de correo</title>
		<link>http://theragingche.com/blog/2009/06/15/mi-problema-con-las-listas-de-correo/</link>
		<comments>http://theragingche.com/blog/2009/06/15/mi-problema-con-las-listas-de-correo/#comments</comments>
		<pubDate>Mon, 15 Jun 2009 18:32:29 +0000</pubDate>
		<dc:creator>hermann</dc:creator>
				<category><![CDATA[Español]]></category>
		<category><![CDATA[Programación]]></category>
		<category><![CDATA[Python]]></category>

		<guid isPermaLink="false">http://theragingche.com/blog/?p=1007</guid>
		<description><![CDATA[Fíjense en el siguiente intercambio de correos: Pavel hace una pregunta Jose responde con un enlace a la documentación de la función en cuestión, junto con una explicación de lo que debe hacer Alexis responde con un ejemplo Carlos responde, al día siguiente exactamente lo mismo que lo que ha dicho Alexis hace unas meras [...]]]></description>
			<content:encoded><![CDATA[<p>Fíjense en el siguiente intercambio de correos:</p>
<ol>
<li><a href="http://listas.aditel.org/archivos/python-es/2009-June/024915.html">Pavel hace una pregunta</a></li>
<li><a href="http://listas.aditel.org/archivos/python-es/2009-June/024916.html">Jose responde</a> con un enlace a la documentación de la función en cuestión, junto con una explicación de lo que debe hacer</li>
<li><a href="http://listas.aditel.org/archivos/python-es/2009-June/024917.html">Alexis responde</a> con un ejemplo</li>
<li><a href="http://listas.aditel.org/archivos/python-es/2009-June/024919.html">Carlos responde</a>, al día siguiente exactamente lo mismo que lo que ha dicho Alexis hace unas meras horas.</li>
<li><a href="http://listas.aditel.org/archivos/python-es/2009-June/024921.html">Manuel contesta</a> con lo mismo que los dos que han contestado antes</li>
<li>Y finalmente, <a href="http://listas.aditel.org/archivos/python-es/2009-June/024951.html">Antonio se une a la fiesta</a>, tres días después contestando con&#8230; lo mismo que los últimos tres.</li>
</ol>
<p>¿Tan faltos de amor están estos tres perdedores que se ven llamados a contestar de manera repetida y sin originalidad a una pregunta tan insulsa y obvia como esta? No es la primera vez, ni será la última, que alguien hace una pregunta de respuesta simple y se abalanzan los que quieren poder fardar de que contestan preguntas en la lista de correo de Python.</p>
<p>Por cierto, la pregunta en cuestión es un ejemplo perfecto de <a href="http://en.wikipedia.org/wiki/Cargo_cult_programming">cargo cult programming</a>: cuando alguien copia y pega código sin saber bien como funciona, otro clásico infaltable de las listas de correo.</p>
]]></content:encoded>
			<wfw:commentRss>http://theragingche.com/blog/2009/06/15/mi-problema-con-las-listas-de-correo/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Cursores con MySQLdb en Python</title>
		<link>http://theragingche.com/blog/2008/10/17/cursores-con-mysqldb-en-python/</link>
		<comments>http://theragingche.com/blog/2008/10/17/cursores-con-mysqldb-en-python/#comments</comments>
		<pubDate>Fri, 17 Oct 2008 11:51:55 +0000</pubDate>
		<dc:creator>hermann</dc:creator>
				<category><![CDATA[Español]]></category>
		<category><![CDATA[Programación]]></category>
		<category><![CDATA[Python]]></category>

		<guid isPermaLink="false">http://theragingche.com/blog/?p=934</guid>
		<description><![CDATA[Resulta que MySQLdb tiene la fea manía de devolver los resultados en una tupla (igual que PHP en realidad), en vez de devolver un dict que tiene más sentido. Esto pasa porque así se comporta el cursor que db.cursor() devuelve por defecto. Afortunadamente hay más cursores disponibles, entre ellos el DictCursor, pero yo siempre me [...]]]></description>
			<content:encoded><![CDATA[<p>Resulta que <a href="http://pypi.python.org/pypi/MySQL-python/1.2.2">MySQLdb</a> tiene la fea manía de devolver los resultados en una tupla (igual que PHP en realidad), en vez de devolver un dict que tiene más sentido. Esto pasa porque así se comporta el cursor que <code>db.cursor()</code> devuelve por defecto. Afortunadamente <a href="http://mysql-python.sourceforge.net/MySQLdb-1.2.2/public/MySQLdb.cursors-module.html">hay más cursores disponibles</a>, entre ellos el <code>DictCursor</code>, pero yo siempre me olvido de como usarlos. Así que me anoto esto aquí para recordarlo.</p>
<p>Se puede hacer de dos maneras, una es por cursor individual:</p>
<pre class="prettyprint"><code>import MySQLdb
db = MySQLdb.connect(...)
cursor = db.cursor(cursorclass=MySQLdb.cursors.DictCursor)</code></pre>
<p>O se puede cambiar el tipo de cursor que <code>db.cursor()</code> devuelve por defecto:</p>
<pre class="prettyprint"><code>import MySQLdb
db = MySQLdb.connect(...)
db.cursorclass = MySQLdb.cursors.DictCursor
cursor = db.cursor()</code></pre>
]]></content:encoded>
			<wfw:commentRss>http://theragingche.com/blog/2008/10/17/cursores-con-mysqldb-en-python/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>RSS de segunda mano</title>
		<link>http://theragingche.com/blog/2008/03/21/rss-de-segunda-mano/</link>
		<comments>http://theragingche.com/blog/2008/03/21/rss-de-segunda-mano/#comments</comments>
		<pubDate>Fri, 21 Mar 2008 16:08:00 +0000</pubDate>
		<dc:creator>hermann</dc:creator>
				<category><![CDATA[Español]]></category>
		<category><![CDATA[Programación]]></category>
		<category><![CDATA[Python]]></category>

		<guid isPermaLink="false">http://theragingche.com/blog/?p=814</guid>
		<description><![CDATA[Llevo un par de días pensando en comprar un móvil nuevo. Actualmente tengo un Nokia 6230 en un estado deplorable y aunque me gusta mucho por su forma, tamaño ni demasiado pequeño ni grande y funcionalidad adecuada creo que es hora de invertir en uno nuevo. He visto que una compañera de trabajo tiene un [...]]]></description>
			<content:encoded><![CDATA[<p>Llevo un par de días pensando en comprar un móvil nuevo. Actualmente tengo un Nokia 6230 en un estado deplorable y aunque me gusta mucho por su forma, tamaño ni demasiado pequeño ni grande y funcionalidad adecuada creo que es hora de invertir en uno nuevo.</p>
<p>He visto que una compañera de trabajo tiene un <a href="http://en.wikipedia.org/wiki/Nokia_E60">Nokia E60</a> y me ha gustado mucho. Tiene una pantalla grande, con una resolución bastante alta, corre Symbian (importante para probar Android en el futuro cercano) y tiene soporte para Wifi.</p>
<p>El punto es que estaba mirando si había alguno en <a href="http://segundamano.es">segunda mano</a> y aunque encontré algunos en Madrid no eran recientes y ya se habían vendido. Quise encontrar alguna manera de hacer que me avisase cuando hubiesen resultados nuevos pero no pude encontrar ni un mísero feed RSS.</p>
<p>Así que hice el mío. Hay una <a href="http://volt.io/code/segunda-mano/">versión online</a> y un <a href="http://volt.io/static/code/segundamano.py">modulo de Python</a> para los que quieran instalarlo en su propio ordenador cuando inevitablemente los de segunda mano bloqueen la IP de mi servidor.</p>
]]></content:encoded>
			<wfw:commentRss>http://theragingche.com/blog/2008/03/21/rss-de-segunda-mano/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>I &lt;3 Python</title>
		<link>http://theragingche.com/blog/2008/03/11/i-love-python/</link>
		<comments>http://theragingche.com/blog/2008/03/11/i-love-python/#comments</comments>
		<pubDate>Tue, 11 Mar 2008 13:23:43 +0000</pubDate>
		<dc:creator>hermann</dc:creator>
				<category><![CDATA[Español]]></category>
		<category><![CDATA[Python]]></category>

		<guid isPermaLink="false">http://theragingche.com/blog/2008/03/11/i/</guid>
		<description><![CDATA[$ python Python 2.5.1 (r251:54863, Mar 7 2008, 04:10:12) [GCC 4.1.3 20070929 (prerelease) (Ubuntu 4.1.2-16ubuntu2)] on linux2 Type "help", "copyright", "credits" or "license" for more information. &#62;&#62;&#62; S = [1, 2, 3, 4] &#62;&#62;&#62; any(x &#62; 3 for x in S) True &#62;&#62;&#62; any(x &#62; 5 for x in S) False &#62;&#62;&#62; all(x &#60; 5 [...]]]></description>
			<content:encoded><![CDATA[<pre><code>$ python
Python 2.5.1 (r251:54863, Mar  7 2008, 04:10:12)
[GCC 4.1.3 20070929 (prerelease) (Ubuntu 4.1.2-16ubuntu2)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
&gt;&gt;&gt; S = [1, 2, 3, 4]
&gt;&gt;&gt; any(x &gt; 3 for x in S)
True
&gt;&gt;&gt; any(x &gt; 5 for x in S)
False
&gt;&gt;&gt; all(x &lt; 5 for x in S)
True
&gt;&gt;&gt; all(x &lt; 3 for x in S)
False</code></pre>
<p>La cantidad de código que me podría haber ahorrado en esta última semana si hubiese sabido de estas dos maravillosas funciones antes. Ahora toca revisar y modificar.</p>
<p>Visto en <a href="http://www.artima.com/weblogs/viewpost.jsp?thread=98196">The fate of reduce() in Python 3000</a></p>
]]></content:encoded>
			<wfw:commentRss>http://theragingche.com/blog/2008/03/11/i-love-python/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Como hacer un HEAD request en Python</title>
		<link>http://theragingche.com/blog/2007/11/26/como-hacer-un-head-request-en-python/</link>
		<comments>http://theragingche.com/blog/2007/11/26/como-hacer-un-head-request-en-python/#comments</comments>
		<pubDate>Mon, 26 Nov 2007 13:42:34 +0000</pubDate>
		<dc:creator>hermann</dc:creator>
				<category><![CDATA[Español]]></category>
		<category><![CDATA[Python]]></category>

		<guid isPermaLink="false">http://theragingche.com/blog/2007/11/26/como-hacer-un-head-request-en-python/</guid>
		<description><![CDATA[Estuve el domingo unas cuantas horas buscando por internet como hacer esto y me estaba frustrando. Mi nuevo mini-proyecto secreto requiere monitorizar unas imágenes regularmente para ir actualizándolas a medida que van cambiando mediante un cron script que se ejecuta cada 15 minutos. Hay dos opciones: Bajarnos las imágenes todas las veces y comparar el [...]]]></description>
			<content:encoded><![CDATA[<p>Estuve el domingo unas cuantas horas buscando por internet como hacer esto y me estaba frustrando. Mi nuevo mini-proyecto secreto requiere monitorizar unas imágenes regularmente para ir actualizándolas a medida que van cambiando mediante un cron script que se ejecuta cada 15 minutos. Hay dos opciones:</p>
<ol>
<li>Bajarnos las imágenes todas las veces y comparar el md5sum para ver si han cambiado</li>
<li>o hacer un pedido HEAD en vez de GET y hacer uso de las cabeceras Last-Modified y ETag.</li>
</ol>
<p>¿Que cuales son las ventajas del punto dos? Lo más importante es que nos ahorramos ancho de banda nosotros y a los que le estemos bajando las imágenes, tampoco es cuestión de abusar del servidor de otra persona. Ojo que esto no aplica sólo a las imágenes, cualquier servidor moderno de hoy en día tiene soporte para estas cabeceras y las devolverá con cualquier tipo de archivo, incluso los que estén generados dinámicamente. Nos ahorramos ancho de banda porque sólo pedimos la cabecera del archivo que exceptuando casos extremos será mucho más pequeño que el resto del documento. Esto es especialmente útil para el contenido estático (js, imagenes, css, etc) y contenido que se baja regularmente como feeds RSS. Además de ahorrar ancho de banda también hacemos que el script vaya más rápido ya que no tiene que procesar todo el documento.</p>
<p>La idea es que hacemos un pedido HEAD inicial y guardamos el Last-Modified y ETag, luego en los subsiguientes pedidos enviamos pedidos GET con las cabeceras If-Modified-Since y If-None-Match. If-Modified-Since se usa con la fecha que guardamos anteriormente y If-None-Match con el ETag. Si ambos campos son los mismos en el archivo actual del lado del servidor entonces este debe responder con un &#8217;304 Not Modified&#8217;</p>
<pre><code class="prettyprint">import StringIO
import pycurl

c = pycurl.Curl()
s = StringIO.StringIO()

c.setopt(pycurl.URL, 'http://theragingche.com/images/hand_made_cms.gif')
c.setopt(pycurl.HEADER, True) # estas dos lineas son las que importan
c.setopt(pycurl.NOBODY, True) # para hacer un pedido HEAD
c.setopt(pycurl.WRITEFUNCTION, s.write)

c.perform()
print s.getvalue()</code></pre>
<p>Nos devuelve solo la cabecera:</p>
<pre><code class="prettyprint">$ python head.py
HTTP/1.1 200 OK
Date: Mon, 26 Nov 2007 12:29:50 GMT
Server: Apache/2.0.54 (Fedora)
Last-Modified: Thu, 16 Mar 2006 19:02:45 GMT
ETag: "303247c3-105-40f21566a7f40"
Accept-Ranges: bytes
Content-Length: 261
Connection: close
Content-Type: image/gif
X-Pad: avoid browser bug</code></pre>
<p>Si luego hacemos:</p>
<pre><code class="prettyprint">import StringIO
import pycurl 

c = pycurl.Curl()
s = StringIO.StringIO()

c.setopt(pycurl.URL, 'http://theragingche.com/images/hand_made_cms.gif')

# especificamos las cabeceras
c.setopt(pycurl.HTTPHEADER,
    ['If-Modified-Since: Thu, 16 Mar 2006 19:02:45 GMT',
    'If-None-Match: "303247c3-105-40f21566a7f40"'])

c.setopt(pycurl.WRITEFUNCTION, s.write)
c.perform()

print c.getinfo(pycurl.RESPONSE_CODE)</code></pre>
<p>Nos da:</p>
<pre><code class="prettyprint">$ python head.py
304</code></pre>
]]></content:encoded>
			<wfw:commentRss>http://theragingche.com/blog/2007/11/26/como-hacer-un-head-request-en-python/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
