Herramientas de usuario

Herramientas del sitio


script:python:new:api

¡Esta es una revisión vieja del documento!


Python - elementos del lenguaje

Clases, módulos y funciones própias de Python.

Cómo tratar con...

Strings

Acciones básicas

my_str = 'Hola buenos días!'	# Definición de un string
'ola' in my_str			# Saber si un string forma parte de otro string
my_str[-1:]			# Recoger el último caracter
my_str[2]			# Recoger el segundo carácter
my_path = u"c:\windows"		# Omite los carácteres de escape
len(my_str)			# Saber el tamaño del string
my_str + my_str2		# Concatena el string my_str con my_str2

Métodos del string

  • upper(): Pasa a mayúsculas.
  • startswith(t)
  • endswith(t)
  • islower()
  • isupper()
  • isalpha(), si todos los caráceres son letras.
  • isalnum(), si todos los carácteres son alfanuméricos (letra o número).
  • isdigit(), si todos los carácteres son dígitos.
  • istitle(), si todas las palabras inician con mayusculas.
  • find(s), devuelve el primer índice de s, si no existe devolverá -1. rfind(s) devolverá el último índice.
  • replace(s1, s2), reemplaza s1 por s2.
  • encode(s), devolverá el string con la codificación indicada como s.
  • strip(), hace un trim del string.
  • capitalize(), pone la primera letra en mayúsuculas.

Formatear strings

Modo antiguo:

"La capital de %s es %s" % ("Araba", "Gasteiz") 		# 'La capital de Araba es Gasteiz'
"%s tiene %d provincias y %4d habitantes" % ("Araba", 1, 100)  	# 'Gasteiz tiene 1 provincias y 0100 habitantes'
"Cada uno con %.2f ojos" % (2.5457)  				# 'Cada uno con 2.54 ojos'

Modo nuevo, con método format:

'{0} and {1}'.format('spam', 'eggs')							# spam and eggs
'This {food} is {adjective}.'.format(food='spam', adjective='absolutely horrible')	# This spam is absolutely horrible.
'The story of {0}, {1}, and {other}.'.format('Bill', 'Manfred', other='Georg')		# The story of Bill, Manfred, and Georg.
'The value of PI is approximately {0:.3f}.'.format(math.pi)				# The value of PI is approximately 3.142.
'{0:10} ==> {1:10d}'.format('Jack', 4098)						# Jack       ==>       4098

Otra forma:

str = 'Name: {user.name}, Age: {user.age}, Sex: {user.sex}'.format(user=user)

Carácteres de escape

  • \u, indica que lo que sigue es un carácter unicode.

Definiciones especiales de strings

u'string'		# indica que el string contiene carácteres unicode
r'string'		# indica que el string es raw (que no se tendrán en cuenta los carácteres de escape)
s1 = '''Esto es un
string multilínea''' 	# crea un string multilínea

Otras acciones

# Unir un vector en un string:
" ".join(['a','b','c'])		# Sacaría: 'a b c'
":".join(['a','b','c'])		# Sacaría: 'a:b:c'

Fechas

datetime

from datetime import datetime
datetime.now()				# momento actual
datetime.time(datetime.now())		# hora actual
datetime.date(2006, 5, 6).isoformat()	# crea un datetime y lo devuelve como string en un formato fácilmente legible (2006-05-06)

struct_time

import time
time.localtime()		# recoge el momento actual
time.ctime(longValue/1000)	# crea una fecha a partir de un long

Comparación de fechas

Comparación utilizando objetos datetime:

now = datetime.datetime.now()
today8am = now.replace(hour=8, minute=0, second=0, microsecond=0)
now < today8am
now == today8am
now > today8am

Cmparación utilizando timedelta:

from datetime import datetime, timedelta
then = datetime.now () - timedelta (hours = 2)
now = datetime.now ()
(now - then) > timedelta (days = 1)
(now - then) > timedelta (hours = 1)

Ficheros

La llamada a la función open() devuelve un objeto del tipo File, los argumentos son la ruta del fichero y el modo.
El modo puede ser 'r' para leer (si se omite es el que se utiliza por defecto), 'w' para escribir (truncando si ya existe) y 'a' para agregar.
Podemos agregar 'b' al modo, esto hará que abramos un fichero en modo binario.

