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