J'aimerais créer une classe pour gérer simplement mes fichiers de configurations personnels, le problème c'est que j'ai aucune idée de comment organiser ça, sachant qu'il devra agir comme un dictionnaire. Enfin un exemple c'est toujours plus clair!
Je sais pas du tout comment faire pour que lorsque j'écris dans le fichier, les infos soient toujours dans le même ordre, comment agencer les méthodes __setitem__ et __getitem__ pour que ça modifie automatiquement le contenu et ça l'écrit dans le fichier ...
J'ai fait une ébauche de code, mais franchement rien de fameux :
class BowlingFile(object):
def __init__(self, filepath):
self.filepath = filepath
self.content = self._parse()
def _parse(self):
returnDict = dict()
with open(self.filepath, 'r') as fileStream:
lines = fileStream.read().splitlines()
for line in lines:
if line.startwith('#'):
continue
month, day, year, time, piste, score, strike, spare, split, null, hcp = line.split('|')
returnDict[len(returnDict)] = {'month':month,
'day':day,
'year':year,
'time':time,
'piste':piste,
'score':score,
'strike':strike,
'spare':spare,
'split':split,
'null':null,
'hcp':hcp}
return returnDict
def _write(self):
with open(self.filepath, 'w') as fileStream:
for key in self.content:
# self.write('%s\r\n' % '|'.join())
Et un petit code pour voir comment je pensais agencer ça :
filepath = 'C://scores.bwl'
fileobj = open(filepath, 'r')
mylist = [line for line in fileobj.read().splitlines() if not line.startswith('#')]
mydict = dict()
for x in mylist:
month, day, year, time, piste, score, strike, spare, split, null, hcp = x.split('|')
mydict[len(mydict)] = {'month':month, 'day':day, 'year':year, 'time':time, 'piste':piste, 'score':score, 'strike':strike, 'spare':spare, 'split':split, 'null':null, 'hcp':hcp}
for key in mydict:
print '%s\n\t' % key,
for subkey in mydict[key]:
print '%s \t: %s\n\t' % (subkey, mydict[key][subkey]),
print '\n',
0
month : 12
piste : 5
year : 2010
null : 5
day : 04
hcp : 0
score : 121
split : 0
time : 12:33
strike : 1
spare : 4
1
month : 12
piste : 5
year : 2010
null : 4
day : 04
hcp : 0
score : 139
split : 0
time : 12:54
strike : 2
spare : 4
2
month : 12
piste : 5
year : 2010
null : 5
day : 04
hcp : 0
score : 147
split : 0
time : 13:10
strike : 4
spare : 1
3
month : 12
piste : 5
year : 2010
null : 7
day : 04
hcp : 0
score : 94
split : 0
time : 13:21
strike : 1
spare : 2
Pour les dates, j'aurais utilisé un timestamp, ça prend moins de place et se traite avec plus de facilité. Ça va aussi accélérer le chargement puisqu'il y aura moins de champs à trouver.
Ensuite, si tu veux juste une liste de dico, pourquoi utiliser une classe ? Une simple fonction qui charge le fichier à coup de 'split("|")' et retourne une liste de dico toute bête ?
a = '12|04|2010|12:33|5|121|1|4|0|5|0'.split('|')
b = 'month|day|year|hour:minutes|piste|score|strike|spare|split|null|hcp'.split('|')
c = dict(zip(b,a))
print c
Pour les dates, j'aurais utilisé un timestamp, ça prend moins de place et se traite avec plus de facilité. Ça va aussi accélérer le chargement puisqu'il y aura moins de champs à trouver.
Ensuite, si tu veux juste une liste de dico, pourquoi utiliser une classe ? Une simple fonction qui charge le fichier à coup de 'split("|")' et retourne une liste de dico toute bête ?
Non, étant donné que c'est pour renseigner des parties de bowling pour calculer un ratio.
Car j'aimerais que le fichier soit, à chaque changement, réécrit totalement, et que ce soit facile à traiter.
josmiley : Merci pour le coup du zip(), ca m'aide pas mal!
J'aimerais savoir maintenant comment, quand je réécris le fichier, que ce soit écrit dans le même ordre, et si on peut m'aider pour les méthodes __get/setitem__ ?
tu veux que, quand tu modifies mydict, ça enregistre automatiquement le fichier, c'est ça ?
peut-être en dérivant de dict et en réécrivant __setitem__ ?
tu veux que, quand tu modifies mydict, ça enregistre automatiquement le fichier, c'est ça ?
peut-être en dérivant de dict et en réécrivant __setitem__ ?
Oui c'est exactement ça
Justement j'y ai pensé, mais je vois pas du tout comment écrire ça ! (J'ai fait un bout de code, suffit de regarder au-dessus)
Le problème est que c'est self.content[x][y] = z que j'aimerais capturer, si c'est possible !
En passant, y'a moyen de simplifier la ligne 37 ?
Code actuel :
''' ./widgets/cfglib.py '''
from __future__ import with_statement
import os.path
class BowlingFile(object):
syntax = 'month|day|year|time|piste|score|strike|spare|split|null|hcp'.split('|')
def __init__(self, filepath):
self.filepath = filepath
self.content = self._parse()
def _parse(self):
returnDict = dict()
with open(self.filepath, 'r') as fileStream:
lines = fileStream.read().splitlines()
for line in lines:
if line.startswith('#'):
continue
returnDict[len(returnDict)] = dict(zip(self.syntax, line))
return returnDict
def _write(self):
with open(self.filepath, 'w') as fileStream:
for key in self.content:
fileStream.write('%s\r\n' % '|'.join(self.content[key][item] for item in self.syntax))
def addGame(self, *args):
if len(args) == len(self.syntax):
self.content[len(self.content)] = dict(zip(self.syntax, '|'.join(args)))
self._write()
else:
raise TypeError, 'addGame expected at %s arguments, got %s' % (len(syntax), len(args))
def removeGame(self, month, day, year, time):
for key in self.content:
if self.content[key]['month'] == month and self.content[key]['day'] == day and self.content[key]['year'] == year and self.content[key]['time'] == time:
del self.content[key]
return
raise IndexError, 'Game %s-%s-%s-%s cannot be found in file \'%s\'' % (month, day, year, time, self.filepath)
EDIT: Voici mon code, j'ai trouvé pour __setitem__ donc, le problème est comment je fais pour accéder à la méthode _write de la classe BowlingFile, celle-ci prenant comme argument le répertoire du fichier ?
''' ./widgets/cfglib.py '''
from __future__ import with_statement
import os.path
class BowlingFile(object):
class GameDict(dict):
def __setitem__(self, key, value):
# ...
super(GameDict, self).__setitem__(key, value)
syntax = 'month|day|year|time|piste|score|strike|spare|split|null|hcp'.split('|')
def __init__(self, filepath):
self.filepath = filepath
self.content = self._parse()
def _parse(self):
returnDict = dict()
with open(self.filepath, 'r') as fileStream:
lines = fileStream.read().splitlines()
for line in lines:
if line.startswith('#'):
continue
returnDict[len(returnDict)] = self.GameDict(zip(self.syntax, line.split('|')))
return returnDict
def _write(self):
with open(self.filepath, 'w') as fileStream:
for key in self.content:
fileStream.write('%s\r\n' % '|'.join(self.content[key][item] for item in self.syntax))
def addGame(self, *args):
if len(args) == len(self.syntax):
self.content[len(self.content)] = dict(zip(self.syntax, args))
self._write()
else:
raise TypeError, 'addGame expected at %s arguments, got %s' % (len(self.syntax), len(args))
def removeGame(self, month, day, year, time):
for key in self.content:
if (self.content[key]['month'], self.content[key]['day'], self.content[key]['year'], self.content[key]['time']) == (month, day, year, time):
del self.content[key]
return
raise IndexError, 'Game %s-%s-%s-%s cannot be found in file \'%s\'' % (month, day, year, time, self.filepath)
tu passes soit le nom du fichier à chaques objets GameDict, soit comme dans l'exemple ci-dessous, l'objet BowlingFile lui même ... ligne 17.
class master(list):
''
class foo(dict):
''
def __init__(self,master):
self.master = master
def __setitem__(self,i,j):
print 'nom du fichier:',self.master.filename
print 'nom de la cle:',i
print 'valeur de la cle:',j
super(master.foo,self).__setitem__(i,j)
print 'master vaut apres modif:',self.master
def __init__(self,filename):
self.filename = filename
for item in range(5):
self.append(self.foo(self))
M = master('mon_fichier')
M[0]['item1'] = 27
Hmm, j'ai eu un peu la flemme de tout lire, mais les namedtuples semblent bien adaptés à tes données (données groupées, nommées et immutables).
Je pense que je vais en rester aux dictionnaires pour l'instant, mais je vais regarder ça petit à petit.
Maxibolt : Comme je l'ai dit, je pense en rester aux dictionnaires!
josmiley : Je vois pas comment inclure ça dans mon code vraiment, et je suis pas sûr que ça marche.
Pour récapituler, j'utilise un dictionnaire (self.content) dans la classe BowlingFile qui contient des clefs digitales, contenant chacune un dictionnaire de type GameDict. J'aimerais que à chaque fois qu'une clef change ou est créé dans un objet de type GameDict, qu'il soit mise à jour dans le dictionnaire self.content de la classe BowlingFile, et qu'il l'écrit dans un fichier.
Le code actuel :
''' ./widgets/cfglib.py '''
from __future__ import with_statement
import sys
class GameDict(dict):
def __setitem__(self, key, value):
# Modify BowlingFile.content and access to BowlingFile(<path>).write() ...
super(GameDict, self).__setitem__(key, value)
class BowlingFile(object):
""" Class for handling .bwl files """
syntax = "month|day|year|time|piste|score|strike|spare|split|null|hcp".split("|")
def __init__(self, filepath):
""""
Default constructor, initialize variables
@PARAM str filepath - The file to parse
"""
self.filepath = filepath
self.content = self.parse()
def parse(self):
"""
Static method to parse the file
@RETURN dict - Dictionnary using the Class"s syntax
"""
returnDict = dict()
with open(self.filepath, "r") as fileStream:
lines = fileStream.read().splitlines()
for line in lines:
if line.startswith("#") or not len(line):
continue
returnDict[len(returnDict)] = GameDict(zip(self.syntax, line.split("|")))
return returnDict
def write(self):
"""
Static method to write the Class"s content into the file, using the Class"s syntax
"""
with open(self.filepath, "w") as fileStream:
for key in self.content:
fileStream.write("%s%s" % ("|".join(self.content[key][item] for item in self.syntax), "\n" if sys.platform == "win32" else "\r\n"))
def addGame(self, *args):
"""
Add a Game into the Class"s content
@PARAM tuple args - Class"s syntax related args, raise a TypeError if not
"""
if len(args) == len(self.syntax):
self.content[len(self.content)] = dict(zip(self.syntax, args))
self.write()
else:
raise TypeError, "addGame expected at %s arguments, got %s" % (len(self.syntax), len(args))
def removeGame(self, month, day, year, time):
"""
Remove a Game from the Class"s content
@PARAM str month - The month of the game to remove
@PARAM str day - The day of the game to remove
@PARAM str year - The year of the game to remove
@PARAM str time - The time of the game to remove (h:m)
Raise a IndexError if game doesn"t exist
"""
for key in self.content:
if (self.content[key]["month"], self.content[key]["day"], self.content[key]["year"], self.content[key]["time"]) == (month, day, year, time):
del self.content[key]
self.write()
return
raise IndexError, "Game %s-%s-%s-%s cannot be found in file '%s'" % (month, day, year, time, self.filepath)
Il n'y a aucun intérêt à réinventer un format de fichier et le parser qui va avec, plutôt que d'utiliser json ou yaml qui règlent le problème en 2 lignes de code...
Il n'y a aucun intérêt à réinventer un format de fichier et le parser qui va avec, plutôt que d'utiliser json ou yaml qui règlent le problème en 2 lignes de code...
Si c'est le cas, y'a moyen de me faire un exemple avec mon fichier et ma syntaxe s'il te plaît ?
Le mieux dans ton cas est d'utiliser yaml, car json ne peut pas sauvegarder directement des objets datetime par exemple. Yaml le fait automatiquement (et aussi pour tout un tas d'autres types) donc c'est extrêmement pratique.
Bien sûr ça change le format de fichier, mais ce n'est pas important, puisque c'est toi qui définis le format, donc tu mets ce que tu veux dedans. Autant utiliser un vrai format.
Sinon, voici un parser (très incomplet) pour ton format de fichier :
import pprint
# parser un format de fichier ad-hoc
fields = "month", "day", "year", "time", "piste", "score", "strike", "spare", "split", "null", "hcp"
data = [ dict( zip( fields, line.strip().split( "|" ))) for line in open( "bidon.txt" ) if not line.isspace() ]
pprint.pprint( data )
Création d'une classe (dict-like) pour parser un fichier!
× Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
× Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
Python c'est bon, mangez-en.
Python c'est bon, mangez-en.
Python c'est bon, mangez-en.
Python c'est bon, mangez-en.
Python c'est bon, mangez-en.
Python c'est bon, mangez-en.
Python c'est bon, mangez-en.