Python API - шаблон для создания необязательных скобок? - PullRequest
1 голос
/ 05 июля 2011

Я разрабатываю API для библиотеки Python и столкнулся с ситуацией, когда я думаю, что мое воображение могло превзойти значительные способности Python.

(Я хочу извиниться перед всеми Pythonistas, которые могут обидеться из-за Рубина моего дизайна)

По сути, есть класс с несколькими методами, каждый из которых возвращает self, так что они могут быть объединены в цепочку. Итак:

>>> a = MyKlass()
>>> b = a.method_one()
>>> c = b.method_two()

будет таким же, как

>>> a = MyKlass()
>>> c = a.method_one().method_two()

Мой вопрос заключается в том, можно ли сделать скобки необязательными. Я немного узнал об использовании __getattr__ и __call__ для манипулирования вызываемыми объектами, но не смог полностью реализовать это. Прямо сейчас у меня есть класс __getattr__, проверяющий атрибут, а затем определяющий, является ли name методом или атрибутом (или, точнее, можно ли его вызвать или нет).

Моя проблема в том, что если он вызывается, мне нужно __getattr__ сделать что-то вроде этого:

>>> class MyKlass(object):
>>>     def __getattr__(self, name):
>>>         # pseudocode, you get the idea...
>>>         if name is callable:
>>>             def callme(*args, **kwds):
>>>                 # do stuff
>>>             return callme
>>>         else:
>>>             # just return the attribute

Таким образом, он возвращает вызываемый объект. Это означает, что я не могу сделать скобки необязательными, поскольку вызываемый объект будет возвращен, но никогда не будет вызван:

>>> a = MyKlass()
>>> c = a.method_one.method_two    # AttributeError, since a bound function object does not have attribute "method_two"

Единственный способ, которым я подумал сделать это, это иметь возможность «заглядывать в будущее» в коде и определять, следует ли за name скобка или нет. Затем, если name был вызван, но не вызван, я мог бы вернуть результаты вызова name без аргументов вместо возврата вызываемого объекта.

Я думаю, что это, вероятно, не выполнимо, но я подумал, что я все равно буду спрашивать гуру.

Ответы [ 2 ]

4 голосов
/ 05 июля 2011

Я думаю, вы с ума сошли от желания сделать это. Какая у тебя причина? Как насчет методов, которые принимают аргументы? (См. Пример ниже.)

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

Рабочий пример:

class Test(object):
    def __getattribute__(self, name):
        attr = super(Test, self).__getattribute__(name)
        if callable(attr):
            return attr()
        return attr
    def f(self):
        print 'f'
        return self
    def g(self):
        print 'g'
        return self
    def h(self, x):
        print x
        return self

t = Test()
t.f.g # Works fine
t.f().g # Fails - the parens aren't optional, they must be left off now
t.f.g.h(1) # Fails - unable to provide an argument

Чтобы обойти проблему с аргументами, вы можете проверить функцию и вызывать ее, только если она не принимает никаких аргументов (кроме self). Смотри: http://docs.python.org/library/inspect.html

Сделайте себе одолжение и прекратите идти по этому пути.

3 голосов
/ 05 июля 2011

Без скобок у вас есть ссылка на функцию, с ними у вас есть результат ее вызова.Это фундаментальная часть синтаксиса Python (эта согласованность - хорошая вещь!).

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

Подобные цепочки популярны в jQuery, потому что единственная цель jQuery - вызывать побочные эффекты в DOM.Обычно это не имеет смысла в других местах, потому что это делает ваше приложение очень трудным для отладки и тестирования.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...