Примеры программ на языке Python

Материал из Seo Wiki - Поисковая Оптимизация и Программирование
Перейти к навигацииПерейти к поиску

Примеры программ на языке программирования Python.

В этой статье собраны примеры небольших программ на языке программирования Python, демонстрирующих его синтаксис и некоторые из возможностей.

Нахождение 10 наиболее частых слов на web странице

Данный пример чисто демонстрационный, так как его можно значительно улучшить.

<source lang="python"> import string # импортируем модуль для работы со строками from urllib2 import urlopen # из модуля urllib2 импортируем функцию urlopen

u = urlopen("http://python.org") # открываем URL на чтение words = {} # связываем имя words с пустым словарём

                                   # (словарь — неупорядоченный ассоциативный массив)

for line in u.readlines(): # читаем u по строкам

   line = string.strip(line, " \n")    # отбрасываем начальные и конечные пробелы
   for word in line.split(" "): # режем каждую строку на слова, ограниченные пробелами
       try:                            # блок обработки исключений
           words[word] += 1            # пытаемся увеличить words[word] на единицу
       except KeyError:                # если не получилось (раньше words[word] не было)
           words[word] = 1             # присваиваем единицу
  1. теперь словарь words содержит частоту встречаемости каждого слова.
  2. Например, words может содержать {"яблоко":5, "апельсин": 12, "груша": 8}

pairs = words.items() # делаем из словаря список пар

                                   # pairs == [("яблоко",5), ("апельсин",12), ("груша",8)]

pairs.sort(lambda a, b: b[1]-a[1]) # сортируем по убыванию второго элемента пары

for p in pairs[:10]: # печатаем первые 10 элементов списка

   print p[0], p[1]

</source>

Примеры работы с последовательностями

Иллюстрируют особенности индексации элементов и срезов: при взятии среза нумеруются не сами элементы, а промежутки между ними.

<source lang="python">

>>> l = ['A', 'B', 'C', 'D', 'E']    # исходный список
>>> #   0    1    2    3    4    5   # пронумерованные промежутки между элементами
>>> #   -5   -4   -3   -2   -1       # нумерация с конца
>>> l[0:2]          # срез от нулевого до второго промежутка
['A', 'B']
>>> l[1:-2]         # срез от второго до второго с конца элемента
['B','C']
>>> l[1::2]         # каждый второй элемент начиная с первого
['B', 'D']
>>> l[::-1]         # все элементы в обратном порядке
['E', 'D', 'C', 'B', 'A']

</source> Функции подобные range() поддерживают то же правило: <source lang="python">

>>> range(2, 5)
[2, 3, 4]
>>> range(5)
[0, 1, 2, 3, 4]

</source>

Реализация перегрузки функций

Это пример простой реализации поддержки перегрузки функций на Python. Она демонстрирует, как, используя уже имеющиеся в Python средства, можно обойти одно из ограничений базовой реализации. Поддерживается минимум возможностей (только фиксированное количество позиционных аргументов, нет именованных аргументов, нет приведения типов (например int -> float) и т. п.), но работает достаточно быстро.

<source lang="python"> import sys # для получения объектов из вышележащих фрэймов стека class CannotResolve(Exception):pass # класс исключения для случая ненахождения функции class Resolver(object): # класс, реализующий разрешение на этапе исполнения

   emess = "Can't found appropriate signature of func %s() for call with" + \
           " params %r"                     # сообщение об ошибке
   def __init__(self,name):                 # конструктор
       self.function_map = {}               # словарь, отображающий типы параметров на функции
       self.default = None                  # функция по умолчанию
       self.name = name                     # имя функции для вывода сообщений об ошибках
   def __call__(self,*dt):                  # имитируем функцию, принимающую любое количество 
                                            # позиционных параметров
       cls = tuple(map(type,dt))            # создаем tuple из типов переданных аргументов
                                            # функция type возвращает тип своего параметра
                                            # map вызовет type для каждого элемента из dt
       try:                                 
           x = self.function_map[cls]       # пытаемся получить функцию из словаря
       except KeyError:                     # если подходящей нет,
           if self.default is not None:     # используем функцию по умолчанию
               x = self.default             
           else:                            # если её нет - возбуждаем искючение
               raise CannotResolve(self.emess % (self.name,cls))
       return x(*dt)                        # вызываем функцию и возвращаем результат

def overload(*dt): # декоратор для перегрузки в качестве параметров

                                            # принимает типы параметров
   def closure(func):                       
       name = func.__name__                 # получаем имя функции
       fr = sys._getframe(1).f_locals.get(name,Resolver(name)) 
                                            # опускаемся на один шаг вниз по стеку и находим
                                            # локальную переменную с именем функции
                                            # если же ее нет, то используем новый 
                                            # Resolver-объект
       fr.function_map[dt] = func           # добавляем новую функцию к словарю 
                                            # разрешения вызовов
       return fr                             
   return closure

