Эмулировать int в python - PullRequest
       19

Эмулировать int в python

0 голосов
/ 01 июля 2018

Я хочу определить объект, который имеет точно такое же поведение, что и int, с небольшими отличиями. Рассмотрим класс

class MyInt:
  def __init__(self, num):
    self.num = num

Мне нужно включить следующее поведение: когда MyInt назначается другой переменной, операция приводит к присвоению MyInt.num вместо всего класса, т.е.

i = MyInt(10)
a = i
print(type(a)) # <class 'int'>
print(a)       # 10

Другими словами, a=i приводит к a= i.num. Все остальные функции MyInt должны быть точно такими же, как int, и применяться к MyInt.num, например. i += 1 должно быть эквивалентно i.num +=1

Полагаю, что этого можно добиться, если MyInt наследовать от int и использовать __getattr__ и __setattr__. Однако я не уверен, какой метод используется для получения значения переменной в python, чтобы я мог достичь желаемой функциональности.

Отказ от ответственности: мне это нужно, чтобы я мог глобально изменить переменную внутри функции. Я знаю, что это не рекомендуется, но это мой единственный вариант. Также я не могу использовать global.

1 Ответ

0 голосов
/ 01 июля 2018

Вы не можете этого сделать. В Python нет хуков, позволяющих вам корректировать назначения.

Существует множество способов привязки объекта, и для Python нет никакой разницы, вообще , между i = MyInt(10) и a = i. Оба являются присваиваниями, где результат выражения с правой стороны выполняется сначала , затем ссылка на результат сохраняется под определенным именем. Так как i создает ссылку на тот же объект, уже созданный MyInt(10), вы получите 2 ссылки с разными именами на один экземпляр.

Но [i] также хранит ссылку, теперь в объекте списка. То же самое происходит с for target_name in (i, i): (3 ссылки, сначала в кортеже с двумя ссылками, затем target_name, который связывается дважды так, когда цикл выполняется и ничто не выходит из цикла раньше). Я считаю по крайней мере 8 различных способов связывания объектов в Python.

Вы можете заставить MyInt работать как целое число в большинстве случаев; есть ряд специальных методов для эмуляции числовых типов , которые позволяют вам это сделать. Существует даже numbers.Integral абстрактный базовый класс , который можно использовать в качестве отправной точки. Они предоставляют вам ряд предварительно реализованных специальных методов, однако вам все равно необходимо реализовать ряд абстрактных методов:

>>> from numbers import Integral
>>> sorted(Integral.__abstractmethods__)
['__abs__', '__add__', '__and__', '__ceil__', '__eq__', '__floor__', '__floordiv__', '__int__', '__invert__', '__le__', '__lshift__', '__lt__', '__mod__', '__mul__', '__neg__', '__or__', '__pos__', '__pow__', '__radd__', '__rand__', '__rfloordiv__', '__rlshift__', '__rmod__', '__rmul__', '__ror__', '__round__', '__rpow__', '__rrshift__', '__rshift__', '__rtruediv__', '__rxor__', '__truediv__', '__trunc__', '__xor__']

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

Методы, которые уже предоставлены:

>>> from numbers import Number
>>> sorted(n for n in dir(Integral) if n not in Integral.__abstractmethods__.union(dir(Number)))
['__bool__', '__complex__', '__divmod__', '__float__', '__index__', '__rdivmod__', '__rsub__', '__sub__', 'conjugate', 'denominator', 'imag', 'numerator', 'real']

и вы действительно хотите предоставить подходящий __hash__ метод .

...