# -*- coding: utf-8 -*- """Этот модуль предназначен для демонстрации самых интересных, на мой взгляд, возможностей языка программирования python (именно языка, для того, чтобы описать его инфаструктуру, даже в пределах стандартной поставки, пришлось бы написать книгу). В основном, здесь демонстрируются различные приемы метапрограмирования. Кстати, это - пример документации к модулю. Python навязывает документирование интерфейсов. Естественно, что эту документацию потом можно почитать, работая за пределами конкретного модуля, что широко используется, например, во всяких IDE. Между прочим - это пример многострочной строки""" #Это - два способа работы с внешними модулями. import sys, __builtin__ #В дальнейшем обращение к членам этого модуля #будет, например, так sys.argv() (в этом #случае получим список аргументов) import functools as ft #А в этом случае мы будем обращаться к членам #модуля через сокращение. В нашем случае ft. #Например, ft.__doc__ покажет документацию к #модулю #Пример метапрограммирования на Python. Для простоты мы просто #вручную создадим класс. Хотя это можно сделать и в во время выполнения. class foo(): """Некоторый пустой класс, который мы превратим в непустой. Кстати, это тоже пример документирования, но уже класса. """ pass def _checkValue(fun): """Это еще одно орудие из арсенала метепрограммирования - декоратор. Применяется здесь исключительно для проверки типа входного значения, с целью демонстрации возможности изменения функций или методов без внесения изменений непосредственно в них. Механизм декораторов основан на том, что функции в python - т.н. объекты первого класса т.е. их можно передавать, как параметры и возвращать, как значения. Модули, кстати, тоже объект первого класса.""" def _check(*args, **kwargs): if 'b' in kwargs and not isinstance(kwargs['b'], str): raise TypeError ('The argument should be an string!') elif args[1] and not isinstance(args[1], str): raise TypeError ('The argument should be an string!') return fun(*args, **kwargs) return _check @_checkValue #Здесь использован простой декоратор, без переданных в него значений def func0(self, b=None): """Эта функция, которая просто возвращает переданные в нее значения, будет установлена как метод во время выполнения""" return b def func1(self): """А эта функция тоже добавляется в класс во время выполнения, и манипулирует полями класса. Поля класса устанавливаются во время выполнения ниже.""" self.someField = self.someField + 2 return self.someField #На самом деле это - тоже функция. Только анонимная. Кроме того #тут демонстрируется так называемые списочные включения (list comprehension). func2 = lambda self, value : [item for item in value] #Кстати, списки в один из самых удобных базовых типов. Наряду с кортежами исловарями. def func3(self, val=200): """Это - демонстрация генераторов. Они запоминают точку в теле функции из которой происходил последний вызов и при повторном вызове возвращается в нее""" while val > 0: val -= 50 v = yield val def addPrototipe(self, other): """Перегрузка операции сложения. Тут мы опишет такую реализацию операции, которая нам нравится. В python можно переопределить почти все, например можно переопределить операции сравнения (= < <=; > >= == !=), так что они будут возвращать не только истину/ложь, но вообще любой объект – список, матрицу и т.д Само собой злоупотреблять этим не стоит. """ if isinstance(other, foo): try: return self.someField+other.someField except: raise ValueError, "Field someField not found!" def testPartial(f, s): """Функция предназначена для демонстрации каррирования. Каррирование (currying) -это преобразование функции от пары аргументов в функцию, берущую свои аргументы по одному. Практическое применение каррирования - это получение из одной функции другой функции, путем частичного применения первой.""" return f + s def strRunner(string): """Демонстрация выполнения строки как кода""" x = 2; exec(string) return x+y # Этот участок кода выполняется только когда запущен этот модуль if __name__ == "__main__": #Функция, которая добавляем поле или метод в класс print u"Пустой, пока, класс foo", dir(foo) print u"Добавили функцию func0 как метод 'someMethod'" setattr(foo, "someMethod", func0) print u'Добавили поле "someField" со значением 13' #Обратите внимание, что строки в python могут быть как в #одинарных так и в двойных кавычках setattr(foo, "someField", 13) print u"Добавили методы someMethod2, someGenMethod" setattr(foo, "someMethod1", func1) setattr(foo, "someMethod2", func2) setattr(foo, "someGenMethod", func3) # Это самый простой способ создавать классы во время выполнения. Для более # изощренной работы требуется умение работать с метаклассами print u"Теперь класс не пустой", dir(foo) v = foo() #И работаем с новым классом print u"Результаты вызова установленных полей и методов:" print u"someMethod - ", v.someMethod("It work") #Раскомментируйте это для проверки работы декоратора. #print "someMethod - ", v.someMethod(1) print u"someField - ", v.someField print u"someMethod1 - ", v.someMethod1() print u"someMethod2 - ", v.someMethod2([1, 2, 3]) print u"Демонстрация работы генераторов" gen = v.someGenMethod() print u"Последовательно вызываем генератор из func3" while 1: try: print u"Значение генератора - ", gen.next() except StopIteration: break #Демонстрация каррирования. В это реализовано в partial из модуля funktool #но работает только для последнего аргумента. Интересующимся гуглить #на тему Xoltar Toolkit. print u"""Проверяем работоспособность каррирования.""" print u"Это результат вызова каррированой функции testPartial с первым аргументом (1)" a = ft.partial(testPartial, 1); print a b = a; c = a print u"Вызываем testPartial с значением второго аргумента 2", b(2) print u"Вызываем testPartial с значением второго аргумента 3", b(3) print u"Проверка работоспособности перегрузки функций" setattr(foo, "__add__", addPrototipe) a = foo() print u"Добавляем 'магический' метод __add__ для перегрузки операции сложения" setattr(a, "someField", 15) #Добавили поле print u"И складываем два класса", a+v #Проверка работоспособности выполнения строки, как кода #В этой строке также видно то, что оператор for реализован по принципу for-each. testStr = """ y=10 for i in (1, 2): x = x+i print x""" print u"Результат выполнения строки, как кода - ", strRunner(testStr)