var = open ("c:\\prueba.txt")
for file in var.readlines():
  print file,
var.close()

Funciones y propiedades

  • close(), cierra el fichero.
  • read(), lee hasta el final del fichero.
  • read(i), lee i carácteres a partir de la última lectura.
  • fileno(), retorna el número del descriptor del fichero.
  • seek(i), se mueve i bytes.
  • tell(), indica la posición del fichero.
  • write(s)
  • writelines(lst)
  • closed
  • encoding

Árbol de directorios

Mediante os

import os
os.path.abspath(rel_path)	# Devuelve el path absoluto al que apunta rel_path
os.mkdir(path)			# Crea un directorio
os.sep				# Devuelve el separador de directorios del sistema
os.listdir(path) 		# Devuelve una lista con los nombres de archivos
os.path.exists(path)		# Indica si un fichero existe
os.path.isdir(path)		# Indica si es directorio
os.path.isfile(path)		# Indica si es fichero
os.path.getsize(path)		# Devuelve el tamaño de un fichero
os.remove(path)			# Borra un fichero

Mediante shutil

import shutil
shutil.rmtree(path)		# Elimina un directorio
shutil.copytree(src, dst)	# Copia un directorio
shutil.copyfile(src, dst)	# Copia un fichero
shutil.move(src, dst)		# Mueve un fichero

Parámetros del ejecutable

Argparse

OptionParse

:!: Deprecated!
Se utiliza el objeto OptionParse del paquete optparse

from optparse import OptionParser
 
# Crear objeto OptionParser e indicar el uso del ejecutable
parser = OptionParser(usage="SRCDS.py -a ADDR -p RCONPASS [command]")
 
# Añadir parametros a gestionar
parser.add_option("-p",dest="rcon",default="",help="Specifies the rcon password")
parser.add_option("-a",dest="addr",default="",help="Specifies the address of the server to connect to")
 
# Parsear parametros
(options,args) = parser.parse_args()
 
# Tratar parametros
if not options.addr:
    os.system(sys.argv[0] + " -h")
    sys.exit(1)
print("Connecting to %s with rcon password of %s" % (options.addr,options.rcon))

Notas

  • docopt es una librería que podría ser utilizada para ello.

Sockets

Broadcasting

  • Todas las máquinas de la red reciben información.
  • Pueden haber varios programas escuchando por el mismo puerto.

Emisor:

MYPORT = 5000
 
import sys, time
from socket import *
 
s = socket(AF_INET, SOCK_DGRAM)
s.bind(('', 0))
s.setsockopt(SOL_SOCKET, SO_BROADCAST, 1)
 
while 1:
    data = repr(time.time()) + '\n'
    s.sendto(data, ('<broadcast>', MYPORT))
    print 'send!', data
    time.sleep(2)

Receptor:

import socket
import struct
 
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.bind(('', 5000))
 
while True:
  print sock.recv(10240)

Threads

Para utilizarlos importaremos el módulo threading.
Podemos llamar a una función haciendo:

thread = threading.Thread(target=myFunc)
thread.start()

