Украсьте всю библиотеку в Python - PullRequest
2 голосов
/ 07 июля 2010

Я новичок в идеях декораторов (и все еще пытаюсь обернуть их вокруг себя), но я думаю, что столкнулся с проблемой, которая была бы хорошо для них. Я хотел бы иметь класс, который украшен для всех функций в математической библиотеке. Точнее, в моем классе два члена: x и flag . Когда flag true, я бы хотел, чтобы исходная математическая функция была вызвана. Когда flag имеет значение false, я хотел бы вернуть None .

В качестве основы для того, что я спрашиваю здесь, является класс:

import math

class num(object):
  def __init__(self, x, flag):
    self.x = x
    self.flag = flag

  def __float__(self):
    return float(self.x)

В результате все отлично работает:

a = num(3, True)
print math.sqrt(a)

Однако это должно (в моем идеальном мире) вернуть Нет :

b = num(4, False)
print math.sqrt(b)

Какие-либо предложения или советы о том, как это можно применить ко всей библиотеке функций?

Ответы [ 2 ]

6 голосов
/ 07 июля 2010

Вот общая идея ...:

>>> class num(object):
...   def __init__(self, x, flag):
...     self.x = x
...     self.flag = flag
...   def __float__(self):
...     return float(self.x)
...   from functools import wraps
>>> def wrapper(f):
...   @wraps(f)
...   def wrapped(*a):
...     if not all(getattr(x, 'flag', True) for x in a):
...       return None
...     return f(*(getattr(x, 'x', x) for x in a))
...   return wrapped
... 
>>> import inspect
>>> import math
>>> for n, v in inspect.getmembers(math, inspect.isroutine):
...   setattr(math, n, wrapper(v))
... 

>>> a = num(3, True)
>>> print math.sqrt(a)
1.73205080757
>>> b = num(4, False)
>>> print math.sqrt(b)
None

Обратите внимание, что эта оболочка также охватывает неунарные функции в math (возвращая None, если любой аргумент имеетFalse .flag) и разрешает их смешанные вызовы (некоторые аргументы являются экземплярами num, а другие являются фактическими числами с плавающей запятой).

Ключевая часть, применимая к любому «обернуть все функции в определенном модуле"tasks, использует модуль inspect для получения всех имен и значений функций (встроенных или нет) в модуле math и явный вызов оболочки (та же семантика, что и у синтаксиса декоратора) для установки этого именик завернутому значению в модуле math.

6 голосов
/ 07 июля 2010

Для этого вы можете использовать декораторы, хотя вам не понадобится синтаксис @decorator.

Следующий код импортирует каждую перечисленную вами функцию из модуля math в пространство имен текущего модуля, оборачивая егов определенном декораторе.Это должно дать вам основную идею.

from functools import wraps
def check_flag(func):
    @wraps(func)
    def _exec(x, *args, **kw):
        if getattr(x, 'flag', False):
            return None

        return func(x, *args, **kw)

    return _exec

import sys, math
_module = sys.modules[__name__]
for func in ('exp', 'log', 'sqrt'):
    setattr(_module, func, check_flag(getattr(math, func)))

Вы могли бы автоматизировать список функций, определенных в модуле math, как демонстрирует Алекс, но я думаю, что явно заключает в себе только функцииВы заинтересованы в использовании, это лучший способ пойти.

...