Подклассы int класс в Python - PullRequest
0 голосов
/ 05 ноября 2018

Я хочу что-то делать каждый раз, когда добавляю два целых числа в свой 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 Ответ

0 голосов
/ 05 ноября 2018

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

...