пятница, 10 мая 2013 г.

Различные тонкости Python


Оператор сечения

Чтобы извлечь подстроку, можно использовать оператор сечения s[i:j]. Он извлечет из строки s все символы с порядковыми номерами k в диапазоне i<=k<j. Если какой-либо из индексов опущен, то он полагается равным началу или концу строки соответственно.

Оператор повторения

print '_'*10 
>>_ _ _ _ _ _ _ _ _ _

Строковое представление списка

ls = ['aaa', 'bbb', 'ccc']
print '---'.join(ls)
>>aaa---bbb---ccc

Оператор join помогает формировать строковое представление списка, помещая между элементами списка указанные символы.

Оператор with

Синтаксически выглядит так:

with выражение:
     блок кода

Упрощает код, который раньше использовал try...finally... для гарантированного исполнения завершающего кода. Например:

with open('f.txt', 'r') as f:
     for line in f:
     print line

В данном примере не только нам не нужно писать f.close(), т.к. из-за использования with файл автоматически будет закрыт, но и если в процессе чтения или обработки данных из файла возникнет ошибка, то файл все равно будет закрыт.

Рекурсия

#пример вычисления факториала

def factorial(n):
     if n <= 1: return 1
     else: return n*factorial (n-1)

Существует ограничение на глубину рекурсии. По умолчанию предел равен 1000.

Итерация с индексами

Такой прием работает не только со списками, но и с другими последовательностями (например, строками):

my_list = ['a', 'b', 'c']
for i,char in enumerate(my_list):
     print i, char

>>0 a
>>1 b
>>2 c

Упорядоченный словарь

Иногда при чтении из словаря требуется, чтобы при этом его ключи были упорядочены. Тогда на помощь приходит OrderedDict, который запоминает, в каком порядке в него были добавлены элементы.

d = {2:3, 1:89, 4:5, 3:0}
od = collections.OrderedDict(sorted(d.items()))
for k,v in od.iteritems(): print k,v
>>1 89
>>2 3
...

Генераторы

Вместо единственного значения функция с помощью инструкции yield может генерировать целые последовательности результатов. Например:

def countdown(n):
    print "Обратный отсчет!"
    while n > 0:
        yield n
        n -= 1

Любая функция, которая использует инструкцию yield, называется генератором. Метод next() заставляет функцию-генератор выполняться, пока не будет достигнута следующая инструкция yield:

c = countdown(5)
print c.next()
>>"Обратный отсчет!"
>>5
print c.next()
>>4
...

Функция-генератор обычно используется в инструкции цикла for, например:

for i in countdown(5):
    print i

>>"Обратный отсчет!"
>>5
>>4
...

Генераторы списков

Генераторы списков - конструкции, которые облегчают работу со списками. Генератор списка обычно имеет вид [выражение(x) for x in некоторый_список]. В результате его использования мы получаем список, каждый элемент которого равен результату применения некоторого выражения к соответствующему элементу некоторого списка.
К примеру, функцию, которая на вход получает список положительных чисел numlist и возвращает сумму их последних цифр, можно написать так:

ls = [str(l)[-1:] for l in numlist]
ls = map(int, ls)
print sum(ls)

Отметим, что map - еще одна полезная конструкция. Она получает на вход список и применяет к каждому его элементу указанную функцию (в данном случае преобразовывает в целое число каждый элемент списка ls)

Ключевое слово лямбда

Может использоваться для создания небольших анонимных функций. Анонимными называются функции, объявляемые в месте использования и не получающие уникального идентификатора для доступа к ним. Может возникнуть вопрос: зачем вообще нужны эти анонимные функции? Если использовать ключевое слово лямбда в связке с такими функциями как map, reduce и filter, то можно сократить код (и таким образом сделать его более легким для восприятия). Ниже приведены примеры полезности лямбды.

foo = [2,18,9,22,17,24,8,12,27]

#отфильтруем список, оставив только те числа, которые без остатка делятся на 3

print filter(lambda x: x%3 == 0, foo)
>> [18, 9, 24, 12, 27]

#преобразуем список foo, умножив каждый элемент на 2 и прибавив 10

print map(lambda x: x*2 + 10, foo)
>>[14,46,28,54,44, 58,26,34,64]

'''получим сумму всех элементов списка. Функция reduce при первом вызове делает что-то с двумя первыми элементами, потом что-то с результатом и третьим элементом, и т.д.'''

print reduce(lambda x,y: x+y, foo)
>>139

А вот еще пара примеров применения лямбды. 

