Как напечатать имя метода динамически назначаемой функции? - PullRequest
0 голосов
/ 19 сентября 2018

Когда я запускаю следующий фрагмент кода, только операторы print в методе, которые я динамически назначил классу «Test», возвращают только «my_unique_method_name».

Как напечатать имя метода, которое я ему дал? (Что такое «волшебство» в методе - см. «Ожидаемый результат» ниже.)

#!/usr/bin/python3
import sys
import inspect

class Test:
    pass

def my_unique_method_name(self):
    print(inspect.stack()[0][3])
    print(sys._getframe().f_code.co_name)
    print(inspect.currentframe().f_code.co_name)

Test.wizardry = my_unique_method_name
t = Test()
t.wizardry()

Токовый выход

my_unique_method_name
my_unique_method_name
my_unique_method_name

Ожидаемый выход

wizardry

Ответы [ 2 ]

0 голосов
/ 19 сентября 2018

Вы можете сделать это, изучив содержимое self.__class__.__dict__:

class Test:
    pass

def my_unique_method_name(self):
    for k, v in self.__class__.__dict__.items():
        if v == my_unique_method_name:
            print(k)
            break  # Assume there's only one.


Test.wizardry = my_unique_method_name
t = Test()
t.wizardry()  # -> wizardry

Вот более общий (и, следовательно, многократно используемый) способ сделать это, не требуя, чтобы назначенная функция делала что-то особенное- это также, вероятно, будет немного быстрее, поскольку нет цикла for:

from functools import wraps

class Test:
    pass

def my_unique_method_name(self):
    pass

def assign_function_to_method(func, cls, name):
    @wraps(func)  # Optional (but recommended).
    def wrapped(*args, **kwargs):
        print(name)
        return func(*args, **kwargs)

    setattr(cls, name, wrapped)


assign_function_to_method(my_unique_method_name, Test, 'wizardry')
t = Test()
t.wizardry()  # -> wizardry

Любой подход работает как в Python 2, так и в 3.

0 голосов
/ 19 сентября 2018

Имя функции равно"my_unique_method_name" - функция - это объект со свойством, которое является его именем.
Test.wizardy - это просто переменная, и ее имя не связано сФункция, которая является его значением.

Это та же самая ситуация, как эти:

>>> def unique(): pass
...
>>> unique
<function unique at 0x0000000002CA4F28>
>>> unique.__name__
'unique'
>>> f = unique
>>> f.__name__
'unique'
>>> class A: pass
...
>>> a = A()
>>> a.g = unique
>>> a.g
<function unique at 0x0000000002CA4F28>
>>> a.g.__name__
'unique'
...