OVH Cloud OVH Cloud

lire dans un fichier => ''

8 réponses
Avatar
R12y
Bonjour,

J'ai une classe Counter et un fichier /tmp/counter qui contient un entier
(68 au moment ou j'écris). En fait comme on le sait tous il sera lu comme
'68\n'.
Mais ce n'ai pas le problème. Le souci c'est que si je fais un

c=Counter()

puis sun

c.state alors je vois que dans c.state il y a '', soit la chaine vide.
Dans /tmp/counter, il y a toujours '68\n', pourtant.

Je ne comprends pas ce qui se passe.
Ma conlcusion est que si dans c.state c'est la chaine vide, alors dans la
fonction _get_state() il est allé dans le "else" mais il n'a lu que dalle.
Ou alors, il y a des problèmes d'encodage encore qui fait qu'il y a des
caractères que je ne vois pas à l'écran...

Auriez-vous une piste qui m'aiderait à résoudre ce souci?

Ce qui m'étonne c'est qu'avant hier, je travaillait sur ce compteur et son
comportement (dans l'ensemble du programme) m'a satisfait, et c'est pour
ça que j'ai pu faire une pause d'un jour, mais maintenant que je reprends
les choses, je sens que je naurais pas dû prendre cette pause...

Voici comment est batie la classe Counter:


class Counter:
def __init__(self):
self.filename="/tmp/counter"
self.state=self._get_state()
def _get_state(self):
fd=open(self.filename,'r')
if fd.readline()=='':
s=0
else:
s=fd.readline()[:-1]
fd.close()
return s
def _write_file(self, n):
fd=open(self.filename,'w')
fd.writelines([str(n)+'\n'])
fd.close()
def increment(self):
self.state+=1
self._write_file(self.state)
def time_tsotra(self):
return ((self.state % 2) == 0)
def time_pitiny(self):
return ((self.state % 3) == 0)

--
Debian/apt Repo: http://locataire-serveur.info/sections/liens/debian-repository
Fedora/yum Repo: http://locataire-serveur.info/sections/liens/fedora-core-yum

8 réponses

Avatar
coisfran
1--if fd.readline()=='':
2-- s=0
3-- else:
4-- sý.readline()[:-1]
5-- fd.close()

Lorsue tu effectue _get_state tu lis 2 lignes hors du fichier la
premiere pour efefctuer le test
(1--) la seconde lorsque tu pense affecter la variable s. (4--) comme
l'unique ligne du fichier est lue dans un il est normal que finalement
c=''

essaie ceci a la place
1--sý.readline()[:-1]
2-- if s=='':
s=0
5-- fd.close()

meme si ceci pas tres joli, car quand tu ne trouves rien dans le
fichier tu mets 0 (entier) dans la variable autrement tu y mets une
chaine de caratere.
fma
Avatar
bruno at modulix
R12y wrote:
Bonjour,

J'ai une classe Counter et un fichier /tmp/counter qui contient un entier
(68 au moment ou j'écris). En fait comme on le sait tous il sera lu comme
'68n'.


Ce n'est donc pas un entier, mais une chaine.

Mais ce n'ai pas le problème. Le souci c'est que si je fais un

c=Counter()

puis sun

c.state alors je vois que dans c.state il y a '', soit la chaine vide.
Dans /tmp/counter, il y a toujours '68n', pourtant.


Et ?

Je ne comprends pas ce qui se passe.
Ma conlcusion est que si dans c.state c'est la chaine vide, alors dans la
fonction _get_state() il est allé dans le "else" mais il n'a lu que dalle.


Si si, il a bien lu. cf plus bas.

Ou alors, il y a des problèmes d'encodage encore qui fait qu'il y a des
caractères que je ne vois pas à l'écran...


Je doute que ce soit le pb.

Auriez-vous une piste qui m'aiderait à résoudre ce souci?


Oui.

Ce qui m'étonne c'est qu'avant hier, je travaillait sur ce compteur et son
comportement (dans l'ensemble du programme) m'a satisfait,


Ce sont surtout tes tests unitaires qui devraient être satisfaits...

et c'est pour
ça que j'ai pu faire une pause d'un jour, mais maintenant que je reprends
les choses, je sens que je naurais pas dû prendre cette pause...

Voici comment est batie la classe Counter:


class Counter:


class Counter(object):

def __init__(self):
self.filename="/tmp/counter"


Ca ne devrait pas être codé en dur.

Et dis moi, que va-t'il se passer quand deux compteurs tourneront ?

self.state=self._get_state()
def _get_state(self):
fd=open(self.filename,'r')


Attention, ça peut échouer.

if fd.readline()=='':
s=0
else:
sý.readline()[:-1]


Pour se débarrasser du 'n', utilise strip(). Et attention, Python est
fortement typé. Un entier et une chaine sont deux types différents, et
il n'y a pas de transtypage automatique. Il faut le faire soit-même.

Par ailleurs, tu appelles *2* fois readline(). Donc la seconde fois, tu
lis une hypothétique deuxième ligne...

def _read_state(self):
f = open(self.filename, 'r')
try:
s = int(f.readline().strip())
except ValueError, e:
s = 0
f.close()
return s

(snip)

def _write_file(self, n):
fd=open(self.filename,'w')
fd.writelines([str(n)+'n'])
fd.close()
def increment(self):
self.state+=1
self._write_file(self.state)
def time_tsotra(self):
return ((self.state % 2) == 0)
def time_pitiny(self):
return ((self.state % 3) == 0)



AMHA, tu devrais séparer la gestion de la persistence du reste. Ce sont
deux responsabilités distinctes, et tu ne devrais pas avoir à modifier
la classe Counter si tu changes de système de persistence.

class PersistentCounter(object):
def __init__(self, persister, default_count = 0):
self._persister = persister
self._default_count = default_count
self._count = self.persister.read_count(self._default_count)

def _get_count(self):
return self._count
count = property(fget=_get_count)

# NB : this could be implemented
# by overriding the augmented assignement op
def increment(self):
self._count += 1
self._persister.persist_count(self._count)

def time_tsotra(self):
return ((self.count % 2) == 0)

def time_pitiny(self):
return ((self.count % 3) == 0)


class FileCountPersister(object):
def __init__(self, filename):
self.filename = filename
def read_count(self, default=0):
# read op
def persist_count(self, count):
# write op

# and now the client code is responsible for handling
# platform-specific path and avoiding concurrent access
# to the same file...

counter1 = PersistentCounter(FileCountPersister('/tmp/count1.dat'))
counter2 = PersistentCounter(FileCountPersister('/tmp/count2.dat'))



Note bien que ce n'est pas forcément *la* solution - mais sans connaitre
le contexte, difficile de proposer mieux...

Mes 2 centimes...
--
bruno desthuilliers
python -c "print '@'.join(['.'.join([w[::-1] for w in p.split('.')]) for
p in ''.split('@')])"

Avatar
R12y
bruno at modulix :

Et dis moi, que va-t'il se passer quand deux compteurs tourneront ?


Bruno, :-)... C"était censé être la deuxième petite question que j'allais
justement poser:

Comment on peut implémenter "l'unicité"? (il ne faut pas qu'il y ait deux
compteurs qui se promènent)

J'ai créé une classe parceque je trouvais ça pas mal d'avoir la
possibilité d'avoir des méthodes d'instance sur le compteur
(incrémentation et toussa..), mais maintenant, comment lever une exception
en cas de tentative de création de deuxième compteur? Ou alors peut-être
aurais-je dû choisir une autre structure de données?

--
Debian/apt Repo: http://locataire-serveur.info/sections/liens/debian-repository
Fedora/yum Repo: http://locataire-serveur.info/sections/liens/fedora-core-yum

Avatar
Hervé Cauwelier
Comment on peut implémenter "l'unicité"? (il ne faut pas qu'il y ait deux
compteurs qui se promènent)


Regarde du côté du design pattern Singleton.

Sinon, une bonne idée serait de demander au module Python qui va bien,
tempfile, de générer un nom de fichier temporaire unique.

--
Hervé Cauwelier
http://www.oursours.net/

Avatar
bruno at modulix
R12y wrote:
bruno at modulix :


Et dis moi, que va-t'il se passer quand deux compteurs tourneront ?



Bruno, :-)... C"était censé être la deuxième petite question que j'allais
justement poser:

