Python protorpc dymnamic message
Я использую protorpc с endpoints-proto-datastore.
Я хочу создать собственное сообщение из предоставленной структуры.
Например, это следующий список ключей: ['id1', 'id2', 'id3']
Каждый ключ назначен MessageField
названный CustomField
,
Я бы хотел унаследовать от Message
и класс, содержащий все key
,
def create_custom_container(key_list):
class cls():
pass
for i, k in enumerate(key_list):
setattr(cls, k, MessageField(CustomField, i))
return cls
class CustomMessage(Message, create_custom_container(key_list)):
pass
Но это не работает, я получил:MessageDefinitionError: Message types may only inherit from Message
Я видел из исходного кода protorpc, что Message
используйте метаклассы, чтобы предотвратить его наследование или иметь атрибуты, которые будут изменены на лету.
Итак, я понятия не имею, как создать свое собственное сообщение на лету.
1 ответ
Библиотека проходит долгий путь, определяя ограничения для класса Message - взлом его для принудительного ввода новых атрибутов, вероятно, приведет к тому, что Message будет работать не так, как ожидалось.
К счастью, вместо жесткого кодирования тела класса class CustomMessage
оператор, создайте свой собственный класс с помощью вызова - это позволяет вам программно определять содержимое. Таким образом, вам не нужно использовать более одного класса в вашем дереве наследования.
Все, что вам нужно сделать, это позвонить Message
метакласс с соответствующими параметрами вместо обычного вызова type
и передать как пространство имен класса -
так что вы можете переписать вашу функцию создания тела:
def create_custom_body(key_list):
dct = {}
for i, k in enumerate(key_list):
dct[k] = MessageField(CustomField, i)
return dct
CustomClass = Message.__class__("CustomClass", (Message,), create_custom_body(key_list))
Это будет работать в этом случае. Если метакласс библиотеки будет использовать пользовательское пространство имен (то есть он будет иметь __prepare__
метод), однако, вам нужно изменить это, чтобы использовать types.new_class
и соответствующий обратный вызов:
from types import new_class
def create_custom_body(dct, key_list):
for i, k in enumerate(key_list):
dct[k] = MessageField(CustomField, i)
return dct
CustomClass = types.new_class(
"CustomClass", (Message,),
exec_body=(lambda namespace: create_custom_body(namespace, key_list))
)
(проверьте документы по адресу: https://docs.python.org/3/library/types.html).