0

Using Python, I'm trying to write object that it's access would be like this:

page[2].records[7].color = "ffff"

(the 'record' has some fields).

the object should be exported to json string and of course import from json (currently unwrittten), so I've added the toString() method.

The point is the code is very "clumsy". Is there way (using python) to make more "comely" code?

my code:

class Record ():
    '''
    '''
    def __init__(self, title, color, action, data) :
        self.title = title
        self.color = color
        self.action = action
        self.data = data
    def toDict(self) :
        ans = {'title':self.title, 'color':self.color, 'action':self.action, 'data':self.data}
        return ans
    def toString(self):
        return '%s' % self.toDict()
#-----------------------------------------------------------------------
class Records():
    '''
    '''
    def __init__(self):
        self.f_record = {}
    def __getitem__(self, key):
        if not(self.f_record.get(key,None)):
            self.f_record[key] = Record(None,None,None,None)
        return self.f_record[key]
    def __setitem__(self, key, value):
        self.f_record[key] = value
    def toDict(self):
        ans = {}
        for i in self.f_record:
            ans[i] = self.f_record[i].toString()
        return ans
    def toString(self):
        return '%s' % self.toDict()
#-----------------------------------------------------------------------
class Page():
    '''
    '''
    def __init__(self):
        self.records = Records()
    def toString(self):
        return self.records.toString()
#-----------------------------------------------------------------------
class Papers():
    '''
    '''
    def __init__(self):
        self.f_papers = {}
    def __getitem__(self,key):
        if not (self.f_papers.get(key,None)):
            self.f_papers[key] = Page()
        return self.f_papers[key]
    def toString(self):
        ans = {}
        for i in self.f_papers:
            ans[i] = self.f_papers[i].toString()
        return '%s' % ans
#-----------------------------------------------------------------------
#tests

a = Papers()
a[1].records[1] = Record('group','red','open', 'group1')
a[1].records[2] = Record('group','green','open', 'group2')

a[2].records[7].title = "ffff"
a[1].records[1].title = 'title :-) '

print a[1].records[1].toString()
print a.toString()
5
  • Can you be more specific about what you dislike about the code and what you want it to be like instead? Commented Dec 18, 2013 at 6:00
  • 1
    Your objects do nothing but store data. Do you need the classes in the first place? Do they have any methods besides toString and toDict? Commented Dec 18, 2013 at 6:02
  • 1
    One thing worth pointing out is that if you want to serialize to JSON you should use the json module instead of relying on dict.__str__ (by the way if you want to return an object with its default string formatting you can just return str(self.toDict())). A Python's dict representation looks close-enough to valid JSON most of the time, but there are corner cases that will bite you if you don't use a JSON library. Commented Dec 18, 2013 at 6:02
  • Additionally, this question seems a bit better suited for codereview.stackexchange.com Commented Dec 18, 2013 at 6:03
  • The code looks "to long" - I have 4 classes (instead of one or two), too much duplicated code (each class has the "toDict" and "toString" that actually are the same) Blender - You are right, I need to store data, 'toString' and 'fromString' (or another good way to convert data and from json strings). the 'toDict' is step on the way to 'toString'. Commented Dec 18, 2013 at 6:05

2 Answers 2

1

You could use dict itself to make it a bit easier:

from collections import defaultdict

class PropertyDict (dict):
    def __getattr__ (self, attr):
        if self.has_key(attr):
            return self.__getitem__(attr)
        return object.__getattr(self, attr)

    def __setattr__ (self, attr, value):
        self.__setitem__(attr, value)

class Record (PropertyDict):
    def __init__ (self, title = None, color = None, action = None, data = None):
        self.title = title
        self.color = color
        self.action = action
        self.data = data

class Page (PropertyDict):
    def __init__ (self):
        self.records = defaultdict(Record)

papers = defaultdict(Page)
papers[1].records[1] = Record('group', 'red', 'open', 'group1')
papers[1].records[2] = Record('group', 'green', 'open', 'group2')

papers[2].records[7].title = "ffff"
papers[1].records[1].title = 'title :-) '

print(papers[1].records[1])
print(papers)

As the objects are now subtypes of dict, serializing it with json is simple. Only for deserializing you would have to write your own encode handler.

Sign up to request clarification or add additional context in comments.

1 Comment

Tnx a lot. this with J.F. Sebastian's (the usage of json) is very helpful.
1

To serialize your object to json:

import json

json_text = json.dumps(your_obj.as_dict())

To create your object from json:

obj = YourClass.from_dict(json.loads(json_text))

You could easily implement the methods:

class YourClass(object):
    def __init__(self, **kwargs):
        self.__dict__.update(kwargs)
    @classmethod
    def from_dict(cls, attrs):
        return cls(**attrs)
    def as_dict(self):
        return dict(self.__dict__)
    def __str__(self):
        return json.dumps(self.as_dict())
    def __repr__(self):
        # see http://docs.python.org/3/library/types.html#types.SimpleNamespace
        d = self.as_dict()
        items = ("{}={!r}".format(k, d[k]) for k in sorted(d))
        return "{}({})".format(type(self).__name__, ", ".join(items))

Example:

>>> obj = YourClass(title="foo", name="bar")
>>> obj.color = "ffffff"
>>> obj.name
'bar'
>>> obj
YourClass(color='ffffff', name='bar', title='foo')
>>> print(obj)
{"name": "bar", "color": "ffffff", "title": "foo"}
>>> obj.as_dict()
{'name': 'bar', 'color': 'ffffff', 'title': 'foo'}

You could define from_json, as_json methods if you'd like using the one-liners

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.