Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

Fin de vie d'une classe

2 réponses
Avatar
Pierre Maurette
Bonsoir,

A la relecture de mon code, je tombe sur des points que j'avais laissé
à l'état flou en première intention, mais qui toutefois fonctionnent.
J'isole ce qui concerne la finalisation d'une instance de classe.

Premier cas, une interface Tkinter, le code (piqué quelque part sans
doute) me semble convenable (je simplifie):

class RepFTPApp(Tk):
def __init__(self):
Tk.__init__(self)
self.protocol("WM_DELETE_WINDOW", self.quit)
#etc.

def quit(self):
#sauvegardes diverses
Tk.destroy(self)


C'est le second cas qui me chagrine. Une classe client FTP:

class SourceSyncByFTP(ftplib.FTP):
def __init__(self, cl_options):
#etc.
if 'action' in self.dicodata and self.dicodata['action'] in
self.actions_dict:
self.actions_dict[self.dicodata['action']]()
self.__del__()

def __del__(self):
try:
ftplib.FTP.quit(self)
except:
ftplib.FTP.close(self)


Dans l'application actuelle, la classe est instanciée - plusieurs fois
- en 'one-shot', c'est à dire que l'instance meurt à la fin de
l'__init__(). Mais elle est utilisable en instanciation persistante,
avec gestion des reconnexions.
Il est clair dans ces conditions que le code du __del__() est
nécessaire, j'ai fait des tests sur un serveur limité à 1 ou 2
connexions entrantes qui le confirment.
Il est également évident que ce code ne détruit pas l'instance. Donc
c'est certainement idiot d'avoir nommé la méthode __del__. Ce serait
mieux de ne pas faire de méthode, ou de la nommer quelque chose comme
disconnect(), n'est-ce pas ?

Moi, ou plutôt le singe tenant la souris, sommes susceptibles
d'instancier frénétiquement. Passer en persistant serait lourd, je n'y
tiens pas. Je crois qu'il n'est pas possible de forcer la destruction
d'une instance à partir d'elle même, et que ce n'est ni joli ni
pratique de le faire depuis la classe cliente. Est-ce que, comme je le
crois, je m'inquiète inutilement, à partir du moment où je facilite le
travail de l'interprêteur (et du GC) en ne récupérant même pas
l'instance ? Ça ressemble à ça:

def doaction(self, action, noif=True):
#bla
try:
repftp.SourceSyncByFTP(options)
except repftp.ExpectedException, e:
if e.code is str and e.code[:5] == 'owned':
print '\nOWNED ! \n', e.message, '\n', e.cause
else:
print e.code, '\n', e.message, '\n', e.cause
except Exception, e:
print 'Unexpected Exception in '
print sys.exc_info()
#bla



Question subsidiaire: au départ, j'avais écrit:

def __del__(self):
try:
self.quit()
except:
self.close()

J'ai préféré modifier, pour qu'il soit clair à la lecture du code que
quit() et close() sont bien les méthodes de l'objet FTP. Est-ce
judicieux ?

Merci à tous, bonne soirée...

--
Pierre Maurette

2 réponses

Avatar
MCI, Shadok Gouroudoudou
Bonsoir !


Juste une idée, vite fait, en passant : et si, pour instancier, tu
passais par une classe fabrique, qui mémoriserait les (références d')
instances ? Il suffirait d'utiliser une méthode de la classe
fabrique, pour détruire une instance.


Autre solution, suggérée par ma fille : attendre fin juin ; les
classes sont alors automatiquement détruites, pour la fin de l'année
scolaire.









--
@-salutations

Michel Claveau
Avatar
Pierre Maurette
Bonsoir !


Juste une idée, vite fait, en passant : et si, pour instancier, tu passais
par une classe fabrique, qui mémoriserait les (références d') instances ?
Il suffirait d'utiliser une méthode de la classe fabrique, pour détruire une
instance.


Merci pour la suggestion, mais une factory à mon avis ne s'impose pas
ici. Je viens de reprendre le truc à froid, et mon erreur datant de mes
premières lignes en Python devient évidente.

J'ai d'abord pensé comme dans d'autres langages à écrire du code de
finalisation dans le destructeur, d'où __del__. J'ai très vite vu avec
Google et en faisant des tests que ce n'était pas la bonne voie(*).
J'ai donc appelé directement __del__, sans le renommer, ce qui est à
l'origine de la confusion.

J'ai maintenant renommé __del__ en disconnect, ce qui est exactement ce
que fait la méthode. Sans elle, j'avais éventuellement des problèmes de
nombre de connexions ouvertes, mais je n'ai en fait aucun problème de
destruction d'instance:

Soit j'initialise le repftp.SourceSyncByFTP avec une ation à effectuer,
et le disconnect est appelé automatiquement, soit je l'initialise sans
action. J'ai donc par exemple ces cas de figure:

repftp.SourceSyncByFTP(options_avec_action)

ou:

ssftp = repftp.SourceSyncByFTP(options_sans_action)
ssftp.doaction(action1) #Connexion/reconnexion automatique
ssftp.doaction(action2) #Connexion/reconnexion automatique
#etc.
ssftp.doaction(actionN) #Connexion/reconnexion automatique
ssftp.disconnect()

Si je ne récupère pas l'instance (premier cas) je n'ai pas de référence
sur elle. Si j'utilise ssftp, je n'ai plus de référence quand je sors
de la méthode dans laquelle est l'appel. Si j'utilisais self.ssftp, je
n'ai plus de référence sur l'instance quand j'en crée une nouvelle,
donc au maximum un objet repftp.SourceSyncByFTP référencé. A partir de
là, je laisse Python se démerder. Correct ?

(*) Alors que ça fonctionne très bien avec une classe dérivée de Tk
par:
self.protocol("WM_DELETE_WINDOW", self.quit)

Autre solution, suggérée par ma fille : attendre fin juin ; les classes sont
alors automatiquement détruites, pour la fin de l'année scolaire.


Et vos 'factories', vous les nommez charlemagne, jules_ferry, voire
ed_nat ? ;-)

--
Pierre Maurette