Comment on peut implémenter "l'unicité"? (il ne faut pas qu'il y ait deux
compteurs qui se promènent)


D'un pur point de vue OO : Singleton ou Borg...
D'un pur point de vue hacker : mettre un lock sur le fichier !-)

D'une façon plus pragmatique, tu avais déjà la réponse en bas de mon
post précédent... Le problème n'est pas d'éviter d'avoir deux compteurs,
c'est d'éviter que deux compteurs ne se marchent sur les pieds.

J'ai créé une classe parceque je trouvais ça pas mal d'avoir la
possibilité d'avoir des méthodes d'instance sur le compteur
(incrémentation et toussa..),


Honnêtement, c'est vraiment utile ou c'est juste pour te faire plaisir ?
(NB : je ne dis pas que c'est forcément inutile...)

mais maintenant, comment lever une exception
en cas de tentative de création de deuxième compteur? Ou alors peut-être
aurais-je dû choisir une autre structure de données?


la question que je me pose, surtout, c'est
1/ pourquoi tu veux stocker l'état du compteur dans un fichier ?
2/ pourquoi tu veux le faire à chaque incrément ?
(concernant le second point, tu imagines ce que ça va donner dans une
boucle ? bonjour les perfs...)


--
bruno desthuilliers
python -c "print '@'.join(['.'.join([w[::-1] for w in p.split('.')]) for
p in ''.split('@')])"


