Herramientas de usuario

Herramientas del sitio


script:python:new:advanced

¡Esta es una revisión vieja del documento!


Python avanzado

Pequeños conceptos

Comprehesion lists

Crean una lista a partir de otras.
Siguen el formato [variable_devuelta bucle(s) condicion(es)]:

>>> lst = [4, 6, 1, 8, 3, 0, 5, 9, 10, 7, 2]		# Creación de la lista inicial
>>> big = [n for n in lst if n > 5]			# Selección de números mayores que 5
>>> big
[6, 8, 9, 10, 7]
>>> sbig = sorted([n for n in lst if n > 5])		# Y ordenados
>>> sbig
[6, 7, 8, 9, 10]
>>> sbig = sorted(n for n in lst if n > 5)		# Aunque entre paréntesis no es necesario poner los corchetes
>>> sbig
[6, 7, 8, 9, 10]
>>> lst2 = [3, 5, 9]
>>> [(n, n2) for n in lst for n2 in lst2 if n == n2]
[(3, 3), (5, 5), (9, 9)]
>>> [n for n in lst for n2 in lst2 if n == n2]
[3, 5, 9]
>>> listOfWords = ["this","is","a","list","of","words"]
>>> [ word[0] for word in listOfWords ]
['t', 'i', 'a', 'l', 'o', 'w']
>>> ['object ' + arg.__class__.__name__ if isinstance(arg, types.ObjectType) else arg for arg in args]

El siguiente crea pares de género (primero para news y luego para romance) y palabra en mayúsculas:

genre_word = [(genre, word.upper())
    for genre in ['news', 'romance']
    for word in words(categories=genre)]

Pueden ser combinadas con funciones del sistema como any o all:

myList = (2, 3, 5, 6)
print any(x == 1 for x in myList)	# False
print any(x == 5 for x in myList)	# True

También los diccionarios pueden ser creados así:

user_email = {user.name: user.email for user in users_list if user.email}

Esto crearía un objeto del estilo:

user_email = {'alfredgg': 'alfredgg@yahoo.es', 'diabolika': 'diabolikalau@gmail.com'}

O los sets:

users_first_names = {user.first_name for user in users}
other = {x+x for x in 'patata'} # -> {'pp', 'aa', 'tt'}

Generators

Los generators son valores que se van generando on the fly, es decir, sólo puedes recoger un valor una vez ya que la lista no se guarda en memoria.
La sintaxis es la misma pero con paréntesis:

mygenerator = (x*x for x in range(3))
for i in mygenerator :
  print(i)

Los generadores no soportan el indexado (gen[3] daría error) ni el slicing (gen[:3] también daría error). Tampoco pueden concatenarse a las listas ni podremos realizar las funciones que hacemos con estas (consultar su tamaño, ordenarlo…).

Podemos realizar las siguientes acciones sobre ellos:

  • .next(), devuelve el siguiente valor.
  • list(g), convertiría el generador en una lista.
filtered_gen = (item for item in my_list if item > 3)
filtered_gen.next()
filtered_gen.next()
filtered_gen.next()

Otro ejemplo:

def route(*args):
    return ':'.join(str(arg) for arg in args)
route('user', 32, 'friends') # -> "user:32:friends" 

yield

Es una especie de return dentro de un bucle pero que conserva su valor para la próxima vez que se le invoque. Es decir, retorna un generator.

def func(l):
  while True:				# Genera valores infinitos
    for v in l: yield v
it = func([1, 9, 5, 6, 3])
it.next()				# 1
it.next()				# 9
it.next()				# 5

Context manager (with)

  • Son usados para estar seguros de que un recurso queda liberado después de utilizarlo.
  • Su sintaxis es: with <inicialización> as <nombre de variable>: <bloque>.
# Este código no libera file_handle si ocurre una excepción (MAL!):
file_handle = open(path_to_file, 'r')
for line in file_handle.readlines():
  if raise_exception(line):
    print('No! An Exception!')
############
# Código CORRECTO:
with open(path_to_file, 'r') as file_handle:
  for line in file_handle:
    if raise_exception(line):
      print('No! An Exception!')

Podemos definir clases que trabajen como context manager definiendo los métodos __enter__ y __exit__, o funciones a partir del módulo contextlib.

Reflection

# sin reflection:
Foo().hello()
 
# con reflection:
getattr(globals()['Foo'](), 'hello')()
  • getattr recoge un atributo por string de una clase, colección…
  • dir devuelve en string los atributos y métodos de ese objeto.
  • El método getmro de inspect devuelve la herencia de una clase.

El siguiente ejemplo recoge las propiedades\métodos de un objeto y mira su herencia, si vienen de DataType realizará una acción con ellas.

def load (self, config):
   import inspect
   attrs = [getattr(self, prop) for prop in dir(self)]
   for attr in attrs:
      types = inspect.getmro(attr.__class__)
      if types[len(types)-1] == DataType:
         attr.load(config[attr.configname])

Expresiones lambda

Una expresión lambda es una función sencilla de una sola línea. Son virtuales y no tienen un nombre con el que llamarlas. Se crean, se ejecutan y desaparecen, pero puedes guardarlas en una variable y llamarlas desde ella.

Sintaxis

lambda <parametro1, parametro2…> : <línea de código devuelta>

a = lambda x,y : x*y
a(3,4)						# devolvería 12

Llamada a una expresión lambda sin almacenar

(lambda x: x*2)(3)				# devolvería 6

Map (high-order function)

Realiza una llamada a una función para cada elemento del array:

lst = [1, 5, 8, 6, 4, 2, 3]
map ((lambda x : x*3), lst)			# retornaría: [3, 15, 24, 18, 12, 6, 9]

Filter (high-order function)

Retorna los elementos de una lista que al evaluarla con una función devuelven True:

lst = [1, 5, 8, 6, 4, 2, 3]
filter((lambda x : x < 5), lst)			# retornaría: [1, 4, 2, 3]

Reduce (high-order function)

Ejecuta una función para cada elemento de un array acumulando su valor:

lst = [1, 5, 8, 6, 4, 2, 3]
reduce((lambda x,y : x+y), lst)			# retornaría: 29, la suma de todos los elementos de la colección

Ejemplos de uso

Función de comparación por longitud:

my_cmp = (lambda x,y: cmp(len(x), len(y)))
my_cmp('abc', 'de')

Relación con las comprehesion lists

Pueden ser usadas en vez de las comprehesion lists (y son preferibles):

map(lambda x: x**2, range(5)) # -> [0, 1, 4, 9, 16]
filter(lambda x: x % 2, range(10)) # -> [1, 3, 5, 7, 9]

El lenguaje

Python trabaja internamente con objetos. Pocos son los datos que se guardan como valores y lo que comunmente denominamos “variables” serían mejor llamadas “nombres”. Y es que una asignación es un enlace de un nombre a un objeto.

>>> foo = Foo()
>>> foo = 10
>>> print(foo.__add__)
<method-wrapper '__add__' of int object at 0x8502c0>

Podríamos comprobar el string que devuelve una referencia con otra para saber si pertenecen al mismo objeto (ya que ese string representa la dirección de memoria en la que está almacenado). Aún así la forma de hacerlo correctamente es usando is.

is también es el comando indicado para comparar con None. Esto es porque None es un objeto singleton dentro del lenguaje.

script/python/new/advanced.1378912286.txt.gz · Última modificación: 2020/05/09 09:24 (editor externo)