Использование globals() для создания экземпляров класса


Я использую globals() для создания экземпляров классов на лету.

Например.

Animals.py

class Cat():
    pass

class Dog():
    pass

Test.py

#import animals

def create_animal():
    # Take 'which_animal' input from 
    # somewhere in form of string
    try:
    animal1 = globals()[which_animal]()
    catch:
    .
    .

Я сделал это, чтобы избежать длинной лестницы if-else.
Каковы плюсы и минусы этого метода ?
Есть ли какой-либо альтернативный метод для того же самого ?
Создает ли это угрозу безопасности ?

1 2

1 ответ:

любое имя в ваших глобалах доступно; это включает в себя функцию create_animal() и все, что вы, возможно, импортировали.

Это означает, что существует может быть угроза безопасности, в зависимости от того, что было импортировано. Вы должны, по крайней мере, фильтровать объекты, найденные на атрибуте __module__:

animal_cls = globals()[which_animal]
if animal_cls.__module__ != __name__:
    raise TypeError('Not a class defined in this module!')
animal1 = animal_cls()
Альтернативой является размещение классов, которые вы хотите сделать доступными, в некотором виде структуры данных. Вы можете использовать новый словарь:
animals = {
    'Cat': Cat,
    'Dog': Dog,
}

Вы можете иметь каждый класс зарегистрируйте себя (через декоратора) в такое отображение:

animals = {}

def registered(cls):
    animals[cls.__name__] = cls
    return cls

@registered
class Cat():
    pass

@registered
class Dog():
    pass

Или вы можете использовать базовый класс; метод __subclasses__() затем позволяет перечислить все производные классы:

class Animal(object):
    pass

class Cat(Animal):
    pass

class Dog(Animal):
    pass

animals = {cls.__name__: cls for cls in Animal.__subclasses__()}