Подклассы int класс в Python
Я хочу что-то делать каждый раз, когда добавляю два целых числа в свой TestClass
,
import builtins
class myInt(int):
def __add__(self, other):
print("Do something")
class TestClass:
def __init__(self):
builtins.int = myInt
def testMethod(self):
a = 1
b = 2
c = a + b
Когда я звоню testMethod
ничего не происходит, однако, если я определю это так, я получу желаемый эффект:
def testMethod(self):
a = int(1)
b = 2
c = a + b
Можно ли сделать это для всех литералов int, не вводя их перед операциями?
1 ответ
Извините, это невозможно без создания собственного пользовательского переводчика. Литеральные объекты не создаются путем вызова конструктора в __builtins__
они построены с использованием кодов операций, которые напрямую вызывают встроенные типы.
Также неизменяемые литералы создаются при компиляции кода, так что вы все равно опоздали. Если вы разберете testMethod
вы увидите, что он просто использует скомпилированные константы, но не пытается их построить:
>>> dis.dis(TestClass.testMethod)
5 0 LOAD_CONST 1 (1)
2 STORE_FAST 1 (a)
6 4 LOAD_CONST 2 (2)
6 STORE_FAST 2 (b)
7 8 LOAD_FAST 1 (a)
10 LOAD_FAST 2 (b)
12 BINARY_ADD
14 STORE_FAST 3 (c)
16 LOAD_CONST 0 (None)
18 RETURN_VALUE
Изменяемые литералы создаются во время выполнения, но они используют коды операций для создания подходящего значения вместо вызова типа:
>>> dis.dis(lambda: {'a': 1, 'b': 2})
1 0 LOAD_CONST 1 (1)
2 LOAD_CONST 2 (2)
4 LOAD_CONST 3 (('a', 'b'))
6 BUILD_CONST_KEY_MAP 2
8 RETURN_VALUE
Вы можете сделать что-то в соответствии с тем, что вы хотите, анализируя исходный код (используйте встроенный compile()
с ast.PyCF_ONLY_AST
флаг) затем прогуливаясь по дереву разбора и заменяя int
литералы с вызовом вашего собственного типа (используйте ast.NodeTransformer
). Тогда все, что вам нужно сделать, это закончить компиляцию (используйте compile()
снова). Вы могли бы даже сделать это с помощью ловушки импорта, чтобы это происходило автоматически при импорте вашего модуля, но это будет грязно.