def overdef(func): # для создания функции по умолчанию

   name = func.__name__                     # аналогично как и в функции overload
   fr = sys._getframe(1).f_locals.get(name,Resolver(name))
   fr.default = func
   return fr
  1. теперь воспользуемся полученными декораторами

@overdef # это будет функция по умолчанию def f(*dt,**mp):

   print "Default call"                     # если нет явного return, то вернется None

@overload(int) # единственный параметр - целое def f(x):

   return x + 1                             

@overload(str) # единственный параметр - строка def f(x):

   return x + "1"

@overload(str,int) # строка и целое def f(x,y):

   return x + str(y)

print f(1) # напечатает : 2 print f("1") # напечатает : 11 f(2,2) # напечатает : Default call </source>

Управление контекстом выполнения

Следующий пример из PEP343 иллюстрирует применение оператора with для защиты блока кода от одновременного выполнения двумя потоками:

<source lang="python"> from __future__ import with_statement # задействует оператор with в коде from contextlib import contextmanager from threading import Lock

  1. Описание менеджера контекста

@contextmanager def locked(lock):

   lock.acquire()
   try:
       yield
   finally:
       lock.release()
  1. Определение блокировки

myLock = Lock()

  1. Применение оператора

with locked(myLock):

   #
   print "Охраняемый блок кода. Блокировка будет освобождена при любом выходе из этого блока."
   #

</source>

Генератор чисел Фибоначчи

Пример генератора чисел Фибоначчи и его использования: <source lang="python"> def fibonacci(max): # генератор (а не функция, т.к. оператор return заменён на yield)

   a, b = 0, 1
   while a < max:
       yield a            # return a, + запоминаем место рестарта для следующего вызова
       a, b = b, a + b    # параллельное присваивание, которое выполняется одновременно и параллельно

for n in fibonacci(100): # используем генератор fibonacci() как итератор

   print n,               # печатаем все числа Фибоначчи меньшие 100 через пробел

</source>

Альтернативный синтаксис доступа к элементам словаря

Можно определить словарь, который в дополнение к обычному синтаксису доступа к значению по ключу d[key] может предоставлять синтаксически более наглядный доступ к атрибуту d.key в случае алфавитно-цифровых ключей:

<source lang="python"> class Entity(dict): # наследуем класс от __builtin__.dict

   def __getattr__(self, key):                     # этот метод будет вызван, если атрибут
                                                   # с именем key не будет найден у экземпляра класса
       try: 
            return self[key]                       # пытаемся вернуть элемент словаря
       except KeyError, k:                         # если такого элемента нет, то возбуждаем
            raise AttributeError, k                # исключение AttributeError
                                                   # по договоренности __getattr__ 
                                                   # не должно возбуждать других исключений
   def __setattr__(self, key, value):              # этот метод будет вызван при присвоении
       self[key] = value                           # атрибуту key значения value
   def __delattr__(self, key):                     # а этот при удалении атрибута 
       try:                                        # с помощью del mydict.g
           del self[key]
       except KeyError, k: 
           raise AttributeError, k
   def __repr__(self):                             # используется функцией repr 
       return self.__class__.__name__ + "(" + dict.__repr__(self) + ")"

d = Entity(a=1) d.b_100 = 100 assert d.a == d['a'] and d.b_100 == d['b_100'] </source>

Функтор с генерацией байтокода

Пример эффективной реализации функтора, основанный на генерации байтокода во время исполнения. Этот пример демонстрирует следующие возможности/особенности Python:

  • Возможность реализации специфических средств функционального программирования наработками, уже имеющимися в языке
  • Работать с байтокодом в Python достаточно просто
  • Зачастую генерация байтокода способна значительно ускорить исполнение.

Это только пример, он реализует всего одну операцию — сложение и имеет несколько других ограничений.

<source lang="python">

  1. -------------------------------------------------------------------------------

import byteplay # специальный модуль для удобной работы с Python-байтокодом import new # для создания функции во время исполнения import functools # для update_wrapper import inspect # для получения информации о параметрах, принимаемых функцией

  1. -------------------------------------------------------------------------------

