Muestra las diferencias entre dos versiones de la página.
| Ambos lados, revisión anterior Revisión previa Próxima revisión | Revisión previa | ||
|
script:python:new:advanced [2013/08/13 14:55] alfred [Expresiones lambda] |
script:python:new:advanced [2020/05/09 09:25] (actual) |
||
|---|---|---|---|
| Línea 26: | Línea 26: | ||
| >>> [ word[0] for word in listOfWords ] | >>> [ word[0] for word in listOfWords ] | ||
| ['t', 'i', 'a', 'l', 'o', 'w'] | ['t', 'i', 'a', 'l', 'o', 'w'] | ||
| + | >>> ['object ' + arg.__class__.__name__ if isinstance(arg, types.ObjectType) else arg for arg in args] | ||
| </code> | </code> | ||
| El siguiente crea pares de género (primero para news y luego para romance) y palabra en mayúsculas: | El siguiente crea pares de género (primero para news y luego para romance) y palabra en mayúsculas: | ||
| Línea 52: | Línea 53: | ||
| <code python> | <code python> | ||
| users_first_names = {user.first_name for user in users} | users_first_names = {user.first_name for user in users} | ||
| + | other = {x+x for x in 'patata'} # -> {'pp', 'aa', 'tt'} | ||
| + | </code> | ||
| + | También puedes anidarlas: | ||
| + | <code python> | ||
| + | matrix = [[1, 2], [3, 4]] | ||
| + | [1, 2, 3, 4] | ||
| </code> | </code> | ||
| - | |||
| ==== Generators ==== | ==== 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. \\ | 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. \\ | ||
| Línea 71: | Línea 77: | ||
| filtered_gen.next() | filtered_gen.next() | ||
| filtered_gen.next() | filtered_gen.next() | ||
| + | </code> | ||
| + | Otro ejemplo: | ||
| + | <code python> | ||
| + | def route(*args): | ||
| + | return ':'.join(str(arg) for arg in args) | ||
| + | route('user', 32, 'friends') # -> "user:32:friends" | ||
| </code> | </code> | ||
| ==== yield ==== | ==== yield ==== | ||
| Línea 163: | Línea 175: | ||
| map(lambda x: x**2, range(5)) # -> [0, 1, 4, 9, 16] | map(lambda x: x**2, range(5)) # -> [0, 1, 4, 9, 16] | ||
| filter(lambda x: x % 2, range(10)) # -> [1, 3, 5, 7, 9] | filter(lambda x: x % 2, range(10)) # -> [1, 3, 5, 7, 9] | ||
| + | </code> | ||
| + | ==== Tipos de datos ==== | ||
| + | Comprobar el tipo de una variable: | ||
| + | <code python> | ||
| + | type(o) is str | ||
| + | isinstance(o, str) | ||
| + | </code> | ||
| + | |||
| + | Saber si es una subclase: | ||
| + | <code python> | ||
| + | issubclass(type(o), str) | ||
| + | </code> | ||
| + | |||
| + | Saber si... | ||
| + | <code python> | ||
| + | isinstance(obj, types.FunctionType) # es función | ||
| + | </code> | ||
| + | |||
| + | Para comprobar si es un string (del que sea) estas dos son válidas: | ||
| + | <code python> | ||
| + | isinstance(o, basestring) | ||
| + | isinstance(o, (str, unicode)) | ||
| + | </code> | ||
| + | ==== Decorators ==== | ||
| + | Las funciones son objetos del lenguaje, como tal pueden ser pasadas a otras funciones como parámetros. \\ | ||
| + | Un decorador no es más que una función que recibe otra, le añade funcionalidad y la devuelve: | ||
| + | <code python> | ||
| + | def identity_decorator(func): | ||
| + | def wrapper(): | ||
| + | func() | ||
| + | return wrapper | ||
| + | |||
| + | def a_function(): | ||
| + | print "I'm a normal function." | ||
| + | |||
| + | decorated_function = identity_decorator(a_function) | ||
| + | decorated_function() | ||
| + | # >> I'm a normal function | ||
| + | </code> | ||
| + | El scope de ''wrapper'' es ''identity_decorator''. En el siguiente ejemplo se utiliza un ''mutable object'' (diccionarios, listas, instancias...). Un simple integer sería inmutable dentro de wrapper y de solo lectura. | ||
| + | <code python> | ||
| + | def logging_decorator(func): | ||
| + | def wrapper(): | ||
| + | wrapper.count += 1 | ||
| + | print "The function I modify has been called {0} times(s).".format( | ||
| + | wrapper.count) | ||
| + | func() | ||
| + | wrapper.count = 0 | ||
| + | return wrapper | ||
| + | |||
| + | def a_function(): | ||
| + | print "I'm a normal function." | ||
| + | |||
| + | modified_function = logging_decorator(a_function) | ||
| + | modified_function() | ||
| + | # >> The function I modify has been called 1 time(s). | ||
| + | # >> I'm a normal function. | ||
| + | modified_function() | ||
| + | # >> The function I modify has been called 2 time(s). | ||
| + | # >> I'm a normal function. | ||
| + | </code> | ||
| + | |||
| + | === *args y **kwargs === | ||
| + | Para acceder a los parámetros de una llamada aprovecharemos ''*args'' (que contiene los parámetros por defecto de la función) y ''<nowiki>**kwargs</nowiki>'' (los especificados no por defecto en forma de diccionario). Puedes mirar el [[script:python:new:language#funciones|apartado de funciones]]. | ||
| + | |||
| + | === Wraps en functools === | ||
| + | Es un decorador que mantiene las propiedades el objeto función (como ''<nowiki>__name__, __class__...</nowiki>''), que si no se utilizase quedaría con las propiedas de la función que lo decora. | ||
| + | <code python> | ||
| + | from functools import wraps | ||
| + | def memoize(func): | ||
| + | cache = {} | ||
| + | @wraps(func) | ||
| + | def wrapper(*args): | ||
| + | ... | ||
| + | </code> | ||
| + | |||
| + | === Sintaxis === | ||
| + | Podemos emular el código anterior utilizando la sintaxis ''@nombre_func'': | ||
| + | <code python> | ||
| + | def some_function(): | ||
| + | print "I'm happiest when decorated." | ||
| + | # Here we will make the assigned variable the same name as the wrapped function | ||
| + | some_function = logging_decorator(some_function) | ||
| + | # We can achieve the exact same thing with this syntax: | ||
| + | @logging_decorator | ||
| + | def some_function(): | ||
| + | print "I'm happiest when decorated." | ||
| + | </code> | ||
| + | |||
| + | === Decoradores de clases === | ||
| + | También pueden ser añadidos a clases para, por ejemplo, agregar nuevos parámetros: | ||
| + | <code python> | ||
| + | foo = ['important', 'foo', 'stuff'] | ||
| + | def add_foo(klass): | ||
| + | klass.foo = foo | ||
| + | return klass | ||
| + | @add_foo | ||
| + | class Person(object): | ||
| + | pass | ||
| + | </code> | ||
| + | |||
| + | === O clases de decoradores === | ||
| + | <code python> | ||
| + | class IdentityDecorator(object): | ||
| + | def __init__(self, func): | ||
| + | self.func = func | ||
| + | def __call__(self): | ||
| + | self.func() | ||
| + | @IdentityDecorator | ||
| + | def a_function(): | ||
| + | print "I'm a normal function." | ||
| + | </code> | ||
| + | |||
| + | === Argumentos a decoradores === | ||
| + | <code python> | ||
| + | from functools import wraps | ||
| + | def argumentative_decorator(gift): | ||
| + | def func_wrapper(func): | ||
| + | @wraps(func) | ||
| + | def returned_wrapper(*args, **kwargs): | ||
| + | print "I don't like this " + gift + " you gave me!" | ||
| + | return func(gift, *args, **kwargs) | ||
| + | return returned_wrapper | ||
| + | return func_wrapper | ||
| + | @argumentative_decorator("sweater") | ||
| + | def grateful_function(gift): | ||
| + | print "I love the " + gift + "! Thank you!" | ||
| + | grateful_function() | ||
| + | # >> I don't like this sweater you gave me! | ||
| + | # >> I love the sweater! Thank you! | ||
| + | </code> | ||
| + | <code python> | ||
| + | from functools import wraps | ||
| + | GLOBAL_NAME = "Brian" | ||
| + | def print_name(function=None, name=GLOBAL_NAME): | ||
| + | def actual_decorator(function): | ||
| + | @wraps(function) | ||
| + | def returned_func(*args, **kwargs): | ||
| + | print "My name is " + name | ||
| + | return function(*args, **kwargs) | ||
| + | return returned_func | ||
| + | if not function: # User passed in a name argument | ||
| + | def waiting_for_func(function): | ||
| + | return actual_decorator(function) | ||
| + | return waiting_for_func | ||
| + | else: | ||
| + | return actual_decorator(function) | ||
| + | @print_name | ||
| + | def a_function(): | ||
| + | print "I like that name!" | ||
| + | @print_name(name='Matt') | ||
| + | def another_function(): | ||
| + | print "Hey, that's new!" | ||
| + | a_function() | ||
| + | # >> My name is Brian | ||
| + | # >> I like that name! | ||
| + | another_function() | ||
| + | # >> My name is Matt | ||
| + | # >> Hey, that's new! | ||
| + | </code> | ||
| + | |||
| + | === Ejemplo memoization === | ||
| + | Este decorator hace que, cuando la función es llamada con los mismos parámetros devuelva el mismo resultado (memoriza el cálculo): | ||
| + | <code python> | ||
| + | from functools import wraps | ||
| + | def memoize(func): | ||
| + | cache = {} | ||
| + | @wraps(func) | ||
| + | def wrapper(*args): | ||
| + | if args not in cache: | ||
| + | cache[args] = func(*args) | ||
| + | return cache[args] | ||
| + | return wrapper | ||
| + | @memoize | ||
| + | def an_expensive_function(arg1, arg2, arg3): | ||
| + | </code> | ||
| + | |||
| + | === Notas === | ||
| + | * [[https://wiki.python.org/moin/PythonDecoratorLibrary|Decorators library]] | ||
| + | * [[http://code.activestate.com/search/recipes/#q=decorator|Búsqueda en la decorators library]] | ||
| + | |||
| + | ==== Unicode ==== | ||
| + | Para poder escribir por consola unicode: | ||
| + | <code python> | ||
| + | import sys | ||
| + | reload(sys) | ||
| + | sys.setdefaultencoding('utf-8') | ||
| </code> | </code> | ||
| ===== El lenguaje ===== | ===== El lenguaje ===== | ||