Un thread tiene la propiedad daemon, si esta es True cuando el thread padre acabe el thread hijo también lo hará (pero cuidado, esto puede hacer no liberar el recurso que estaba utilizando un objeto Event (poniéndolo como flag en el bucle principal).

  • Los objetos Event sirven para comunicarse entre threads. Consisten en una flag que puede estar a True o a False sus métodos importantes on:
    • wait, que hará esperar hasta que la flag sea True.
    • set, que pondrá la flag a True.
    • isSet o is_set que indicará el estado de la flag.
    • reset que pondrá la flag a False.
  • Los objetos Lock sirven para indicar una zona de exclusión mutua. Utilizaremos su método acquire para adquirirla y el release para liberarla:
self.mutex = Lock()
 
def initProcess (self):
    self.mutex.acquire()
    host = self.results.get()
    self.mutex.release()
    return host

Múltiples procesos

En el módulo multiprocessing podemos encontrar clases como Process, para lanzar un proceso a parte, Pool, para lanzar varios procesos, Pipe o Queue para la comunicación entre ellos…

Lanzar procesos

La clase Pool permite lanzar varios procesos, en el constructor se le pasa el número de procesos que gestionará y al llamar al método map se le indicará qué función corresponderá a qué proceso y el array de parámetros para cada uno de ellos:

from multiprocessing import Pool
servers = config['servers']            # Servers array de diccionarios
procs = Pool(processes=len(servers))
procs.map(askServerInfo, servers)      # askServer es una función que recibe un único parámetro

Comunicación entre procesos

  • Pipe o Queue

Compartir datos entre procesos

  • Array o value

Sincronización

  • Lock

Casos

Uso de Queue y procesos sueltos:

from multiprocessing import Queue, Process
 
class AskServerInfo (Process):
    def __init__(self, server, queue):
        Process.__init__(self)
        self.server = server
        self.queue = queue
 
    def run (self):
        # action to obtain info from self.server
        self.queue.put(self.server)
 
if __name__ == "__main__":
    config = readConfigFile('servers.yml')
    nservers = len(config['servers'])
    results = Queue()
 
    for server in config['servers']:
        worker = AskServerInfo(server, results)
        worker.start()
 
    while nservers:
        info = results.get()
        saveInfo(info)
        nservers = nservers - 1

Ejecución de procesos externos

Expresiones regulares

Uso

import re
for w in wordlist:
  print re.search('^..j', w)							# imprime None o un objeto patrón encontrado según si w cumple el patrón
 
[w for w in wordlist if re.search('^..j', w)]					# devuelve lista de palabras que su tercer carácter sea la j
 
word = 'supercalifragilisticoespialidoso'
re.findall(r'[aeiou]', word)							# devuelve la lista de vocales directamente (sin necesidad de recorrer el resultado)
 
re.split(regex, text)								# corta un texto a partir de una expresión regular
 
re_pattern='(/+)|(~+)|("+)|(;+)|(,+)|(!+)|(\.)+|(:+)|(\(+)|(\)+)'
re.sub(re_pattern, ' ', texto)							# substituye un patrón en el texto

Selección del retorno

Los paréntesis nos permiten indicar qué se ha de retornar en caso de encontrar un matching. Agregando ?:, :?, ? al principio o al final de estos podremos indicar qué parte del matching nos interesa.

Selección de palabras

Mediante < y > podemos seleccionar palabras:

  • <a>(<.*>)<man> devolverá los adjetivos que se le agregan a “a man” (nervous, dangerous, white…).

Codificación de texto

Funciones nativas

unicode('abcdef')						# devuelve el string en formato unicode: u'abcdef'
s.encode('utf8')						# devuelve el string s en formato utf-8
unicode_char = u'\u0061'					# asigna un string con codificación unicode, en este caso unicode_char tomaría el valor 'a'
unicode('\x80abc', errors='strict')				# errors puede tomar los valores 'strict', 'replace' o 'ignore'

codecs

import codecs
f1 = codecs.open(path1, encoding='latin2')			# abre un archivo para leer con una codificación latin2
f2 = codecs.open(path2, 'w', encoding='utf-8')			# abre un archivo para escribir codificandolo en utf-8

unicodedata

title = u"Klüft skräms inför på fédéral électoral große"
import unicodedata
unicodedata.normalize('NFKD', title).encode('ascii','ignore')
'Kluft skrams infor pa federal electoral groe'

Formato de texto

Formato de tags en general

Encontraremos una serie de parsers en el módulo sgllib.

HTML

XML

import xml.dom.minidom
archivo = xml.dom.minidom.parse('archivo.xml')		# cargar el archivo
archivo.toxml()						# mostrar el código xml
elements = archivo.getElementsByTagName('name')		# recoge los nodos con nombre name
nodo = elements.item(0)					# recoge el primer elemento
nodo.hasChildNodes()					# devuelve si tiene nodos hijos
nodo.nodeName						# nombre del nodo
nodo.nodeType						# tipo del nodo
nodo.nodeValue						# valor del nodo
subnds = nodo.childNodes				# devuelve los nodos hijo del nodo actual
attr = nodo.attributes					# devuelve los atributos del nodo actual
subn = attr.getNamedItem('tal')				# retorna el atributo 'tal' del nodo actual
 
xmldoc.getElementsByTagName('title')[0].firstChild.data
 
from xml.dom.minidom import parseString
file = open('somexmlfile.xml','r')
data = file.read()
file.close()
dom = parseString(data)

Si el nodo actual tiene un valor, del estilo <nombre>nom</nombre>; el nodo actual tendrá como nodeName “nombre” pero None como nodeValue, para acceder a su valor tendrás que coger sus nodos-hijo y el primer elemento de estos tendrá el nodeName a None pero el nodeValue como “nom”.
Para más información lee “Python and XML - An introduction.pdf” en los documentos.

JSON

A partir de la versión 2.6 de Python podemos utilizar un encoder\decoder de JSON en Python.
Para codificar a JSON:

import json
json.dumps(['foo', {'bar': ('baz', None, 1.0, 2)}])		# '["foo", {"bar": ["baz", null, 1.0, 2]}]'

Para decodificar de JSON:

import json
json.loads('["foo", {"bar":["baz", null, 1.0, 2]}]')		# [u'foo', {u'bar': [u'baz', None, 1.0, 2]}]

Contenido web

urllib

from urllib import urlopen
web = urlopen('http://www.google.es')		# abre un stream web
web.read()					# lee la web indicada
web.close()					# cierra el stream de la web
  • Si utilizamos uno o varios proxies podemos pasarselos como segundo parámetro en una lista a urlopen.

Serialización

Para su uso utilizaremos el módulo pickle.

SQLite

Desde la versión 2.5, y de forma nativa, en Python podemos utilizar el módulo sqlite3 el cual nos permite hacer uso de este motor de base de datos.

import sqlite3
db = sqlite3.connect('c:\\prueba.db')			# abrimos una conexión a un fichero de base de datos
c1 = db.cursor()					# recogemos un cursor de acceso a la DB
c1.execute('insert into data (id) values (1)')		# indicamos el comando
db.commit()						# tras un comando se realiza un commit
c2 = db.cursor()
c2.execute('select * from data')			# indicamos la consulta a lanzar
for row in c2:						# recorremos el cursor
  print row
c3 = db.cursor()
c3.execute('select * from data')
lst = c3.fetchall()					# extrae el resultado en una lista
c1.close()						# cerramos la primera conexión

Insertar una fecha

t = time.localtime()
ts = sqlite3.Timestamp(t[0], t[1], t[2], t[3], t[4], t[5]);
c.execute ("insert into fecha (fecha) values (?)", (ts,))

Insertar un blob

query = u'''insert into data VALUES(?, ?)'''
c = db.cursor()
b = sqlite3.Binary(data)
c.execute(query,(id,b))
db.commit()

Datos binarios

Módulo binascii

Existe el módulo binascii que trae distintas funciones para recoger los datos en un formato u otro:

import binascii
binascii.b2a_base64(data)
binascii.b2a_hex(data)
binascii.b2a_uu(data)
binascii.crc32(data, 0)
binascii.hexlify(data)

Módulo array

También podemos hacerlo mediante el módulo array, este define un objeto con un tipo concreto (caracteres, integers, floats…) el cual se indica en la creación que es de la siguiente forma:

import array
a = array.array('c', data)

Siendo el primer parámetro pasado (c en este caso) el tipo que es. Los tipos se definen por (c (caracter a partir de un byte), b, B, u, h (short a partir de dos bytes), H, i (integer a partir de dos bytes), I, l (long a partir de cuatro bytes), L, f (float a partir de cuatro bytes), d (doubles a partir de cuatro bytes)).

Módulo struct

Muy útil para la extracción de datos tipados de una cadena en bytes, y viceversa, pasar datos a cadena de bytes.
Para recoger datos utilizamos la función unpack a la cual se le pasa un formato (que se forma a partir de los valores de la siguiente tabla) y la cadena de bytes:

format tipo leido numero de bytes
c char 1
b byte 1
B ubyte 1
h short 2
H ushort 2
i int 4
I uint 4
l long 4
L ulong 4
q long (64b) 8
Q ulong (64b) 8
f float ?
d double 8
s char[] 1
p char[] 1

Con este formato podríamos indicar qué es lo que viene en la cadena de bytes pasada, por ejemplo, cHIII esperaría a leer de los bytes un carácter, un unsigned short y tres unsigned int, es decir, la cadena de bytes debería de tener 11 bytes. El ejemplo también lo podríamos escribir como cH3I, el resultado sería una lista. En el siguiente ejemplo se tiene un array de bytes (data) y se sabe que el primer es un número y el segundo un carácter. Luego también habría otro byte, pero este se imprimiría en la siguiente línea:

print struct.unpack("Bc", data[:2])
print struct.unpack("B", data[2:3])

El primer carácter del formato puede indicar hacia donde se dirigen los bytes, por ejemplo puede ser:

  • !: Como se envia por red.
  • <: Little-endian.
  • >: Big-endian.

Otras funciones útiles podrían ser calcsize que pasándole un formato indica qué tamaño debería de tener este:

struct.calcsize('hhl')								# 8

O también podemos aprovechar el tipo namedtuple para crear objetos:

from collections import namedtuple
Student = namedtuple('Student', 'name serialnum school gradelevel')
Student._make(unpack('<10sHHb', data))						# Student(name='raymond   ', serialnum=4658, school=264, gradelevel=8)

Y si quisieramos leer de un archivo binario…

import struct
f = file('test.chm','r')
s = f.read(4*1 + 3*4)
struct.unpack("4s3I", s)							# ('ITSF', 3L, 96L, 1L)

Logging

Niveles de log: DEBUG, INFO, WARNING, ERROR, CRITICAL
El nivel por defecto es WARNING.
Desde cualquier módulo que se llame a logging se escribirá en el log general.

import logging
logging.warning('Watch out!')
logging.info('I told you so')

Esto tendrá la siguiente salida. No aparece la de info debido a que no se ha cambiado el nivel por defecto y root es el log por defecto también:

WARNING:root:Watch out!

Configuración básica

import logging
logging.basicConfig(filename='example.log',level=logging.DEBUG)
logging.debug('This message should go to the log file')
logging.info('So should this')
logging.warning('And this, too')

Mediante los parámetros de logging.basicConfig podemos indicar:

  • filename: fichero de log.
  • level: nivel de log (logging.DEBUG, logging.WARNING…)
  • filemode: según lo que se haga con el fichero (w para reescribirlo cada vez que arranque).
  • format: Utilizando el formato podemos indicar cosas como: '%(asctime)s %(message)s.
  • datefmt: Para indicar el formato de la fecha ('%m/%d/%Y %I:%M:%S %p').

Indicar varias fuetes

Podemos crear varios logs (a parte del root) para organizarlo:

logger1 = logging.getLogger('myapp.area1')
logger2 = logging.getLogger('myapp.area2')
logger1.debug('Quick zephyrs blow, vexing daft Jim.')
logger1.info('How quickly daft jumping zebras vex.')
logger2.warning('Jail zesty vixen who grabbed pay from quack.')
logger2.error('The five boxing wizards jump quickly.')

Indicar varios logs

Añadir, por ejemplo, la consola y darle otro formato (los sublogs también lo cogerán):

console = logging.StreamHandler()
console.setLevel(logging.INFO)
formatter = logging.Formatter('%(name)-12s: %(levelname)-8s %(message)s')
console.setFormatter(formatter)
logging.getLogger('').addHandler(console)
logging.info('Jackdaws love my big sphinx of quartz.')

Configurar un log mediante un fichero

import logging
import logging.config
logging.config.fileConfig('logging.conf')
logger = logging.getLogger('simpleExample')
logger.debug('debug message')

Este sería el contenido de logging.conf:

[loggers]
keys=root,simpleExample

[handlers]
keys=consoleHandler

[formatters]
keys=simpleFormatter

[logger_root]
level=DEBUG
handlers=consoleHandler

[logger_simpleExample]
level=DEBUG
handlers=consoleHandler
qualname=simpleExample
propagate=0

[handler_consoleHandler]
class=StreamHandler
level=DEBUG
formatter=simpleFormatter
args=(sys.stdout,)

[formatter_simpleFormatter]
format=%(asctime)s - %(name)s - %(levelname)s - %(message)s
datefmt=

Imports dinámicos

A partir del módulo imp podemos realizar imports por código. Este módulo tiene funciones como…

  • load_module para cargar el módulo.

Otros

Donde podemos encontrar...

  • Números aleatorios?, en el módulo random.
    • random.choice escoge un elemento de la lista.
    • random.randint devuelve un entero entre dos números (incluidos).
  • Un método de sleep?, en el módulo time existe la función sleep.

Funciones

  • copy.copy copiará un objeto en otro.
  • random.shuffle desordenará una colección.
script/python/new/api.1376479558.txt.gz · Última modificación: 2020/05/09 09:24 (editor externo)