Имитация указателей в Python для арифметики - PullRequest
4 голосов
/ 14 мая 2010

Вопрос на

Имитация указателей в Python

, спрашивающий, как имитировать указатели в Python, имел хорошее предложение в решениях, а именно:

class ref:
    def __init__(self, obj): self.obj = obj
    def get(self): return self.obj
    def set(self, obj): self.obj = obj

, который затем можно использовать, например,

a = ref(1.22)
b = ref(a)

print a # prints 1.22
print b.get() # prints 1.22

Класс можно изменить, чтобы избежать использования get для оператора печати, добавив

def __str__(self): return self.obj.__str__()

Тогда

print b # prints out 1.22

Теперь я хотел бы иметь возможность выполнять арифметику с b так же, как и с a, что, я думаю, было бы равносильно тому, чтобы сказать, что я хочу, чтобы a и b вели себяточно так же как obj.Есть какой-либо способ сделать это?Я пытался добавить методы, такие как

def __getattribute__(self, attribute): return self.obj.__getattribute__(attribute)
def __call__(self): return self.obj.__call__()

Но независимо от этого, вывод

print a + b

всегда

Traceback (most recent call last):
  File "test.py", line 13, in <module>
    print a + b
TypeError: unsupported operand type(s) for +: 'instance' and 'instance'

У кого-нибудь есть какие-либо идеи о том, какизменить класс ref, чтобы разрешить это?

Спасибо за любой совет!

Ответы [ 2 ]

3 голосов
/ 14 мая 2010

Оператор + реализован с помощью метода __add__() для левого операнда или метода __radd__() для правого операнда.

Здесь .

0 голосов
/ 14 мая 2010

Есть две потенциальные проблемы.

Во-первых, вы, похоже, полагаетесь на реализацию __getattribute__, чтобы позволить интерпретатору найти правильный __add__ метод. К сожалению, я заметил, что интерпретатору Python часто не удается найти специальные функции, такие как __add__ или __call__, если они создаются на лету (то есть не являются явной частью класса при определении класса). Руководства явно подтверждают это, по крайней мере, для классов нового стиля:

Для классов нового стиля, неявный вызовы специальных методов гарантированно работать правильно, только если определяется по типу объекта, а не в словарь экземпляра объекта.

хотя мне кажется, что у меня были проблемы с подобными уловками даже с классами старого стиля.

Во-вторых, простого перенаправления __add__ будет недостаточно. Даже если переводчик успешно уменьшает

a + b

до

float.__add__( 1.22, b )

класс float все еще не знает, как добавить float к ref. Таким образом, ваш __add__ должен будет явно разыменовать цель (и разыменовать ее, если это косвенная ссылка (и разыменование, что ...). Вот так:

class ref:
    def __init__(self, obj):
        self.obj = obj
    def get(self): return self.obj
    def set(self, obj): self.obj = obj
    def __str__(self): return self.obj.__str__()
    def __add__( self, other ):
        while isinstance( other, ref ):
            other = other.obj
        return self.obj.__add__( other )

a = ref(1.22)
b = ref(a)

print a
print b

print a + b

Цикл while в __add__ гарантирует, что вы распаковали все вложенные ссылки вплоть до базового объекта.

Если бы я делал это и использовал подобные конструкции для реализации шаблонов прокси, я бы изменил рефакторинг так, чтобы цикл while находился в своем собственном методе, скажем, getBaseObject (), и затем вызывался каждый раз, когда нам нужен объект то есть у фактической базы цепочки ссылок.

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