Проверка, был ли метод вызван из класса

Этот недавний вопрос вызвал у меня интерес, можем ли мы моделировать поведение частных переменных в python. Я попытался сделать это с помощью модуля проверки.

Мой план состоял в том, чтобы проверить, __getattribute__ Метод вызывается изнутри класса, подобно тому, как это делает этот ответ.

Из моего понимания я могу получить следующий объект внешнего кадра, используя f_back пока я в конечном итоге не приеду в класс, откуда его зовут. К моему удивлению, все вызовы frame.__self__ приводил к AttributeError, пока я в конечном итоге не достиг None чрезмерно звоня f_back:

import inspect

class MyClass:
    def __init__(self):
        self.variable = 1

    def __getattribute__(self, attr):
        frame = inspect.currentframe()

        try:
            while frame != None:
                try:
                    frame.__self__ # Can I do that?
                    print("Yes I can")
                except AttributeError:
                    print("Nope")

                frame = frame.f_back

        finally:
            del frame

        return super().__getattribute__(attr)

    def get_variable(self):
        return self.variable

A = MyClass()
print(A.get_variable())

Так как все, что я получаю, это "Нет", хотя геттер звонит __getattribute__ Изнутри класса (и я предполагаю, что возвращаясь кадр за кадром, я должен прийти к классу, из которого он вызывается), я могу придумать две возможности, почему это не работает.

  1. Что-то изменилось с тех пор, как был опубликован ответ?
  2. Мне не хватает ключевой детали

Поскольку мой код очень похож на код, размещенный в ответе, упомянутом выше, я пойду и предположу, что он как-то связан с версиями python.

Итак, мой вопрос: как я могу проверить, из какого класса вызывается метод? Есть ли другой способ сделать это? Но самое главное, почему этот код не работает?

1 ответ

Несмотря на то, что задача считается невозможной, кажется, что желаемого поведения можно легко достичь, просто заменив __self__ с f_locals['self'],

import inspect

class MyClass:
    def __init__(self):
        self.variable = 1

    def __getattribute__(self, attr):
        frame = inspect.currentframe()

        try:
            locals = frame.f_back.f_locals

            if locals.get('self', None) is self:
                print("Called from this class!")

            else:
                print("Called from outside of class!")

        finally:
            del frame

        return super().__getattribute__(attr)

    def get_variable(self):
        return self.variable

A = MyClass()
print(A.get_variable())

Текущий код не должен был функционировать, так как сам объект фрейма не имеет __self__ атрибут и не возвращает класс этого кадра - что я предположил, что делает из вышеупомянутого ответа.

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