2016-12-01 3 views
3

Я хочу использовать Python для создания JSON.Использование Python для создания JSON

Поскольку я не нашел библиотеки, которая может мне помочь, я хочу знать, можно ли проверить порядок классов в файле Python?

Пример

# example.py 
class Foo: 
    pass 

class Bar: 
    pass 

Если я импортировать example, я хочу знать, порядок классов. В этом случае это [Foo, Bar], а не [Bar, Foo].

Возможно ли это? Если «да», как?

фон

Я не доволен YAML/JSON. У меня есть неопределенная идея создать конфигурацию через классы Python (только классы, а не объекты для объектов).

Ответы, которые помогут мне добраться до моей цели (создайте JSON с помощью инструмента, который легко и интересно использовать).

+1

Это отличная смутная идея. Вы должны дать [Figura] (https://figura.readthedocs.io/en/latest/) выстрел! – shx2

+0

Я должен указать, что порядок заявлений не сохраняется в Figura, а также [также не в json] (http://stackoverflow.com/a/7214312), а также не в YAML. – shx2

+0

@ shx2 AFAIK порядок в ямле сохраняется. В противном случае порядок состояний в соляной кассе не будет работать: https://docs.saltstack.com/ru/latest/ref/states/ordering.html – guettli

ответ

10

Осматривать модуль может сказать номера строк из объявлений классов:

import inspect 

def get_classes(module): 
    for name, value in inspect.getmembers(module): 
     if inspect.isclass(value): 
      _, line = inspect.getsourcelines(value) 
      yield line, name 

Так следующий код:

import example 

for line, name in sorted(get_classes(example)): 
    print line, name 

Печать:

2 Foo 
5 Bar 
+0

Для этого нужно, чтобы модуль примера находился на пути импорта, а также довольно большое отверстие для безопасности, вы загружая редактируемый пользователем файл в том же контексте, что и остальная часть приложения, без какой-либо песочницы ... – pradyunsg

+1

@pradyunsg: он написал, что «если я импортирую пример», поэтому импорт не кажется проблемой. –

+0

Ох ... Тем не менее, я вижу это как дыру в безопасности. Добавил раздел к моему ответу. – pradyunsg

1

Вы можете использовать метакласс для записи времени создания каждого класса, а затем отсортировать классы по нему.

Это работает в python2:

class CreationTimeMetaClass(type): 
    creation_index = 0 
    def __new__(cls, clsname, bases, dct): 
     dct['__creation_index__'] = cls.creation_index 
     cls.creation_index += 1 
     return type.__new__(cls, clsname, bases, dct) 

__metaclass__ = CreationTimeMetaClass 

class Foo: pass 
class Bar: pass 

classes = [ cls for cls in globals().values() if hasattr(cls, '__creation_index__') ] 
print(sorted(classes, key = lambda cls: cls.__creation_index__)) 
2

(Moving мои комментарии к ответу)

Это отличная смутное представление. Ты должен дать Figura выстрел! Он делает именно это.

(Полное раскрытие:. Я автор Figura)

Я должен указать порядок деклараций не сохраняется в Figura, а также не в формате JSON.

Я не уверен, о порядке самосохранения в YAML, но я нашел это на wikipedia:

... в соответствии со спецификацией, ключи картография не имеют порядок

Возможно, что определенные партизаны YAML поддерживают порядок, хотя они и не требуются.

1

Модуль json прост в использовании и хорошо работает для чтения и записи файлов конфигурации JSON.

Объекты не упорядочены в структурах JSON, но списки/массивы, поэтому помещают информацию о заказе в список.

Я использовал классы в качестве инструмента настройки, я сделал это, чтобы получить их из базового класса, который был настроен конкретными переменными класса. Используя этот класс, мне не нужен фабричный класс. Например:

from .artifact import Application 
class TempLogger(Application): partno='03459'; path='c:/apps/templog.exe'; flag=True 
class GUIDisplay(Application): partno='03821'; path='c:/apps/displayer.exe'; flag=False 

в сценарии установки

from .install import Installer 
import app_configs 

installer = Installer(apps=(TempLogger(), GUIDisplay())) 
installer.baseline('1.4.3.3475') 
print installer.versions() 
print installer.bill_of_materials() 

следует использовать правильные инструменты для работы, так что, возможно, классы питона не правильный инструмент, если вам нужно заказ.

Другой инструмент python, который я использовал для создания файлов JSON, - это Mako templating system. Это очень мощно. Мы использовали его для заполнения переменных, таких как IP-адреса и т. Д., В статические файлы JSON, которые затем были прочитаны программами на C++.

3

Прежде всего, как я это вижу, есть 2 вещи, которые вы можете сделать ...

  1. продолжать реализацию использовать Python исходные файлы как файлы конфигурации. (Я не буду рекомендовать. Это аналогично использование бульдозера, чтобы ударить гвоздь или преобразование a shotgun к колесу)
  2. Переключитесь на что-то вроде TOML, JSON или YAML для конфигурационных файлов, которые предназначены для работы.

    Ничто в JSON или YAML не позволяет им удерживать «упорядоченные» пары ключ-значение. По умолчанию тип данных Python dict неупорядочен (по крайней мере, до 3,5) и упорядочен тип данных list. Они сопоставляются непосредственно объекту и массиву в JSON, соответственно, при использовании загрузчиков по умолчанию. Просто используйте что-то вроде Python's OrderedDict при десериализации их и вуаля, вы сохраняете порядок!


С этим из пути, если вы действительно хотите использовать Python исходные файлы конфигурации, я предлагаю попробовать обработать файл с помощью ast модуля. Абстрактные синтаксические деревья - это мощный инструмент для анализа уровня синтаксиса.

Я взломал быстрый скрипт для извлечения строк и имен строк из файла.

Вы (или кто-либо действительно) можете использовать его или расширить его, чтобы быть более обширным и иметь больше проверок, если хотите, что хотите.

import sys 
import ast 
import json 


class ClassNodeVisitor(ast.NodeVisitor): 

    def __init__(self): 
     super(ClassNodeVisitor, self).__init__() 
     self.class_defs = [] 

    def visit(self, node): 
     super(ClassNodeVisitor, self).visit(node) 
     return self.class_defs 

    def visit_ClassDef(self, node): 
     self.class_defs.append(node) 


def read_file(fpath): 
    with open(fpath) as f: 
     return f.read() 


def get_classes_from_text(text): 
    try: 
     tree = ast.parse(text) 
    except Exception as e: 
     raise e 

    class_extractor = ClassNodeVisitor() 

    li = [] 
    for definition in class_extractor.visit(tree): 
     li.append([definition.lineno, definition.name]) 

    return li 


def main(): 
    fpath = "/tmp/input_file.py" 

    try: 
     text = read_file(fpath) 
    except Exception as e: 
     print("Could not load file due to " + repr(e)) 
     return 1 

    print(json.dumps(get_classes_from_text(text), indent=4)) 


if __name__ == '__main__': 
    sys.exit(main()) 

Вот пример работы на следующий файл:

input_file.py:

class Foo: 
    pass 


class Bar: 
    pass 

Выход:

$ py_to_json.py input_file.py 
[ 
    [ 
     1, 
     "Foo" 
    ], 
    [ 
     5, 
     "Bar" 
    ] 
] 

Если я импортировать example,

Если вы собираетесь импортировать модуль, то модуль example быть на пути импорта. Импортирование означает выполнение any Код Python в модуле example. Это довольно большая дыра в безопасности - вы загружаете редактируемый пользователем файл в том же контексте, что и остальная часть приложения.

+0

Модуль 'ast' довольно приятный, спасибо за пример. Я играл с ним, пока не достиг одного лайнера: '[(n.lineno, n.name) для n в ast.walk (ast.parse (open (" example.py "). Read())) if isststance (n, ast.ClassDef)] ' –

+0

Да. Это тоже работает. Я чувствую себя глупо. Мое лучшее возможное возвращение: я так много сделал, так как не уверен, хочет ли OP просто имя класса, а также задания внутри него. (Потому что я тоже написал код для этого, а затем удалил его). – pradyunsg

+0

Оба «ast.NodeVisitor» и «ast.walk» идут по дереву. «Ast.walk» проще для этого однострочного, но «ast.NodeVisitor» может быть более изящным для более сложной обработки. Я просто предпочитаю более короткие примеры, потому что читателям это легче понять. –

1

Я не уверен, отвечает ли это на ваш вопрос, но это может быть актуально. Взгляните на отличный модуль attrs. Это отлично подходит для создания классов для использования в качестве типов данных.

Вот пример из glyph's блога (создатель Twisted Python):

import attr 
@attr.s 
class Point3D(object): 
    x = attr.ib() 
    y = attr.ib() 
    z = attr.ib() 

Это экономит писать много шаблонного кода - вы получите такие вещи, как str представления и сравнения бесплатно, а модуль имеет удобный asdict функция, вы можете перейти к json библиотеке:

>>> p = Point3D(1, 2, 3) 
>>> str(p) 
'Point3D(x=1, y=2, z=3)' 
>>> p == Point3D(1, 2, 3) 
True 
>>> json.dumps(attr.asdict(p)) 
'{"y": 2, "x": 1, "z": 3}' 

модуль использует странное соглашение об именах, но читать attr.s, как «attrs» и attr.ib как «атрибут», и с вами все будет в порядке.

2

Я предполагаю, что, поскольку вы заботитесь о сохранении порядка класса четкость, вы также заботиться о сохранении порядка определений в пределах каждого класса.

Стоит отметить, что сейчас поведение по умолчанию в python, since python3.6.

Aslo см. PEP 520: Сохранение атрибута класса Определение.

+0

Это отличная новость. До сих пор мы все еще используем Python 2.7, но рано или поздно мы переключимся. Спасибо. – guettli

0

Просто касаясь точки создания JSON из python. есть отличная библиотека под названием jsonpickle, которая позволяет вам сбрасывать объекты python в json. (и используя это самостоятельно или с другими упомянутыми здесь способами, вы, вероятно, можете получить то, что вы хотели)

+0

это тоже работает для занятий? У меня нет объектов. – guettli

+0

он может работать для занятий, но это действительно зависит от ваших потребностей. из того, что я видел, он будет кодироваться примерно так: «py/object»: « .B», а затем он может декодировать его для восстановления B, он доступен – Eytan

Смежные вопросы