Динамически создавать атрибуты класса
Мне нужно динамически создавать атрибуты класса из словаря ПО УМОЛЧАНИЮ.
defaults = {
'default_value1':True,
'default_value2':True,
'default_value3':True,
}
class Settings(object):
default_value1 = some_complex_init_function(defaults[default_value1], ...)
default_value2 = some_complex_init_function(defaults[default_value2], ...)
default_value3 = some_complex_init_function(defaults[default_value3], ...)
Я мог бы также добиться этого, имея что-то. лайк __init__
для создания классов, чтобы динамически создавать эти атрибуты из словаря и сохранить много кода и глупой работы.
Как бы вы это сделали?
Заранее большое спасибо!
3 ответа
Вы можете сделать это без метаклассов, используя декораторы. Этот способ немного более понятен ИМО:
def apply_defaults(cls):
defaults = {
'default_value1':True,
'default_value2':True,
'default_value3':True,
}
for name, value in defaults.items():
setattr(cls, name, some_complex_init_function(value, ...))
return cls
@apply_defaults
class Settings(object):
pass
До Python 2.6 декораторы класса были недоступны. Таким образом, вы можете написать:
class Settings(object):
pass
Settings = apply_defaults(Settings)
в старых версиях Python.
В приведенном примере apply_defaults
можно использовать повторно… Ну, за исключением того, что значения по умолчанию жестко закодированы в теле декоратора:) Если у вас есть только один случай, вы можете даже упростить свой код до этого:
defaults = {
'default_value1':True,
'default_value2':True,
'default_value3':True,
}
class Settings(object):
"""Your implementation goes here as usual"""
for name, value in defaults.items():
setattr(Settings, name, some_complex_init_function(value, ...))
Это возможно, поскольку классы (в смысле типов) сами являются объектами в Python.
Я думаю, что это относится к метаклассу:
class SettingsMeta(type):
def __new__(cls, name, bases, dct):
for name, value in defaults.items():
dct[name] = some_complex_init_function(value, ...)
return type.__new__(cls, name, bases, dct)
class Settings(object):
__metaclass__ = SettingsMeta
При определении класса локальное пространство имен будет преобразовано в пространство имен класса в конце тела класса. Таким образом, вы можете сделать это с помощью:
class Settings(object):
for key, val in defaults.iteritems():
locals()[key] = some_complex_init_function(val, ...)