joe di castrohttp://joedicastro.com2011-05-02T22:18:00+02:00Python one-liners. Potencia en una sola línea2011-05-02T22:18:00+02:00joe di castrohttp://joedicastro.com/python-one-liners-potencia-en-una-sola-linea.html<p>Un <a href="http://en.wikipedia.org/wiki/One-liner_program">one-liner</a> propiamente dicho
es un comando de la consola que ejecuta una determinada función en "una sola
línea de texto". En Python esto se consigue con una única orden de línea de
comandos que llama al interprete y ejecuta los argumentos que le pasemos en
la misma. Aunque también se les denomina así a veces a funciones lambda y
funciones que han sido reducidas a una sola linea de código.</p>
<p>Un ejemplo de python one-liner es uno de los más famosos:</p>
<div class="codehilite"><pre><span class="n">python</span> <span class="o">-</span><span class="n">m</span> <span class="n">this</span>
</pre></div>
<p>Y que nos devuelve el popular <a href="http://www.python.org/dev/peps/pep-0020/">Zen of Python</a>:</p>
<div class="codehilite"><pre>The Zen of Python, by Tim Peters
Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!
</pre></div>
<p>Pero existen varios one-liners muy útiles que nos pueden hacer la vida más fácil
para determinadas tareas. </p>
<h3 id="iniciar_un_servidor_web_y_compartir_un_directorio">Iniciar un servidor web y compartir un directorio</h3>
<div class="codehilite"><pre><span class="n">python</span> <span class="o">-</span><span class="n">m</span> <span class="n">SimpleHTTPServer</span>
</pre></div>
<p>Si ejecutamos este one-liner se iniciará un servidor web en el puerto <code>8000</code> de
nuestra dirección local (<code>localhost</code> o <code>127.0.0.1</code>) que nos servirá los archivos
del directorio donde lo ejecutemos. Para ello solo tenemos que acceder desde
nuestro navegador a la dirección <code>http://localhost:8000</code> o <code>http://127.0.0.1</code>.
Para interrumpir el servicio basta con que interrumpamos el programa con
<code>Ctrl+C</code>. Si quisiéramos emplear un puerto distinto de <em>8000</em>, por ejemplo
<em>8080</em>, solo tenemos que indicarselo:</p>
<div class="codehilite"><pre><span class="n">python</span> <span class="o">-</span><span class="n">m</span> <span class="n">SimpleHTTPServer</span> <span class="mi">8080</span>
</pre></div>
<h3 id="iniciar_un_servidor_smtp">Iniciar un servidor SMTP</h3>
<div class="codehilite"><pre><span class="n">python</span> <span class="o">-</span><span class="n">m</span> <span class="n">smtpd</span> <span class="o">-</span><span class="n">n</span> <span class="o">-</span><span class="n">c</span> <span class="n">DebuggingServer</span> <span class="n">localhost</span><span class="p">:</span><span class="mi">25</span>
</pre></div>
<p>Con este comando iniciamos un servidor de correo SMTP. Es básico, pero puede ser
muy útil para crear un entorno temporal de pruebas. Dependiendo de la
configuración de nuestro sistema, es muy probable que necesitemos ejecutar este
comando como administrador (<em>root</em>). Si ya tenemos corriendo un servidor de
correo en ese puerto, podemos cambiarlo por otro (eg: <em>2525</em>)</p>
<h3 id="iniciar_un_servidor_ftp">Iniciar un servidor FTP</h3>
<div class="codehilite"><pre><span class="n">python</span> <span class="o">-</span><span class="n">m</span> <span class="n">pyftpdlib</span><span class="o">.</span><span class="n">ftpserver</span>
</pre></div>
<p>Para poder ejecutar este comando es necesario tener instalada la librería
<a href="http://code.google.com/p/pyftpdlib/">pyftpdlib</a>. Debemos además ser usuario con permisos de administrador de la
maquina para poder iniciar este servidor. Una vez ejecutado tendremos un
servidor FTP de solo lectura en el directorio en el que lo iniciemos.</p>
<h3 id="ejecutar_un_cliente_ftp">Ejecutar un cliente FTP</h3>
<div class="codehilite"><pre><span class="n">python</span> <span class="o">-</span><span class="n">m</span> <span class="n">ftplib</span>
</pre></div>
<p>Si ejecutamos este comando, nos devolverá la ayuda con los argumentos necesarios
para poder conectarnos a un servidor FTP.</p>
<h3 id="abrir_una_p+gina_web_en_el_navegador">Abrir una página web en el navegador</h3>
<div class="codehilite"><pre><span class="n">python</span> <span class="o">-</span><span class="n">m</span> <span class="n">webbrowser</span> <span class="n">http</span><span class="p">:</span><span class="o">//</span><span class="n">joedicastro</span><span class="o">.</span><span class="n">com</span>
</pre></div>
<p>Nos abrirá la dirección web que le indiquemos en el navegador web predeterminado
de nuestro equipo.</p>
<h3 id="obtener_el_c+digo_fuente_de_una_p+gina_web">Obtener el código fuente de una página web</h3>
<div class="codehilite"><pre><span class="n">python</span> <span class="o">-</span><span class="n">m</span> <span class="n">urllib</span> <span class="n">http</span><span class="p">:</span><span class="o">//</span><span class="n">example</span><span class="o">.</span><span class="n">com</span>
</pre></div>
<p>Esto nos imprime en pantalla el código fuente (HTML) de una dirección web.</p>
<h3 id="eliminar_las_etiquetas_html_de_un_fichero_html">Eliminar las etiquetas HTML de un fichero HTML</h3>
<div class="codehilite"><pre><span class="n">python</span> <span class="o">-</span><span class="n">m</span> <span class="n">htmllib</span> <span class="n">test</span><span class="o">.</span><span class="n">html</span>
</pre></div>
<p>Esto nos imprime el contenido del fichero <code>test-html</code> pero sin mostrarnos las
etiquetas HTML, solo texto plano. Algo parecido a lo que hace un navegador en
modo texto como <em>links</em>, pero de forma estática.</p>
<h3 id="comparar_dos_directorios">Comparar dos directorios</h3>
<div class="codehilite"><pre><span class="n">python</span> <span class="o">-</span><span class="n">m</span> <span class="n">filecmp</span> <span class="n">dir_1</span> <span class="n">dir_2</span>
</pre></div>
<p>De esta manera podemos comparar dos directorios. El resultado será un resumen de
que ficheros son iguales, cuales diferentes y lo mismo con los subdirectorios.</p>
<h3 id="identificar_la_plataforma">Identificar la plataforma</h3>
<div class="codehilite"><pre><span class="n">python</span> <span class="o">-</span><span class="n">c</span> <span class="s">'from sys import platform; print platform'</span>
</pre></div>
<p>Este nos sirve para identificar la plataforma sobre la que se ejecuta el comando
(Windows, Linux, ...) No es de mucha utilidad, pero nos sirve como curiosidad.
Otra opción más simple y que nos devuelve un resultado más completo sería:</p>
<div class="codehilite"><pre><span class="n">python</span> <span class="o">-</span><span class="n">m</span> <span class="n">platform</span>
</pre></div>
<h3 id="obtener_el_nombre_de_la_maquina_hostname">Obtener el nombre de la maquina (hostname)</h3>
<div class="codehilite"><pre><span class="n">python</span> <span class="o">-</span><span class="n">c</span> <span class="s">'from socket import gethostname; print gethostname()'</span>
</pre></div>
<p>ó</p>
<div class="codehilite"><pre><span class="n">python</span> <span class="o">-</span><span class="n">c</span> <span class="s">'import platform; print platform.node()'</span>
</pre></div>
<p>Cualquiera de estos dos one-liners nos devolverán el nombre de la maquina en que
los ejecutemos.</p>
<h3 id="imprimir_el_calendario_del_a+o_en_curso">Imprimir el calendario del año en curso</h3>
<div class="codehilite"><pre><span class="n">python</span> <span class="o">-</span><span class="n">m</span> <span class="n">calendar</span>
</pre></div>
<p>Imprime en pantalla el calendario de todo el año. Para conocer más opciones,
como imprimir el calendario de otro año, mes, etc añadir la opción <code>-h</code> al final
de la línea.</p>
<h3 id="mostrar_los_m+dulos_empleados_en_un_script">Mostrar los módulos empleados en un script</h3>
<div class="codehilite"><pre><span class="n">python</span> <span class="o">-</span><span class="n">m</span> <span class="n">modulefinder</span> <span class="n">script</span><span class="o">.</span><span class="n">py</span>
</pre></div>
<p>De esta manera podemos no solo saber que módulos son importados por el script,
si no que además nos muestra su ruta en el sistema de archivos.</p>
<p>Aquí he mencionado solo algunos que empleo con cierta frecuencia o que me han
parecido reseñables, pero existen bastantes más. Una buena pista es que la
mayoría hace uso de los módulos de la librería estándar de Python.</p>
<h2 id="como_funciona">Como funciona</h2>
<p>Básicamente se trata de llamar al interprete Python utilizando uno de los
siguientes argumentos:</p>
<ul>
<li>
<p><code>-c</code>: Lo que seguiría a esta opción sería un programa Python encerrado entre
comillas. Por ejemplo, el primer ejemplo quedaría de este modo,
<code>python -c 'import this'</code></p>
</li>
<li>
<p><code>-m</code>: Está opción llama a un modulo de python, que puede a su vez tener
distintas opciones y argumentos, y lo ejecuta como script. Por ejemplo:
<code>python -m locale</code></p>
</li>
</ul>
<h2 id="https_server">HTTPS Server</h2>
<p>Este no es un one-liner en Python, pero sirve como complemento a los distintos
servidores que hemos visto que se podían iniciar con mucha facilidad gracias a
Python. Este código inicia un servidor HTTPS en Python en el puerto <em>4443</em> de la
dirección local. Lo suyo sería iniciarlo en el puerto <em>443</em>, y se puede hacer
simplemente cambiándolo, pero se necesitan entonces permisos de administrador
para iniciarlo.</p>
<div class="codehilite"><pre><span class="kn">import</span> <span class="nn">BaseHTTPServer</span><span class="o">,</span> <span class="nn">SimpleHTTPServer</span>
<span class="kn">import</span> <span class="nn">ssl</span>
<span class="n">httpd</span> <span class="o">=</span> <span class="n">BaseHTTPServer</span><span class="o">.</span><span class="n">HTTPServer</span><span class="p">((</span><span class="s">'localhost'</span><span class="p">,</span> <span class="mi">4443</span><span class="p">),</span>
<span class="n">SimpleHTTPServer</span><span class="o">.</span><span class="n">SimpleHTTPRequestHandler</span><span class="p">)</span>
<span class="n">httpd</span><span class="o">.</span><span class="n">socket</span> <span class="o">=</span> <span class="n">ssl</span><span class="o">.</span><span class="n">wrap_socket</span> <span class="p">(</span><span class="n">httpd</span><span class="o">.</span><span class="n">socket</span><span class="p">,</span>
<span class="n">certfile</span><span class="o">=</span><span class="s">'path/to/localhost.pem'</span><span class="p">,</span>
<span class="n">server_side</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>
<span class="n">httpd</span><span class="o">.</span><span class="n">serve_forever</span><span class="p">()</span>
</pre></div>
<p>El código es original de <a href="http://www.piware.de/2011/01/creating-an-https-server-in-python/">Martin Pitt</a> y me ha servido en más de una ocasión
para probar un script.</p>
<br />
<h3 id="editar_una_p+gina_web_con_javascript">Editar una página web con javascript</h3>
<p>No es un one-liner escrito en Python, si no en javascript, pero lo menciono aquí
a modo de curiosidad porque siempre me ha parecido curioso y aparentemente
inútil, pero tiene sus aplicaciones (alguna broma ha caído gracias a él).</p>
<div class="codehilite"><pre><span class="nx">javascript</span><span class="o">:</span><span class="nb">document</span><span class="p">.</span><span class="nx">body</span><span class="p">.</span><span class="nx">contentEditable</span><span class="o">=</span><span class="s1">'true'</span><span class="p">;</span> <span class="nb">document</span><span class="p">.</span><span class="nx">designMode</span><span class="o">=</span><span class="s1">'on'</span><span class="p">;</span> <span class="k">void</span> <span class="mi">0</span>
</pre></div>
<p>Para ejecutarlo es muy sencillo. Abrimos nuestro navegador web favorito,
abrimos la página web que deseamos editar y luego simplemente sustituimos el
texto de la barra de direcciones por el de este one-liner y pulsamos Enter.
Ahora podemos editar la página web como si fuera un procesador de texto.</p>