Monkeypatching вызов метода в Python - PullRequest
0 голосов
/ 23 июня 2009

Как отложить доступ к атрибутам в Python?

Предположим, у нас есть:

    def foo():
        ...

    class Bar:
        ...

    bar = Bar()

Можно ли реализовать Bar так, чтобы в любое время к bar предоставлялось значение, возвращаемое обратным вызовом foo()?

bar имя уже существует в контексте. Вот почему семантика доступа должна быть сохранена (она не может быть вызываемой, превращение bar в свойство класса, использование SomeClass.bar вместо bar также не будет работать) Мне нужно сохранить все как есть, но изменить программу так, чтобы bar ссылался на данные, генерируемые на лету, на foo().

UPD : Спасибо всем за ваши ответы, из которых кажется невозможным сделать подобные вещи в Python. Я найду обходной путь.

Ответы [ 7 ]

6 голосов
/ 23 июня 2009

Полагаю, вы хотите связать некоторый атрибут "data" с foo:

class Bar:
    data = property(lambda self: foo())


bar = Bar()
bar.data # calls foo()
2 голосов
/ 23 июня 2009

В основном вы запрашиваете способ перехвата переменной (как бы вы ее переназначили?) В пространстве имен модуля, что невозможно в Python.

Вы должны будете использовать средства доступа к атрибутам класса, если вы хотите описанное поведение:

class MyClass(object):
    def __getattr__(self, attr):
        if attr == 'bar':
            print 'getting bar... call the foo()!'
        else:
            return object.__getattribute__(self, attr)

    def __setattr__(self, attr, val):
        if attr == 'bar':
            print 'bar was set to', val
        else:
            object.__setattr__(self, attr, val)
0 голосов
/ 23 июня 2009

Если вам нужны результаты функции foo (), проще всего сделать это:

foo()

Все остальное - просто ненужное осложнение. Я подозреваю, что вы упростили свой пример, пока он не имеет смысла.

Редактировать: ОК, значит, вы пытаетесь изменить чей-то другой код. Нет, невозможно преобразовать переменную в метод универсальным способом. Вы можете заменить его объектом, который будет возвращать различные переменные, которые он использует, таким образом, что последовательно будет вызываться некоторый метод python.

barrio.py: bar = "Некоторая строка"

fool.py:

import random

class Foo:
    def __str__(self):
        return str(random.random())

import barrio
barrio.bar = Foo()

Теперь запустите python:

>>> import fool
>>> import barrio

>>> print barrio.bar
0.783394625457
>>> print barrio.bar
0.662363816543
>>> print barrio.bar
0.342930701226
>>> print barrio.bar
0.781452467433

Это работает, потому что print вызовет str для объекта, так как это не строка. Но в целом нет, это невозможно.

0 голосов
/ 23 июня 2009

Вы можете переопределить метод Бар __new__ для выполнения произвольного кода и возврата нового экземпляра. Смотри: http://docs.python.org/reference/datamodel.html#object.__new__

Вот надуманный пример:

>>> class Bar(object):
...     def __new__(cls):
...             print "Calling Bar.__new__"
...             return super(Bar, cls).__new__(cls)
...
>>> bar = Bar()
Calling Bar.__new__
>>> bar
<__main__.Bar object at 0x0222B3D0>

РЕДАКТИРОВАТЬ: Я неправильно понял, что вы хотели, ваше разъяснение прояснил это. Я не думаю, что вы хотите, возможно.

0 голосов
/ 23 июня 2009

Спасибо за разъяснения!

Это просто не может работать! Переменная является переменной в большинстве языков, а не вызовом функции. Вы можете многое сделать в Python, но просто не можете этого сделать.

Причина в том, что у вас всегда есть некоторые внутренние языковые правила. В Python есть одно правило: переменные являются переменными. Когда вы читаете переменную (не изменяя ее или что-то еще), вы можете рассчитывать, что она будет такой же в следующей строке кода.

Обозначение этого кода как вызова функции просто изменит это правило.

То, что вы хотите, может быть сделано только еще более динамичным языком. Что-то вроде системы макрообработки или языка, который не имеет переменных, но что-то вроде меток, которые можно прикрепить к чему угодно. Но это также сделало бы создание компилятора для него намного более трудным - следовательно, полностью динамическим. Компилятор должен учитывать все кодировки в программе.

0 голосов
/ 23 июня 2009

Это то, что вы ищете?

>>> def foo(): print('foo() was called');
...
>>> class Bar:
...     pass;
...
>>> bar = Bar();
>>> bar.data = foo;
>>> bar.data()
foo() was called
>>>
0 голосов
/ 23 июня 2009

"любой доступ к панели времени" ... Какие виды доступа будут делать ваши абоненты? (Например, они делают «1 + bar», они делают «bar [5:]», они делают «bar.func ()» и т. Д.). Будут ли они каждый раз вызывать конструктор Bar ()?

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

...