#узнать длины слов в предложении

sentence = "It is raining cats and dogs"
words = sentence.split()
lengths = map(lambda word: len(word), words)

#вывести True, если число четное и False в противном случае

g = lambda x: not bool(x % 2)
print g(4)
>>True

Сопрограммы

Функцию можно написать так, что она будет действовать как программа, обрабатывающая последовательность входных данных. Такие функции называются сопрограммами, а создаются они с помощью инструкции yield, используемой в выражении yield:

def print_matches(matchtext):
     print "Поиск подстроки ", matchtext
     while True:
          line = (yield)
          if matchtext in line:
               print line

matcher = print_matches("Python")
matcher.next()
>> Поиск подстроки python
matcher.send("Hello world")
>>
matcher.send("Python is cool")
>> Python is cool

matcher.close()

Сопрограммы удобно использовать при разработке многозадачных программ, когда одна часть программы производит некоторые данные, а другая потребляет их.

Функции в Python

Функции в Python могут передаваться другим функциям в виде аргументов, сохраняться в структурах данных и возвращаться функциями в виде результата.

Пример 1. Передача функции в виде аргумента

def callf(func):
     return func()

def helloworld():
     print "Привет, мир!"

callf(helloworld)
>>Привет, мир!

Пример 2. Сохранение в структурах данных.

Следующий кусок кода 


def function1():
    print '1'
    
def function2():
    print '2'
    
def function3():
    print '3'

if value == 'one':
    function1()
elif value == 'two':
    function2()
elif value == 'three':
    function3()

можно переписать так:


switch = {
     'one': function1,
     'two': function2,
     'three': function3,
}

choice = raw_input('Enter one, two or three')
try:
     result = switch[choice]()  #получаем функцию и тут же вызываем ее
except KeyError:
     print "I didn\'t understand your choice"

Замыкание      

Замыкание - процедура или функция, в теле которой присутствуют ссылки на переменные, объявленные вне тела этой функции и не в качестве ее параметров (а в окружающем коде). Рассмотрим следующий пример.

#файл foo.py
x = 42
def callf(func):
     return func()

#какой-то другой файл 
import foo
x= 37
def helloworld():
     return "Привет, мир!" x = %d % x

foo.callf(helloworld)
>>Привет, мир! x=37

Обратим внимание, что функция helloworld использует то значение переменной x,  которое была определено в том же окружении, что и сама функция helloworld. Когда инструкции, составляющие функцию, упаковываются вместе с окружением, в котором они выполняются, получившийся объект называют замыканием. 

Args и Kwargs

* - синтаксис для распаковки кортежа, ** - для распаковки словаря.
Рассмотрим следующий пример.

def tuple_test(x,y):
     x += 1
     y += 1
     print x, y

Если мы попробуем подать на вход этой функции кортеж, то будет ошибка:
t = (1,2)
tuple_test(t) #ошибка!

Ошибка возникнет потому, что функции нужны 2 аргумента, а кортеж будет интерпретироваться как 1 аргумент. Для того, чтобы ошибки не было, кортеж нужно распаковать:

tuple_test(*t)
>>2 3

То же самое для словаря:

d = {'x':1, 'y': 2}
tuple_test(d) #ошибка!

tuple_test(**d)
>>2 3

Ключевые слова args и kwargs используются при задании функций в случаях, когда заранее не известно количество и состав аргументов функции. Например:

def foo(*args, **kwargs):
     return args if args else kwargs

print foo(1,2)
>>(1,2)

print foo(1,2,3)
>>(1,2,3)

print foo(x=1, y=2)
>>{'x': 1, 'y': 2}

Декоратор

Декоратор - функция, основное назначение которой состоит в том, чтобы служить оберткой для другой функции или класса. Главная цель такого обертывания - изменить или расширить возможности обертываемого объекта. Например, в Django веб-приложении можно встретить такое:

from django.contrib.auth.decorators import login_required

@login_required
def my_view(request):
     ...

Функция login_required - декоратор, служит оберткой для функции my_view. login_required делает следующее:

если пользователь не залогинен, перенаправляет его на страницу авторизации,
в противном случае вызывает функцию my_view, которая формирует соответствующую html-страницу.

Вот еще пример декоратора.

enable_tracing = True

def trace(func):
    if enable_tracing:
        print "tracing..."
    else:
        return func
@trace
def square(x):
    return x*x

try:
    print square(2)
except:
    pass

>>tracing...

Информационные источники:



Комментариев нет:

Отправить комментарий