Как реализовать метаданные класса / объекта в Python?

#python #class #coding-style #metadata

#python #класс #стиль кодирования #метаданные

Вопрос:

Я работаю над структурой структурированного анализа данных, которая основана на потоковой передаче данных между узлами. В настоящее время узлы реализованы как подклассы класса корневого узла, предоставляемого фреймворком. Для каждого класса / фабрики узлов мне нужны метаданные, такие как список атрибутов узла, их описание, выходные данные узла. Метаданные могут быть обоими: для конечных пользователей во интерфейсном приложении или для использования в программировании — некоторые другие инструменты управления потоками. В будущем их будет больше.

(Обратите внимание, что я только начал изучать python во время написания этого кода)

В настоящее время метаданные предоставляются в переменной класса

 class AggregateNode(base.Node):
    """Aggregate"""

    __node_info__ = {
        "label" : "Aggregate Node",
        "description" : "Aggregate values grouping by key fields.",
        "output" : "Key fields followed by aggregations for each aggregated field. Last field is "
                   "record count.",
        "attributes" : [
            {
                 "name": "keys",
                 "description": "List of fields according to which records are grouped"
            },
            {
                "name": "record_count_field",
                 "description": "Name of a field where record count will be stored. "
                                "Default is `record_count`"
            }
        ]
    }
  

Другие примеры можно найти здесь .

Я чувствую, что это можно сделать гораздо более чистым способом. Существует одно ограничение: поскольку узлы являются пользовательскими классами подклассов, должно быть минимальное вмешательство в потенциальные будущие имена атрибутов.

То, что я думал сделать, это разделить текущий node_info. Он должен был быть закрытым для фреймворка, но теперь я понимаю, что он имеет гораздо более широкое применение. Я думал об использовании атрибутов node_: будет иметь общее пространство имен атрибутов, не принимая слишком много имен из потенциальных пользовательских атрибутов узла.

Мой вопрос: каков наиболее распространенный способ предоставления таких метаданных в программах на Python? Одна переменная со словарем? Несколько переменных, по одной для каждого атрибута метаданных? (это противоречило бы ограничению) Пользовательский класс / структура? Использовать какой-то префикс, например, node_ * и использовать несколько переменных?

Комментарии:

1. Просто чтобы добавить еще один пример использования метаданных: потоковая сеть будет настраиваться через словарь с кортежами node attribute value, а функция настройки должна заботиться о значениях по умолчанию и предотвращать установку защищенных атрибутов при определенных обстоятельствах (например, некоторые атрибуты будут устанавливаться только в коде, другие будут открыты дляпользовательский интерфейс).

2. Не создавайте пользовательские имена, которые начинаются и заканчиваются двойным подчеркиванием. У меня сейчас нет ссылки, но они считаются зарезервированными, так что любое их использование явно относится к языковой функции, а не к определяемой пользователем переменной.

Ответ №1:

Я не уверен, существует ли какой-то «стандартный» способ хранения пользовательских метаданных в объектах python, но в качестве примера реализация dbus на python добавляет атрибуты с префиксом « _dbus « к опубликованным методам и сигналам.

Комментарии:

1. Используется обычный, общедоступный node_info .

Ответ №2:

Многие функции, которые вы описываете, перекрываются с epydoc:

 >>> class AggregateNode(base.Node):
...     r"""
...     Aggregate values grouping by key fields.
... 
...     @ivar keys: List of fields according to which records are grouped
... 
...     @ivar record_count_field: Name of a field where record count will be
...                               stored.
...     """
...     record_count_field = "record_count"
...     
...     def get_output(self):
...         r"""
...         @return: Key fields followed by aggregations for each aggregated field.
...                  Last field is record count.
...         """
... 
>>> import epydoc.docbuilder
>>> api = epydoc.docbuilder.build_doc(AggregateNode)
>>> api.variables['keys'].descr.to_plaintext(None)
u'List of fields according to which records are groupednn'
>>> api.variables['record_count_field'].value.pyval
'record_count'
  

Комментарии:

1. Спасибо, полезно знать, так как это может быть полезно для некоторых других проектов. Однако мне это нужно не только для целей документации. Он будет использоваться, например, при создании формы пользовательского интерфейса и автоматической (защищенной) конфигурации узла. Мне нужно больше информации для @ivar, чем его описание.

2. Вы также можете использовать epydoc для указания его типа и значения по умолчанию. В вашем примере приведено только описание; что еще вам нужно?

3. Я сожалею о недостаточном примере. Помимо значений по умолчанию и типа, будет: область защиты или тип проверки / вызываемый (в настоящее время реализующий материал, который его использует). В будущем их наверняка будет больше.

4. Вы также можете упомянуть такие вещи, как предварительное условие или постусловие, для большинства вызываемых объектов; epydoc не придает этому никакого значения; но вы, вероятно, могли бы указать это в терминах выражения, которое должно быть истинным, чтобы удовлетворить условию; или как объект python, который каким-то образом представляет условие.

Ответ №3:

Единственным элементом класса Python, способным изменять само определение класса (следовательно, метаданные), является __new__() функция, new вызывается до фактического создания объекта и до инициализации. Вы можете использовать его для чтения / изменения внутренней структуры ваших классов / узлов до их инициализации с помощью __init__()