Опубликован: 22.12.2005 | Доступ: свободный | Студентов: 16501 / 504 | Оценка: 4.18 / 3.71 | Длительность: 16:16:00
ISBN: 978-5-9556-0109-0
Лекция 4:

Объектно-ориентированное программирование

Устойчивые объекты

Для того чтобы объекты жили дольше, чем создавшая их программа, необходим механизм их представления в виде последовательности байтов. Во второй лекции уже рассматривался модуль pickle, который позволяет сериализовать объекты.

Здесь же будет показано, как класс может способствовать более качественному консервированию объекта. Следующие методы, если их определить в классе, позволяют управлять работой модуля pickle и рассмотренной ранее функции глубокого копирования. Другими словами, правильно составленные методы дают возможность воссоздать объект, передав самую суть - состояние объекта.

__getinitargs__() Должен возвращать кортеж из аргументов, который будет передаваться на вход метода __init__() при создании объекта.
__getstate__() Должен возвращать словарь, в котором выражено состояние объекта. Если этот метод в классе не определен, то используется атрибут __dict__, который есть у каждого объекта.
__setstate__(state) Должен восстанавливать объекту ранее сохраненное состояние state.

В следующем примере класс CC управляет своим копированием (точно так же экземпляры этого класса смогут консервироваться и расконсервироваться при помощи модуля pickle ):

from time import time, gmtime
import copy
class CC:
    def __init__(self, created=time()):
        self.created = created
        self.created_gmtime = gmtime(created)
        self._copied = 1
        print id(self), "init", created
    def __getinitargs__(self):
        print id(self), "getinitargs", self.created
        return (self.created,)
    def __getstate__(self):
        print id(self), "getstate", self.created
        return {'_copied': self._copied}
    def __setstate__(self, dict):
        print id(self), "setstate", dict
        self._copied = dict['_copied'] + 1
    def __repr__(self):
        return "%s obj: %s %s %s" % (id(self), self._copied, 
                                     self.created, self.created_gmtime)

a = CC()
print a
b = copy.deepcopy(a)
print b

В результате будет получено

1075715052 init 1102751640.91
1075715052 obj: 1 1102751640.91 (2004, 12, 11, 7, 54, 0, 5, 346, 0)
1075715052 getinitargs 1102751640.91
1075729452 init 1102751640.91
1075715052 getstate 1102751640.91
1075729452 setstate {'copied': 1}
1075729452 obj: 2 1102751640.91 (2004, 12, 11, 7, 54, 0, 5, 346, 0)

Состояние объекта состоит из трех атрибутов: created, created_gmtime, copied. Первый из этих атрибутов может быть восстановлен передачей параметра конструктору. Второй - вычислен в конструкторе на основе первого. А вот третий не входит в интерфейс класса и может быть передан только через механизм getstate / setstate. Причем, по смыслу этого атрибута при каждом копировании он должен увеличиваться на единицу (хотя в разных случаях атрибут может требовать других действий или не требовать их вообще). Следует включить отладочные операторы вывода, чтобы отследить последовательность вызовов методов при копировании.

Механизм getstate / setstate позволяет передавать при копировании только то, что нужно для воссоздания объекта, тогда как атрибут __dict__ может содержать много лишнего. Более того, __dict__ может содержать объекты, которые просто так сериализации не поддаются, и поэтому getstate / setstate - единственная возможность обойти подобные ограничения.

Примечание:

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

Для хранения объектов используются не только простейшие механизмы хранения вроде pickle.dump / pickle.load или полки shelve. Сериализованные объекты Python можно хранить в специализированных хранилищах объектов (например, ZODB) или реляционных базах данных.

Это также касается передачи объектов по сетям передачи данных. Если простейшие объекты (вроде строк или чисел) можно передавать напрямую через HTTP, XML-RPC, SOAP и т.д., где они имеют собственный тип, то произвольные объекты необходимо консервировать на передающей стороне и расконсервировать на принимающей.

Андрей Егоров
Андрей Егоров

def bin(n):

"""Цифры двоичного представления натурального числа """

if n == 0:

   return []

n, d = divmod(n, 2)

return bin(n) + [d]

print bin(69)

Что значит здесь return[] ? Возвращает список? Непонятно какой список? Откуда он? 

 

 

Асмик Гаряка
Асмик Гаряка

Почему при вычислении рейтинга не учитывается уровень, как описано? Для всех курсов У=1, хотя для Специалист должно быть 2.

Лариса Матросова
Лариса Матросова
Россия
Аделина Федорова
Аделина Федорова
Россия, 155900