Python Forum

Full Version: Object of type Scoreboard is not JSON serializable
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
Object of type Scoreboard is not JSON serializable

IS ANY OTHER WAY TO serialize this OBJECT ... ? trying a scoreboard for a game...

>>> %Run snake-points-pause-sounds-highscores2.py
pygame 1.9.6
Hello from the pygame community. https://www.pygame.org/contribute.html
Traceback (most recent call last):
File "F:\OneDrive\OneDrive\macOS_MBP2016\2019mbp\Clients\Snake - PyGame\snake-points-pause-sounds-highscores2.py", line 424, in <module>
drawGameOver(surface, data.username, data.points)
File "F:\OneDrive\OneDrive\macOS_MBP2016\2019mbp\Clients\Snake - PyGame\snake-points-pause-sounds-highscores2.py", line 115, in drawGameOver
board = scoreRecord(username, points)
File "F:\OneDrive\OneDrive\macOS_MBP2016\2019mbp\Clients\Snake - PyGame\snake-points-pause-sounds-highscores2.py", line 355, in scoreRecord
serialize("hightscores.txt", board)
File "F:\OneDrive\OneDrive\macOS_MBP2016\2019mbp\Clients\Snake - PyGame\snake-points-pause-sounds-highscores2.py", line 285, in serialize
json.dump(players, f)
File "C:\Users\lwdls\Thonny\lib\json\__init__.py", line 179, in dump
for chunk in iterable:
File "C:\Users\lwdls\Thonny\lib\json\encoder.py", line 438, in _iterencode
o = _default(o)
File "C:\Users\lwdls\Thonny\lib\json\encoder.py", line 179, in default
raise TypeError(f'Object of type {o.__class__.__name__} '
TypeError: Object of type Scoreboard is not JSON serializable


# hghscores - start

def deserialize(fileName):
    exists = os.path.isfile(fileName)
    if exists:
        # Store configuration file values
        f = open(fileName, 'r')
        board = json.load(f)
        f.close()    
    else:
        # Keep presets
        board = Scoreboard()
        
    return board


def serialize(fileName, players):
    f = open(fileName, 'w')
    json.dump(players, f)
    f.close()


class GameEntry:
  """Represents one entry of a list of high scores."""

  def __init__(self, name, score):
    """Create an entry with given name and score."""
    self._name = name
    self._score = score

  def get_name(self):
    """Return the name of the person for this entry."""
    return self._name
    
  def get_score(self):
    """Return the score of this entry."""
    return self._score

  def __str__(self):
    """Return string representation of the entry."""
    return '({0}, {1})'.format(self._name, self._score) # e.g., '(Bob, 98)'


class Scoreboard:
  """Fixed-length sequence of high scores in nondecreasing order."""

  def __init__(self, capacity=10):
    """Initialize scoreboard with given maximum capacity.

    All entries are initially None.
    """
    self._board = [None] * capacity        # reserve space for future scores
    self._n = 0                            # number of actual entries

  def __getitem__(self, k):
    """Return entry at index k."""
    return self._board[k]

  def __str__(self):
    """Return string representation of the high score list."""
    return '\n'.join(str(self._board[j]) for j in range(self._n))

  def add(self, entry):
    """Consider adding entry to high scores."""
    score = entry.get_score()

    # Does new entry qualify as a high score?
    # answer is yes if board not full or score is higher than last entry
    good = self._n < len(self._board) or score > self._board[-1].get_score()

    if good:
      if self._n < len(self._board):        # no score drops from list
        self._n += 1                        # so overall number increases

      # shift lower scores rightward to make room for new entry
      j = self._n - 1
      while j > 0 and self._board[j-1].get_score() < score:
        self._board[j] = self._board[j-1]   # shift entry from j-1 to j
        j -= 1                              # and decrement j
      self._board[j] = entry                # when done, add new entry


def scoreRecord(username, points):
    board = deserialize("hightscores.txt")

    entry = GameEntry(username, points)
    board.add(entry)
            
    serialize("hightscores.txt", board)
        
    return board
       
json.dump takes non mandatory param encoder
Use https://docs.python.org/3/library/json.h...SONEncoder to customize encoder
In my case... of custom object of type class Scoreboard

what can try / use ???

or is better use
Writing Your Own Serializer
???
Ok,I've just created my own class SuperClass. Do you know, how to convert it's object into JSON? Of course, nobody knows except me. You have to write your own serializer. I can suggest solution like this:

import json


class Foo(object):

    def __init__(self):
        self.a = 1
        self.b = 1

    def __json__(self):
        return dict(a=self.a, b=self.b)


class MyUniversalEncoder(json.JSONEncoder):
    def default(self, obj):
        if hasattr(obj, "__json__"):
            return obj.__json__()
        return json.JSONEncoder.default(self, obj)


f = Foo()
print json.dumps(f, cls=MyUniversalEncoder)
I solve the problem using Scoreboard object and my own serializer/deserializer

text file(storage.txt) is like

Player1username, 1600
Player3username, 800
Player2username, 500
....
....

this i ask is
is any python 3 serializer/deserializer build-in func to store the object Scoreboard in file txt or binary file ... ?
Quote:is any python 3 serializer/deserializer build-in func to store the object Scoreboard in file txt

What do you think json.dump does?
Look at jsonpickle.
A quick example and i have removed getter/setter which in not popular or not needed for simple simple attribute access.
For more advance attribute access that return a value can use @property.
import jsonpickle

class GameEntry:
  """Represents one entry of a list of high scores."""
  def __init__(self, name, score):
    """Create an entry with given name and score."""
    self.name = name
    self.score = score

  def __str__(self):
    """Return string representation of the entry."""
    return f'({self.name}, {self.score})' # e.g., '(Bob, 98)'

obj = GameEntry('Bob', 98)
frozen = jsonpickle.encode(obj)

# To disk
with open('score.json', 'w') as j_out:
    print(frozen, file=j_out)

# From disk
with open('score.json') as j:
    frozen_obj = jsonpickle.decode(j.read())
Test frozen_obj:
>>> frozen_obj.name
'Bob'
>>> frozen_obj.score
98

>>> print(frozen_obj)
(Bob, 98)
(Jul-31-2019, 10:10 AM)fishhook Wrote: [ -> ]
Quote:is any python 3 serializer/deserializer build-in func to store the object Scoreboard in file txt

What do you think json.dump does?

If I want save... use binary or text file ?
(Jul-31-2019, 04:41 PM)lsepolis123 Wrote: [ -> ]
(Jul-31-2019, 10:10 AM)fishhook Wrote: [ -> ]What do you think json.dump does?

If I want save... use binary or text file ?

It looks like to be impossible to save python object to text.
class Foo:
   pass

a = Foo()

def log(text):
    print(text)

a.log = log

a.log("foo")
To save "a" object to a file it is required to save the byte-code of "log" function either. To save the object completely there is "pickle" and "cPickle" packages. Both of them make binary from python object. But assume, that you need to pass a data from web-server to web-client. You can't use pickle for that because JavaScript knows nothing about python's bytecode and it's impossible to convert python class to JS class. For that case, another approach is applied. You have to convert your python object to some format, but the result can only contain data, not methods. So that type of serialization can be text(JSON, YAML, XML) or binary(protobuf, MessagePack). Choose the format you need.
def deserialize(fileName):
    # From disk
    with open(fileName) as j:
        frozen_obj = jsonpickle.decode(j.read())
    return frozen_obj

def serialize(fileName, frozen):
    # To disk
    with open(fileName, 'w') as j_out:
        print(frozen, file=j_out)
    


if __name__ == '__main__':
  for e in (
    ('Rob', 750), ('Mike',1105), ('Rose', 590), ('Jill', 740),
    ('Jack', 510), ('Anna', 660), ('Paul', 720), ('Bob', 400),
    ):
    ge = GameEntry(e[0], e[1])
    frozen = jsonpickle.encode(ge)

    serialize("hightscores.json", frozen)

// how to append with jsonpickle... above add only last one... well? Also How get all users back, after append all in json to file?
// hightscores.json
{"_name": "Bob", "_score": 400, "py/object": "__main__.GameEntry"}