Уведомления

Группа в Telegram: @pythonsu

#1 Сен. 15, 2017 21:44:30

thund3r
Зарегистрирован: 2017-09-15
Сообщения: 5
Репутация: +  0  -
Профиль   Отправить e-mail  

Проблема при сохранении списка объектов с помощью Picle

Приветствую сообщество! Возникла задача написать програмку для использования с Zabbix. Нужно распарсить странный json (структуру которого я не могу изменить), из-за этого использую циклы, чтобы сериализовать данные в объекты и список этих объектов сохранить в файл. Решил использовать Pickle. Но возникает ошибка в независимости от использования pickle и cPickle. Использую Python 2.7.

Определение класса:

     class Switch():
        """Object switch
        """
        def __init__(self, mac="", ip="" ports = []):
            self.mac = mac
            self.ip = ip
            self.ports = ports

Вот так создаю экземпляры:

 for mac in data_from_url:
            sw = Switch(mac) # Create instance
            switch_list.append(sw) # Adding object to list
            # Adding values to attributes of objects:
            if isinstance(data_from_url[mac], dict):
               for mac in data_from_url:
                  if switch_key == '1':
                     sw.ip = data_from_url[mac][switch_key]
                  if switch_key == '21':    
                     sw.mac = data_from_url[mac][switch_key]


 print object1.__dict__
    {'hostname': u'name', 'ip': u'192.168.0.1' ... }
    print object2.__dict__
    {'hostname': u'name2', 'ip': u'192.168.0.2' ... }
    list_objects = [object1, object2, ... ]
    save_to_file(list_objects, file.db)
    def save_to_file(lst, file_pickle):
        with open(file_pickle, 'wb') as output:
            pickle.dump(lst, output)
            output.close()
Содержание ошибки:

  File "/home/thund3r/work/git/zabbix_topology/list_of_objects.py", line 89, in save_to_file
        pickle.dump(lst, output)
      File "/usr/lib/python2.7/pickle.py", line 1376, in dump
        Pickler(file, protocol).dump(obj)
      File "/usr/lib/python2.7/pickle.py", line 224, in dump
        self.save(obj)
      File "/usr/lib/python2.7/pickle.py", line 286, in save
        f(self, obj) # Call unbound method with explicit self
      File "/usr/lib/python2.7/pickle.py", line 606, in save_list
        self._batch_appends(iter(obj))
      File "/usr/lib/python2.7/pickle.py", line 621, in _batch_appends
        save(x)
      File "/usr/lib/python2.7/pickle.py", line 286, in save
        f(self, obj) # Call unbound method with explicit self
      File "/usr/lib/python2.7/pickle.py", line 704, in save_inst
        args = obj.__getinitargs__()
    TypeError: 'str' object is not callable 

Откуда str?

type(lst) is {list}
type(output) is {file}

Хотя список можно распечать и проблем в нем не видно:

  for x in zabbix_switches:
        if x.mac == '1024CF94FD97':
            print x.__name__
            print x.__class__
            print x.__dict__
Вывод:

    __name__
    __main__.Switch
    {'ip': u'192.168.0.1', 'mac': u'1024CF94FD97', ...}

Подскажите, что делаю не так. Заранее благодарен!

Офлайн

#2 Сен. 15, 2017 22:18:30

Rodegast
От: Пятигорск
Зарегистрирован: 2007-12-28
Сообщения: 2842
Репутация: +  186  -
Профиль   Отправить e-mail  

Проблема при сохранении списка объектов с помощью Picle

> Нужно распарсить странный json (структуру которого я не могу изменить), из-за этого использую циклы

Используй simplejson.

чтобы сериализовать данные в объекты и список этих объектов сохранить в файл. Решил использовать Pickle.

Зачем тебе Pickle? Храни в файле json, при необходимости его можно легко сериализовать.



С дураками и сектантами не спорю, истину не ищу.
Ели кому-то правда не нравится, то заранее извиняюсь.

Офлайн

#3 Сен. 15, 2017 23:42:47

thund3r
Зарегистрирован: 2017-09-15
Сообщения: 5
Репутация: +  0  -
Профиль   Отправить e-mail  

Проблема при сохранении списка объектов с помощью Picle

Спасибо! Так как я не знаю еще модулей, вычитал, что cPickle будет работать быстрее, но прочитал о simplejson и наверное буду использовать его, темболее я уже использовал json в этой же программе, но для других целей:

 response = urllib .urlopen(url)
data_from_url = json.loads(response.read())
Сделал так:
 def save_to_file(data, file_json):
    # print(obj.__getinitargs__())
    with open(file_json, 'w') as outfile:
        json.dumps(data, outfile)
        outfile.close()