class FastFunctor(object):

   def __init__(self,func,code = None):
       self.func = None                # здесь будем хранить результирующую функцию
       self.ofunc = func               # а здесь исходную(original) функцию
       if code is None:     
           # конструируем байтокод для вызова функции
           self.code = [(byteplay.LOAD_CONST,func)]
           rparams = inspect.getargspec(func)[0] # получаем список параметров, принимаемых функцией
           self.code.extend((byteplay.LOAD_FAST,i) for i in rparams)
           self.code.append((byteplay.CALL_FUNCTION,len(rparams)))
       else:
           # если же функтор создан из другого функтора, 
           # то только копируем переданный байтокод
           self.code = code
       # создаем новый объект кода
       self.ocode = bp.Code.from_code(func.func_code)
   def __add__(self,obj):   # этот метод вызывается для операции '+'
       code = self.code[:]  # копируем байтокод
       if isinstance(obj,FastFunctor):  # если прибавляемый объект - функтор
           # просто дописываем его код к нашему
           # после своего исполнения он "оставит" в вершине стека результат
           code.extend(obj.code) 
       else:
           # иначе загружаем объект в стек
           code.append((byteplay.LOAD_CONST,obj))
       # дописываем байтокод, складывающий два верхних элемента в стеке
       code.append((byteplay.BINARY_ADD ,None )) 
       # создаем новый функтор, с байтокодом получения суммы
       return self.__class__(self.ofunc,code = code)
   def __call__(self,*dt,**mp):        # этот метод будет вызван для операции вызова object()
       return self.fast()(*dt,**mp)    # конструируем и вызываем функцию
   def fast(self): # конструируем функцию из байтокода
       if self.func is None:           # если функция не была создана раннее
           code = self.code + [(bp.RETURN_VALUE,None)] # добавляем байтокод возврата
           oc = self.ocode
           # создаем объект кода из байтокода и другой информации
           bin_code =  byteplay.Code(code,
                               oc.freevars,
                               oc.args,
                               oc.varargs,
                               oc.varkwargs,
                               oc.newlocals,
                               "<just_code_%s>" % id(self),
                               "<auto_gen_%s>" % id(self),
                               0,
                               "auto_generated code")
           # конструируем новую функцию из объекта кода
           self.func = new.function(bin_code.to_code(),globals())
           # после этой операции для всех средств интроспекции 
           # созданная функция будет выглядеть как оригинальная
           self.func = functools.update_wrapper(self.func,self.ofunc)
       return self.func

</source>

   # Ниже представлено тестирование скорости объектов FastFunctor и SlowFunctor
   # (статья "Функциональное программирование на Python", см. сноску после блока кода)
   # из IPython (для удобства чтения лог немного изменен)
   # строки, начинающиеся с "In [XX]:" вводятся, остальные — вывод интерпретатора 
   In [1]: import fastfunctor  
   In [2]: func = lambda x : x + 1                   # Создаем очень простую функцию
   In [3]: vl = 1                                    # Переменная, для предотвращения оптимизации
   In [4]: functor = fastfunctor.Functor(func)
   In [5]: %timeit (functor + functor + 1)(vl)       # Тестируем "лобовой" способ
   1000 loops, best of 3: 661 mks per loop           # Очень медленно
   In [6]: functor2 = (functor + functor + 1)        # Конструируем функтор один раз
   In [7]: %timeit functor2(vl)                      # и тестируем только непосредственно вызов
   100000 loops, best of 3: 4.52 mks per loop        # Значительно лучше
   In [8]: functor3 = (functor + functor + 1).fast() # Получаем результирующую функцию
   In [9]: %timeit functor3(vl) 
   1000000 loops, best of 3: 1.42 mks per loop
   In [10]: def of(vl): return x(vl) + x(vl) + 1     # Создаем функцию "вручную"
   In [11]: %timeit of(vl)
   1000000 loops, best of 3: 1.42 mks per loop       # Скорость полностью совпадает со 
                                                     # скоростью функтора
   In [12]: sfunctor = SlowFunctor(func)             # Простая реализация функтора
   In [13]: sfunctor = sfunctor + sfunctor + 1       # 
   In [14]: %timeit sfunctor(vl)                     # 
   100000 loops, best of 3: 12.6 mks per loop        # Примерно в 9 раз медленнее, чем статический 
                                                     # вариант

Код SlowFunctor можно посмотреть здесь.
Приведенные значения времени следует рассматривать только в сравнении друг с другом.
ipython — расширение интерпретатора Python для интерактивной работы.

Используя эту технику, можно создать полноценный функтор, добавив функции для других операций (__sub__, __div__ и другие) и расширив его на случай нескольких входных функций с разными аргументами.

Транспонирование матрицы

Пример лаконичной реализации операции транспонирования матриц с использованием парадигм функционального программирования.

<source lang="python"> from pprint import pprint # модуль pprint используется для удобного вывода на экран matrix = [[0.5, 0, 0, 0, 0],

         [  1, 0.5,   0,   0,   0],
         [  1,   1, 0.5,   0,   0],
         [  1,   1,   1, 0.5,   0],
         [  1,   1,   1,   1, 0.5]]

matrix_t = list(zip(*matrix)) # непосредственно транспонирование

pprint(matrix) pprint(matrix_t) </source>

Вывод:

[[0.5, 0, 0, 0, 0],
 [1, 0.5, 0, 0, 0],
 [1, 1, 0.5, 0, 0],
 [1, 1, 1, 0.5, 0],
 [1, 1, 1, 1, 0.5]]

[[0.5, 1, 1, 1, 1],
 [0, 0.5, 1, 1, 1],
 [0, 0, 0.5, 1, 1],
 [0, 0, 0, 0.5, 1],
 [0, 0, 0, 0, 0.5]]

Если вам нравится SbUP.com Сайт, вы можете поддержать его - BTC: bc1qppjcl3c2cyjazy6lepmrv3fh6ke9mxs7zpfky0 , TRC20 и ещё....