Проверьте, используется ли имя класса (строка) для некоторого класса в Python - PullRequest
0 голосов
/ 03 апреля 2019

Как получить точную переменную класса, которая (в текущей области видимости) доступна под заданным именем?Я хочу написать функцию, подобную этой:

from my_module import ClassA # A subclass of my_other_module.BenevolentClass
from my_other_module import my_function
a = 'ClassA'
cls_var = my_function(a)
o = cls_var()

Чтобы я мог предоставить любую строку для my_function и до тех пор, пока эта строка доступна в пространстве имен вызывающей стороны как имя класса, он будет производить правильный класстак же, как если бы я копировал строку прямо в код.Причина в том, что мне нужно указывать имена классов для подпрограммы создания сложных объектов, но по возможности избегать eval.Моя текущая реализация выглядит следующим образом:

def my_function(name):
    if name in globals():
        c = globals()[name]
        # Actually a complex class whitelist
        if issubclass(c, BenevolentClass):
            return c
        else:
            raise ValueError(f'Potentially malicious class {name}')

Но это, очевидно, производит globals () из my_other_module, а это не то, что я хочу.Я хочу, чтобы все классы были доступны в точной строке кода, где вызывается my_function (который может быть внутри совершенно другого модуля, который вызывается из еще одного).

Ответы [ 2 ]

0 голосов
/ 03 апреля 2019

Я думаю, что нашел решение.Не уверен, что это идеально, поэтому я предпочел бы услышать некоторые комментарии, прежде чем принять мой собственный ответ.

import inspect

def my_function(name):
    for frame in inspect.getouterframes(inspect.currentframe()):
        c = None
        if name in frame.frame.f_globals:
            c = frame.frame.f_globals[name]
            break
    if c and issubclass(c, BenevolentClass):
        return c
    else:
        raise ValueError(f'Potentially malicious class {name}')

Насколько я понимаю, inspect.getouterframes идет вдоль стека вызовов, и я могу проверитьглобалы на каждом шагу, чтобы увидеть, что доступно.Ни локальные переменные, ни встроенные функции не доступны в frame.f_globals, так что, похоже, у него мало возможностей для внедрения вредоносных данных.

0 голосов
/ 03 апреля 2019

Вы можете передать глобальный dict функции my_function.

def my_function(name, g):
    if name in g:
        ...

cls_var = my_function(a, globals())
...