Похоже, что проблема все-таки, не в сохранении, а в самом списке объектов. При использовании simplejson выдает похожую ошибку.
 Connected to pydev debugger (build 172.3544.46)
Traceback (most recent call last):
  File "/home/thund3r/.local/share/JetBrains/Toolbox/apps/PyCharm-C/ch-0/172.3544.46/helpers/pydev/pydevd.py", line 1599, in <module>
    globals = debugger.run(setup['file'], None, None, is_module)
  File "/home/thund3r/.local/share/JetBrains/Toolbox/apps/PyCharm-C/ch-0/172.3544.46/helpers/pydev/pydevd.py", line 1026, in run
    pydev_imports.execfile(file, globals, locals)  # execute the script
  File "/home/thund3r/work/git/zabbix_topology/list_of_objects.py", line 160, in <module>
    save_to_file(zabbix_switches, db_file) # TODO add hash compare of file
  File "/home/thund3r/work/git/zabbix_topology/list_of_objects.py", line 90, in save_to_file
    json.dumps(data, outfile)
  File "/home/thund3r/.local/lib/python2.7/site-packages/simplejson/__init__.py", line 397, in dumps
    **kw).encode(obj)
  File "/home/thund3r/.local/lib/python2.7/site-packages/simplejson/encoder.py", line 291, in encode
    chunks = self.iterencode(o, _one_shot=True)
  File "/home/thund3r/.local/lib/python2.7/site-packages/simplejson/encoder.py", line 373, in iterencode
    return _iterencode(o, 0)
  File "/home/thund3r/.local/lib/python2.7/site-packages/simplejson/encoder.py", line 268, in default
    raise TypeError(repr(o) + " is not JSON serializable")
TypeError: 'str' object is not callable
Опять появляется string.
Ошибка возникает на строке
 json.dumps(data, outfile)
Проверил список объектов или действительно передаю то, что нужно - распечатал:
 for x in zabbix_switches:
    if x.mac == '23AAFC94FD95':
        print x.__name__
        print x.__class__
        print x.__dict__

 __name__
__main__.Switch
{'building': '1', 'hostname': '3528', 'monitoring': '0', 'porch': '0', 'ip': '192.168.0.1', 'vlan': '0', 'snmp_write': 'smp-wr', 'ports': [<__main__.Port instance at 0x000009e02d8>], 'mac': '23AAFC94FD95', 'street': u'043d\u0438\u0446\u044c\u043a\u043e\u0457 \u0421\u043e\u043b', 'floor': '0', 'inventory_state': '1', 'model': 'EdgeCore_ES3528M', 'serial': '0000001'}
{'upswitch_mac': '0004968BC143', 'upswitch_port': '6', 'num': '1', 'port': '28'}

Отредактировано thund3r (Сен. 16, 2017 12:04:21)

Офлайн

#4 Сен. 16, 2017 14:34:10

JOHN_16
От: Россия, Петропавловск-Камчатск
Зарегистрирован: 2010-03-22
Сообщения: 3292
Репутация: +  221  -
Профиль   Отправить e-mail  

Проблема при сохранении списка объектов с помощью Picle

Вам бы кашу эту убрать и оставить все что по сути. Вот вы собрали некие данные data, покажите что это.
P.S. вы понимаете что в JSON могут быть сохранены только примитивные типы данных?



_________________________________________________________________________________
полезный блог о python john16blog.blogspot.com

Офлайн

#5 Сен. 16, 2017 16:07:28

thund3r
Зарегистрирован: 2017-09-15
Сообщения: 5
Репутация: +  0  -
Профиль   Отправить e-mail  

Проблема при сохранении списка объектов с помощью Picle

В data передовал словарь объектов.
Да, Вы правы! Я не понял, что нельзя прямо сериализовать объект! На сколько я понял можно только его __dict__.
Спасибо!
Кажется как сериализовать объект я понял. Но вот как правильно сериализовать словарь объектов, а в дальнейшем десериализовать в тот же словарь - еще нет, и пока не нашел решения в интернете. Подскажите, пожалуйста или может есть ссылка?
Сейчас сделал:

 def save_to_file(data):
    with open(db_file, 'w') as outfile:
          for key, obj in data.iteritems():
                outfile.write(json.dumps(obj, default=lambda o: o.__dict__))
          outfile.close()
Но если сделать так. В файле получается абракадабра вида
{mac: “”, ip: “”}{mac: “”, ip: “”}
Сейчас разбираюсь, как правильно это сделать.

