0

I didn't quite know how to word my question as this isn't something one would often do. Here's my situation:

I have a list of values.

Values= ["1","2","3","4"]

I then want to be able to separately access each of the values and combine them into a string with commas in between them. I wrote a bit of code that I want to format a string ('{}'.format())in such a way so that the outcome looks like this: '1,2,3,4'. My code that I have so far (it is also the code structure that I'd prefer to use if possible) is the following:

string = "{}".format(exec(
    "Out= ''\n"
    "for value in Values:\n"
    "    Out+= value + ','\n"
    "Out"))
print(string)

If, within the string that is given as the parameter to the 'exec' function, I write "print(Out)" IE:

string = "{}".format(exec(
    "Out= ''\n"
    "for value in Values:\n"
    "    Out+= value + ','\n"
    "print(Out)"))

Then the program will properly run and print out "1,2,3,4", but it will not store it in 'string' (Which is to be expected)

I therefore thought of adding a function in order to make sure that it can return something. I wrote the following, but as expected it also didn't work. string is still None:

string = "{}".format(exec(
    "def do_stuff():\n"
    "    Out = ''\n"
    "    for value in Values :\n"
    "       Out += value + ','\n"
    "    return Out \n"
    "do_stuff()"))

Now, I do realise that this method of combining strings is nowhere near the preferred way to combine strings, but let me give you some context.

I am making a game in python. There is a Character class and it contains various attributes of various data types (such as dict, list, int, str, float.... as well as some custom ones: AI, Item, ActiveSkill, PassiveSkill, Effect, Weapon, Armour etc...) Now, my plan is to be able to store the game progress in a json tree. For that I started giving each of these entities a method which will convert all of its attributes into json trees stored as strings. That way, when I want to save the game and it comes to the Character, it will sort all of its attributes, but it'll also have to make a call to objects that it's referencing (such as ActiveSkills). For each of ActiveSkills in a list, it'll have to call for their own json syntaxed strings and combine these using commas.

Here's some of my code to help you understand what I want to do:

json += \
    '"ActiveSkills":[{oActiveSkills}],' \
    '"PassiveSkills":[{oPassiveSkills}].' \
    '"Effects":[{oEffects}],'.format(
        oActiveSkills=exec(
            "Skills = ''\n"
            "for skill in self.ActiveSkills:\n"    # ActiveSkills is a list of ActiveSkill objects
            "    Skills+=skill.encode_to_json() + ','\n"
            "return Skills"),
        oPassiveSkills=exec(
            "Skills = ''\n"
            "for skill in self.PassiveSkills:\n"    # PassiveSkills is a list of PassiveSkill objects
            "    Skills+=skill.encode_to_json() + ','\n"
            "return Skills"),
        oEffects=exec(
            "Effects = ''\n"
            "for effect in self.Effects:\n"    # Effects is a list of Effect objects
            "    Effects+=effect.encode_to_json() + ','\n"
            "return Effects"))

I know that this code currently doesn't run, as you can only return from within a function, but I really don't know how to go about it in a quick and easy way.

One solution that I have saved up as a last resort is to just do everything by hand. IE: Have some kind of for loop that creates a string from returned values. Add this string to the json string, after which you will manually open and close with "},{" and make sure that there isn't a "," at the end. Then repeat this for PassiveSkills and Effects also. Finally, close the json string with "}," and add it to the 'json' (string type) variable...

I want to minimise the space taken up by this, and I want this system to be flexible, so that no matter how many skills in a list that you have, you could continue adding more and more of these json strings without changing the code.

Alexz
  • 85
  • 1
  • 1
  • 10
  • Take a look at [`str.join()`](https://docs.python.org/3/library/stdtypes.html#str.join). – El'endia Starman Nov 25 '15 at 23:04
  • When a list is passed into JSON. One does need to worry about commas. Also when you extract the list back, you do not need to worry about the commas either. JSON worries about it for you. Unless I am getting the idea wrong here.... – Damian Chrzanowski Nov 25 '15 at 23:10
  • @El'endiaStarman Yes, but later on I present a situation in which I have a list of objects, from which I call on a method that returns a value. Should I then create a new list? IE: `Skills=[i.encode_to_json: for i in ActiveSkills]` followed by, as you suggested `json += ",".join(Skills)`? – Alexz Nov 25 '15 at 23:12
  • Your explanation still doesn't make clear why you're using `exec` at all. Just take whatever you're doing in the exec-ed string, move it out into a real function, call it, and store the result. – BrenBarn Nov 25 '15 at 23:15
  • Yes, don't use exec - see my answer about using json or pickle. – DisappointedByUnaccountableMod Nov 25 '15 at 23:23

2 Answers2

3

To join a list using ',':

Values = ["1","2","3","4"]
result = ",".join( Values )
print(result)

More info about str.join(iterable)can be found here in the online documentation.

For a better solution to store dictionaries and lists (and, using pickle, objects), you should look at the json and pickle packages in the Python Standard Library.

For example, with json:

import json

mydata = {}
mydata['hello'] = { 'value1':1, 'valuuelist':[1,2,3,4] }

print(json.dumps(mydata))

Output:

{"hello": {"valuuelist": [1, 2, 3, 4], "value1": 1}}

So, don't roll your own encoder, unless you really have to.

martineau
  • 119,623
  • 25
  • 170
  • 301
  • The problem is that the data I want to save in a json file is scattered across various objects (EG: Character has its own attributes, but so do skills of the character.) To store all of the data as a single tree I require each object to create a string in json syntax that will then be combined with any objects that are referenced by that object (Each object is referenced by only one other object. That way I have a hierarchy and I'm trying to backwards engineer the json tree.) – Alexz Nov 25 '15 at 23:33
  • I can imagine (though I can't point at an implementation) that the main objects could have registered all the child objects, and could provide a way to load/restore all the data by calling the registered child objects 'pickle'. This is probably an important part of your design, difficult to retrofit later. See e.g. http://stackoverflow.com/questions/4529815/saving-an-object-data-persistence-in-python – DisappointedByUnaccountableMod Nov 25 '15 at 23:42
  • I have used pickle before and my biggest problem was that I didn't understand _how_ it encoded the data. As a result, it would be difficult for me to then load up the data if the system has been updated, since I didn't know how to pick out the required data out of a pickled object, without loading up the previous version of the object in one swoop. I decided to go with json as my data storage, as it is quite simple to load up the data, even if the process (method) that uses the data has changed. I have designed it to make it as easy to retrofit as I could... But I might have missed something. – Alexz Nov 25 '15 at 23:55
  • You use pickle.load() to unpickle - don't do it yourself! To quote the docs: "The data format used by pickle is Python-specific. This has the advantage that there are no restrictions imposed by external standards such as XDR (which can’t represent pointer sharing); however it means that non-Python programs may not be able to reconstruct pickled Python objects. By default, the pickle data format uses a printable ASCII representation." – DisappointedByUnaccountableMod Nov 25 '15 at 23:58
  • I could unpickle the data easily. The problem was then loading the old data into a new system that now has changed. The unpickled data is no longer compatible with the new updated system. With json, however, I could pick out the data that would be relevant to the new system without worrying about compatibility, as I could manipulate the data in order to make it compatible. – Alexz Nov 26 '15 at 00:01
  • I understand what you mean about loading after updating the code - if you really need to solve this problem you will probably end up have different versions of the class always available to restore into, and understanding how to transform themselves into newer versions. However the same basic problem exists with using json - if the latest implementation of the class has new capabilities, and you need to be able to restore older versions, you will have to implement the old->new transformation yourself. – DisappointedByUnaccountableMod Nov 26 '15 at 00:03
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/96194/discussion-between-alexz-and-barny). – Alexz Nov 26 '15 at 00:03
0

For joining each element of a sequence into a string you can use join method.

   L=['1','2','3']
   string=",".join(L)
   print(L)
Rishikesh Jha
  • 540
  • 3
  • 11