python - Unpickle namedtuple with backwards compatibility (ignoring additional attributes) -


here's scenario simulates running older version of python program against shelve database written newer version. ideally, user object still parsed , read in; favouritepet attribute ignored. understandably, throws error complaining tuple doesn't match.

is there way of making scenario work namedtuples, or better switch storing dictionary or class if sort of flexibility required?

import shelve collections import namedtuple  shelf = shelve.open("objectshelf", flag='n')  user = namedtuple("user", ("username", "password", "firstname", "surname", "favouritepet")) shelf["namedtupleandrew"] = user("andrew@example.com", "mypassword", "andrew", "smith", "cat")  # redefine user simulate previous version of user object didn't record favouritepet; # using old version of program against database written new version user = namedtuple("user", ("username", "password", "firstname", "surname")) # throws error "takes 5 positional arguments 6 given" namedtupleread = shelf["namedtupleandrew"]  print(namedtupleread.username) 

edit: completeness here's same idea using class:

import shelve  shelf = shelve.open("objectshelf", flag='n')  class user:      def __init__(self, username, password, firstname, surname, favouritepet):         self.username = username         self.password = password         self.firstname = firstname         self.surname = surname         self.favouritepet = favouritepet  shelf["objectandrew"] = user("andrew@example.com", "mypassword", "andrew", "smith", "cat")  # redefine user simulate previous version of user object didn't record favouritepet; # using old version of program against database written new version class user:      def __init__(self, username, password, firstname, surname):         self.username = username         self.password = password         self.firstname = firstname         self.surname = surname  objectread = shelf["objectandrew"]  print(objectread.username) # favouritepet still there; it's dictionary, after all. print(objectread.favouritepet) 

i advise use dict or custom class.

a named tuple needs many arguments has fields, make work named tuple directly yout'd have change class' __new__ method use *args , **kwargs instead of fixed list of arguments. if have @ definition of user class (by adding verbose=true argument), you'll see how class defined:

... class user(tuple):     'user(username, password, firstname, surname, favouritepet)'      __slots__ = ()      _fields = ('username', 'password', 'firstname', 'surname', 'favouritepet')      def __new__(_cls, username, password, firstname, surname, favouritepet):         'create new instance of user(username, password, firstname, surname, favouritepet)'         return _tuple.__new__(_cls, (username, password, firstname, surname, favouritepet)) ... 

__new__ have become __new__(_cls, *args, **kwargs), , correctly parse args , kwargs (you'll still want able use user('a', 'b', 'c', ...) user('a', password='b', firstname='c', ...) not user('a', username='a', ...) remain consistent namedtuple), , use resulting sequence tuple.__new__. it's better use dedicated class instead of modifying behaviour of namedtuple in such way.

it easier change way user namedtuple pickled using __reduce__ protocol (or copyreg.pickle()) using custom constructor function, e.g:

from collections import namedtuple import shelve import copyreg  shelf = shelve.open("test")  user = namedtuple("user", ("username", "password", "firstname", "surname", "favouritepet"))  user.__reduce__ = lambda user: (construct_user, tuple(user)) # or: copyreg.pickle(user, lambda user: (construct_user, tuple(user)))  def construct_user(*args):     print('creating new user:', args)       # debugging     return user(*args[:len(user._fields)])   user = user("andrew@example.com", "mypassword", "andrew", "smith", "cat") print(user) shelf["namedtupleandrew"] = user  # redefine user user = namedtuple("user", ("username", "password", "firstname", "surname"))  print(shelf["namedtupleandrew"]) 

this work long construct_user function available in compatible versions, said initially, still recommend use different data structure.


Comments

Popular posts from this blog

javascript - jQuery: Add class depending on URL in the best way -

caching - How to check if a url path exists in the service worker cache -

Redirect to a HTTPS version using .htaccess -