Офлайн

#6 Сен. 16, 2017 17:34:37

JOHN_16
От: Россия, Петропавловск-Камчатск
Зарегистрирован: 2010-03-22
Сообщения: 3292
Репутация: +  221  -
Профиль   Отправить e-mail  

Проблема при сохранении списка объектов с помощью Picle

А собственно изначально вы этого хотели?

 In [2]: class Switch():
   ...:         def __init__(self, mac="", ip="", ports = []):
   ...:                 self.mac = mac
   ...:                 self.ip = ip
   ...:                 self.ports = ports
   ...:         
In [3]: sw1 = Switch('mac1', 'ip1', [1001, 1002])
In [4]: sw2 = Switch()
In [5]: sw2.mac = 'mac2'
In [6]: sw2.ip= 'ip2'
In [8]: sw2.ports = [2001]
In [9]: sw_list = [sw1, sw2]
In [10]: import pickle
In [11]: with open('sws.pickle', 'wb') as f:
   ....:     pickle.dump(sw_list, f)
   ....:     
In [12]: with open('sws.pickle', 'rb') as f:
   ....:     sw_p = pickle.load(f)
   ....:     
In [13]: sw_list == sw_p
Out[13]: False
In [14]: sw_list
Out[14]: [<__main__.Switch at 0x7f8a4327a438>, <__main__.Switch at 0x7f8a4327a390>]
In [15]: sw_p
Out[15]: [<__main__.Switch at 0x7f8a432575f8>, <__main__.Switch at 0x7f8a432577f0>]
In [16]: [x.__dict__ for x in sw_list] 
Out[16]: 
[{'mac': 'mac1', 'ports': [1001, 1002], 'ip': 'ip1'},
 {'mac': 'mac2', 'ports': [2001], 'ip': 'ip2'}]
In [17]: [x.__dict__ for x in sw_list] == [x.__dict__ for x in sw_p]
Out[17]: True



_________________________________________________________________________________
полезный блог о python john16blog.blogspot.com

Офлайн

#7 Сен. 17, 2017 00:39:10

thund3r
Зарегистрирован: 2017-09-15
Сообщения: 5
Репутация: +  0  -
Профиль   Отправить e-mail  

Проблема при сохранении списка объектов с помощью Picle

Простите, что не сразу отвечаю - хотелось уже все проверить и поправить
Совершенно верно. Только я допустил несколько ошибок…
Да, и если сохранять коммандой

 outfile.write(json.dumps(x.__dict__ for x in data))
используя список моих объектов возникает ошибка. Интересно почему обычный объект не может быть сериализован. Думаю при десериализации из файла это сыграет злую шутку.
 raise TypeError(repr(o) + " is not JSON serializable")
TypeError: <generator object <genexpr> at 0x7f7d543f40f0> is not JSON serializable
Сериализовать получилось если прописать реакцию по-умолчанию. Из документации:
If specified, default should be a function that gets called for objects that can’t otherwise 
be serialized. It should return a JSON encodable version of the object or raise a TypeError.
If not specified, TypeError is raised.
 def save_to_file(data, file_to_save):
    with open(file_to_save, 'w') as outfile:
        for obj in data:
            outfile.write(json.dumps(obj, default=lambda o: o.__dict__))
        outfile.close()
Правда, я сделал через метод объекта, а вдруг еще где-то пригодится в программе ))
 class Switch:
         ...
    def toJSON(self):
        return json.dumps(self, default=lambda o: o.__dict__,
                          sort_keys=True, indent=4)
    def save_to_file(data, file_to_save):
         with open(file_to_save, 'w') as outfile:
             for obj in data:
                 outfile.write(json.dumps(obj.toJSON()))
             outfile.close()
Даже не знаю, что не так с объектом, почему его нельзя сериализовать. Скорее всего это из-за вложенности объектов. В switch вложен список объектов port.
 class Switch:  
def __init__(self, mac="", ip="", ports = []):
        self.mac = mac
        self.ports = []
и в коде я добавляю порты к Switch
 for mac in data_from_url:
        sw = Switch(mac)
        switch_dict.append(sw)
        for port in data_from_url[mac][switch_key]
              pt = Port(port)
              sw.ports.append(pt)

Еще выяснил что cPicke из модуля six работает чуть-чуть быстрее чем simplejson. На очень большом файле 46c и
47с соответственно. Может кому сгодится ))
Теперь осталось только десериализовать…

Отредактировано thund3r (Сен. 17, 2017 01:10:52)

Офлайн

Board footer

Модераторировать

Powered by DjangoBB

Lo-Fi Version