Avatar
R12y
bruno at modulix :

D'un pur point de vue OO : Singleton ou Borg...
D'un pur point de vue hacker : mettre un lock sur le fichier !-)


Ok.

D'une façon plus pragmatique, tu avais déjà la réponse en bas de mon
post précédent... Le problème n'est pas d'éviter d'avoir deux compteurs,
c'est d'éviter que deux compteurs ne se marchent sur les pieds.


En fait, moi ça m'arrangerais d'avoir un moyen d'éviter que deux compteur
existent.

J'ai créé une classe parceque je trouvais ça pas mal d'avoir la
possibilité d'avoir des méthodes d'instance sur le compteur
(incrémentation et toussa..),
Honnêtement, c'est vraiment utile ou c'est juste pour te faire plaisir ?



J'ai trouve une utilisation des classes et je m'en suis servi.
Quand j'ai cherché comment implémenter ce que je veux faire, c'est comme
ça que ça m'est venu.

mais maintenant, comment lever une exception
en cas de tentative de création de deuxième compteur? Ou alors peut-être
aurais-je dû choisir une autre structure de données?


la question que je me pose, surtout, c'est
1/ pourquoi tu veux stocker l'état du compteur dans un fichier ?


- Je suis encore imprégné de la programmation shell. C'est assez dur de
s'en désimprégner ;-)
- Mon programme plante encore assez (trop) souvent du fait que j'utilise
des trucs encore assez instables (shout-python et ogg/theora). Si je dois
réinitialiser ce compteur à chaque relance, je bousille le cahier des
charges.

2/ pourquoi tu veux le faire à chaque incrément ?


Persistence. Si je ne sauve pas l'état du compteur quelquepart, comment
pourrais-je le récupérer si "ça plante"?

Pour remettre les choses dans le contexte, j'incrémenterais le compteur
environ toutes les 2-3 minutes. A moins d'avoir un ordinateur déjà à
genoux, ça devrait être jouable.

