Как установить имена классов динамически?
У меня есть функция, которая создает классы, полученные из ее аргументов:
def factory(BaseClass) :
class NewClass(BaseClass) : pass
return NewClass
Теперь, когда я использую его для создания новых классов, все классы имеют одинаковые имена, и экземпляры выглядят так, как будто они имеют один и тот же тип:
NewA = factory(ClassA)
NewB = factory(ClassB)
print type(NewA()) # <class __main__.NewClass>
print type(NewB()) # <class __main__.NewClass>
Является ли правильное исправление для установки атрибута __name__
вручную?
NewA.__name__ = 'NewA'
print type(NewA()) # <class __main__.NewA>
Есть ли какие-то другие вещи, которые я должен устанавливать, пока я нахожусь на нем?
Ответы
Ответ 1
Да, настройка __name__
- правильная вещь; вам не нужно устанавливать что-либо еще для настройки имени класса.
Например:
def factory(BaseClass) :
class NewClass(BaseClass): pass
NewClass.__name__ = "factory_%s" % BaseClass.__name__
return NewClass
type
- это неправильная вещь для использования здесь. Он не позволяет вам определять классы с синтаксисом обычного класса Python, вместо этого вы настраиваете каждый атрибут класса вручную. Он использовался для создания классов вручную, например. если у вас есть массив базовых классов, и вы хотите создать его с помощью класса (который вы не можете использовать с синтаксисом класса Python). Не используйте его здесь.
Ответ 2
Проверьте, используя функцию type()
с тремя аргументами. Следующий код создает новый класс "NewA" с object
в качестве базового типа и без начальных атрибутов.
>>> type('NewA', (object,), {})
<class '__main__.NewA'>
Ответ 3
Обновление ответа от Гленна Мейнарда: В настоящее время есть атрибут __name__
атрибут __qualname__
. Первое, что вы можете подумать; второй пунктирный "путь" для вложенных классов.
В случае "простых" классов оба равны. Просто установите __name__
и __qualname__
в ваше новое имя. Вы должны установить оба атрибута, так как вы не можете быть уверены, какой сторонний код будет выглядеть.
Теперь для вложенных классов различия между двумя атрибутами показывают:
class Outer:
class Inner:
pass
print(Outer.__name__, Outer.__qualname__)
print(Outer.Inner.__name__, Outer.Inner.__qualname__)
печатает:
Outer Outer
Inner Outer.Inner
Если вы хотите изменить Outer
имя, вам нужно исправить три места, а именно: Outer.__name__
, Outer.__qualname__
, Inner.__qualname__
. Для последних двух вам нужно правильно разделить и объединить точки.
Последнее предупреждение: даже если вы все сделали правильно, такие вещи, как сфинкс, пилинт и т.д., Все равно могут не работать на 100%. Например, поддельное имя не может быть найдено в пространстве имен модуля как обычно; источник не может быть grep
ped для определения класса; и так далее.