Подклассы 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() снова). Вы могли бы даже сделать это с помощью ловушки импорта, чтобы это происходило автоматически при импорте вашего модуля, но это будет грязно.

Другие вопросы по тегам