--
Debian/apt Repo: http://locataire-serveur.info/sections/liens/debian-repository
Fedora/yum Repo: http://locataire-serveur.info/sections/liens/fedora-core-yum


Avatar
Bruno Desthuilliers
bruno at modulix :


D'un pur point de vue OO : Singleton ou Borg...
D'un pur point de vue hacker : mettre un lock sur le fichier !-)



Ok.


D'une façon plus pragmatique, tu avais déjà la réponse en bas de mon
post précédent... Le problème n'est pas d'éviter d'avoir deux compteurs,
c'est d'éviter que deux compteurs ne se marchent sur les pieds.



En fait, moi ça m'arrangerais d'avoir un moyen d'éviter que deux compteur
existent.


Si ça correspond à un besoin effectif de ton appli, c'est autre chose.

J'ai créé une classe parceque je trouvais ça pas mal d'avoir la
possibilité d'avoir des méthodes d'instance sur le compteur
(incrémentation et toussa..),


Honnêtement, c'est vraiment utile ou c'est juste pour te faire plaisir ?



J'ai trouve une utilisation des classes et je m'en suis servi.


Ce que je veux dire, c'est: était-il utile de créer une classe pour ça ?
(et ça ne préjuge pas de la réponse... )

Quand j'ai cherché comment implémenter ce que je veux faire, c'est comme
ça que ça m'est venu.


mais maintenant, comment lever une exception
en cas de tentative de création de deuxième compteur?




Pas la bonne soluce... Regarde les patterns Singleton et Borg (tu
trouvera le second dans le python cookbook).

Ou alors peut-être
aurais-je dû choisir une autre structure de données?


la question que je me pose, surtout, c'est
1/ pourquoi tu veux stocker l'état du compteur dans un fichier ?



- Je suis encore imprégné de la programmation shell. C'est assez dur de
s'en désimprégner ;-)
- Mon programme plante encore assez (trop) souvent du fait que j'utilise
des trucs encore assez instables (shout-python et ogg/theora). Si je dois
réinitialiser ce compteur à chaque relance, je bousille le cahier des
charges.


???


2/ pourquoi tu veux le faire à chaque incrément ?



Persistence.


Ca j'avais compris, merci :-/

La question était de savoir s'il était judicieux de le faire *à chaque
incrément*.

Note que cet aspect là (ie: à quel moment l'état du compteur doit-il
être sauvegardé) pourrait aussi être rendu paramétrable si tu délègue la
persistence à un autre objet.

Si je ne sauve pas l'état du compteur quelquepart, comment
pourrais-je le récupérer si "ça plante"?


En recalculant ?

<hs>
Tu connais le cas d'utilisation de ton compteur, moi pas. Je ne peux
donc pas être à même de juger du bien fondé de certains choix. Comme je
te sais débutant (pas d'offense, tu l'annonces clairement toi-même), je
me permet de poser quelques questions qui peuvent t'aider - ou pas - à
faire au mieux. A toi de voir si ces questions, remarques etc sont
pertinentes ou non.
</hs>

Pour remettre les choses dans le contexte, j'incrémenterais le compteur
environ toutes les 2-3 minutes. A moins d'avoir un ordinateur déjà à
genoux, ça devrait être jouable.


Effectivement, dans ce cas, je ne pense pas que ce soit un pb majeur...



Avatar
Eric Deveaud
R12y wrote:
bruno at modulix :

2/ pourquoi tu veux le faire à chaque incrément ?


Persistence. Si je ne sauve pas l'état du compteur quelquepart, comment
pourrais-je le récupérer si "ça plante"?


voir du coté de atexit()

Eric
--
C'est pas moi qui ait parlé du spam, d'ailleurs je vois mal comment on
peut faire du spam sur Usenet Je ne défend pas les spammeurs, je défend
la liberté d'expression.
-+- LP in <http://www.le-gnu.net> : Neuneu d'or novembre 2000. -+-