Проверка, был ли метод вызван из класса - PullRequest
0 голосов
/ 26 февраля 2019

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

Я планировал проверить, вызывается ли метод __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())

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

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

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

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

1 Ответ

0 голосов
/ 26 февраля 2019

Несмотря на то, что задача считается невозможной, кажется, что желаемого поведения можно легко достичь, просто заменив __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__ и не возвращает класс этого фрейма - что я и предполагал из вышеприведенного ответа.

...