We have made a small selection of Python tricks for you, which, we hope, will greatly facilitate your work. We advise the article to advanced users.
Python is full of amazing features and tricks that make you think, “Wow! Python is so cool! ” We’ve put together a few features that we especially love. We hope you learn something that makes you say, “Wow! I did not know that”.
The source code is on GitHub , if you have any ideas for improving it, you’re welcome!
Generators in Python
A generator is an object that creates a sequence of values. It can be used like an iterator, which means you can use it with a for statement or use the next function to get the next value. However, you can iterate over values only once.
A generator can be created using a function whose keyword is yield (creates a value). When a generator function is called, a generator object is created.
def fibonacci_generator():
a, b = 0, 1
while True:
yield a
a, b = b, a + b
# Печатает все числа последовательности Фибоначчи, меньше 1000
for i in fibonacci_generator():
if i > 1000:
break
print(i)
For simple cases, you can create a generator using a generator expression. Unlike a list, values will be computed on the fly, rather than cluttering memory with them for a one-time computation.
a = (x * x for x in range(100))
# a объект-генератор
print(type(a))
# Сумма всех числе
print(sum(a))
# В генераторе не осталось чисел
print(sum(a))
Collections module
Collections is a module in the standard library that implements containers of alternative data types.
For example, counter is a collection of elements that are stored as dictionary keys, and their counters are stored as dictionary values:
from collections import Counter
a = Counter('blue')
b = Counter('yellow')
print(a)
print(b)
print((a + b).most_common(3))
Defaultdict is a dict subclass that allows for a factory function used to automatically create a new value in the absence of a key.
from collections import defaultdict
my_dict = defaultdict(lambda: 'Default Value')
my_dict['a'] = 42
print(my_dict['a'])
print(my_dict['b'])
Defaultdict can be used to create a tree data structure!
from collections import defaultdict
import json
def tree():
"""
Factory that creates a defaultdict that also uses this factory
"""
return defaultdict(tree)
root = tree()
root['Page']['Python']['defaultdict']['Title'] = 'Using defaultdict'
root['Page']['Python']['defaultdict']['Subtitle'] = 'Create a tree'
root['Page']['Java'] = None
print(json.dumps(root, indent=4))
Itertools module
itertools is a module in the standard library that allows you to create iterators for efficient looping.
For example, permutations allows you to generate all the possible ways to order a set of things:
from itertools import permutations
for p in permutations([1,2,3]):
print(p)
Likewise, combinations creates every possible way to select items from a collection, so that (unlike permutations) the order doesn’t matter:
from itertools import combinations
for c in combinations([1, 2, 3, 4], 2):
print(c)
itertools also contains helper functions such as chain, which takes an iterable and creates a new iterator that returns items from the data, one at a time, as a single sequence:
from itertools import chain
for c in chain(range(3), range(12, 15)):
print(c)
Packing / Unpacking in Python
The * – operator, known as the unboxing or splat operator, allows for very convenient conversions, going from lists or tuples of a single variable or arguments, and vice versa.
a, *b, c = [2, 7, 5, 6, 3, 4, 1]
print(a)
print(b)
print(c)
When the arguments to your function are already in a list or tuple, you can unpack them with * args if it’s a list, or ** kwargs if it’s a dict.
def repeat(count, name):
for i in range(count):
print(name)
print("Call function repeat using a list of arguments:")
args = [4, "cats"]
repeat(*args)
print("Call function repeat using a dictionary of keyword arguments:")
args2 = {'count': 4, 'name': 'cats'}
repeat(**args2)
The reverse operation is also possible: you can define a function that will pack all arguments into one tuple and all keywords into one dict.
def f(*args, **kwargs):
print("Arguments: ", args)
print("Keyword arguments: ", kwargs)
f(3, 4, 9, foo=42, bar=7)
Decorators in Python
decorator is a function that takes a function as a parameter and returns a function.
For example, in the code below, the cache function is used as a decorator to store Fibonacci numbers that have already been calculated:
def cache(function):
cached_values = {} # Cодержит уже посчитанные числа
def wrapping_function(*args):
if args not in cached_values:
# Вызывает функцию только если мы еще не сделали этого для этих параметров
cached_values[args] = function(*args)
return cached_values[args]
return wrapping_function
@cache
def fibonacci(n):
print('calling fibonacci(%d)' % n)
if n < 2:
return n
return fibonacci(n-1) + fibonacci(n-2)
print([fibonacci(n) for n in range(1, 9)])
The Functools module provides us with several decorators, such as lru_cache, that can do what we just did: remember. It saves recent calls to save time when the function is called with the same arguments:
from functools import lru_cache
@lru_cache(maxsize=None)
def fibonacci(n):
print('calling fibonacci(%d)' % n)
if n < 2:
return n
return fibonacci(n-1) + fibonacci(n-2)
print([fibonacci(n) for n in range(1, 9)])
Context managers
Context managers are mainly used to manage resources properly. They are most commonly used to open a file: open (‘workfile’, ‘r’) as f :. However, most developers don’t know how they all actually work and how to create your own.
In fact, a context manager is just a class that implements the __enter__ and __exit__ methods.
from time import time
class Timer():
def __init__(self, message):
self.message = message
def __enter__(self):
self.start = time()
return None # Возвращает что угодно, чтобы использовать следующим образом:
Timer("Message") as value:
def __exit__(self, type, value, traceback):
elapsed_time = (time() - self.start) * 1000
print(self.message.format(elapsed_time))
with Timer("Elapsed time to compute some prime numbers: {}ms"):
primes = []
for x in range(2, 500):
if not any(x % p == 0 for p in primes):
primes.append(x)
print("Primes: {}".format(primes))
In simple cases it is possible to use a single yield function generator using the @contextmanager decorator.
from contextlib import contextmanager
@contextmanager
def colored_output(color):
print("\033[%sm" % color, end="")
yield
print("\033[0m", end="")
print("Hello, World!")
with colored_output(31):
print("Now in color!")
print("So cool.")