All pastes #1214472 Raw Edit

python metaprogramming demo

public python v1 · immutable
#1214472 ·published 2008-09-30 06:38 UTC
rendered paste body
# -*- coding: utf-8 -*-"""Этот модуль предназначен для демонстрации самых интересных, намой взгляд, возможностей языка программирования python (именноязыка, для того, чтобы описать его инфаструктуру, даже в пределахстандартной поставки, пришлось бы написать книгу). В основном,здесь демонстрируются различные приемы метапрограмирования. Кстати, это - пример документации к модулю. Python навязываетдокументирование интерфейсов. Естественно, что эту документацию потомможно почитать, работая за пределами конкретного модуля, что широкоиспользуется, например, во всяких IDE.Между прочим - это пример многострочной строки"""#Это - два способа работы с внешними модулями.import sys, __builtin__ #В дальнейшем обращение к членам этого модуля                        #будет, например, так sys.argv() (в этом                        #случае получим список аргументов)import functools as ft  #А в этом случае мы будем обращаться к членам                        #модуля через сокращение. В нашем случае ft.                        #Например, ft.__doc__ покажет документацию к                        #модулю#Пример метапрограммирования на Python. Для простоты мы просто#вручную создадим класс. Хотя это можно сделать и в во время выполнения.class foo():    """Некоторый пустой класс, который мы превратим в непустой.    Кстати, это тоже пример документирования, но уже класса. """    passdef _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 bdef 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 valdef 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 + sdef 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=10for i in (1, 2):    x = x+i    print x"""    print u"Результат выполнения строки, как кода - ", strRunner(testStr)