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

Accéder à la chaîne qui constitue le nom d'une variable

10 réponses
Avatar
Denis Bitouzé
Bonjour,

y a-t-il moyen de construire une fonction nom_variable telle que, si :

ma_variable=3D'test'

alors :

nom_variable(ma_variable)

renvoie la cha=EEne :

'ma_variable'

Merci d'avance.
--=20
Denis

10 réponses

Avatar
Pierre Quentel
On 18 juin, 17:47, Denis Bitouzé wrote:
Bonjour,

y a-t-il moyen de construire une fonction nom_variable telle que, si :

ma_variable='test'

alors :

nom_variable(ma_variable)

renvoie la chaîne :

'ma_variable'

Merci d'avance.
--
Denis



Bonsoir,

Oui, il y a moyen... mais si tu as besoin d'une telle fonction, c'est
que ton code n'est pas "pythonique". Si tu nous dis pourquoi tu en as
besoin, on te dira comment faire autrement

- Pierre
Avatar
Bruno Desthuilliers
Pierre Quentel a écrit :
On 18 juin, 17:47, Denis Bitouzé wrote:
Bonjour,

y a-t-il moyen de construire une fonction nom_variable telle que, si :

ma_variable='test'

alors :

nom_variable(ma_variable)

renvoie la chaîne :

'ma_variable'

Merci d'avance.
--
Denis



Bonsoir,

Oui, il y a moyen...



Ajoutons au passage que selon le contexte, ce n'est pas forcément simple
ni fiable...

<op>
La notion de "variable" en Python est assez différente de celle en C ou
en Pascal... Au lieu d'être un "conteneur de donnée", c'est une
association entre un nom et une référence sur un objet - le dit objet
existant indépendemment de ce nom[1], et pouvant être référencé par
plusieurs noms différents.

Dans ton example ci-dessus, la première ligne instancie un objet de type
chaine, puis associe une référence à cette objet au nom 'ma_variable'
dans l'espace de nommage courant. Si tu ajoute la ligne suivante:

mon_alias = ma_variable

tu aura alors deux noms référençant le même objet:

mon_alias is ma_variable
=> True

Dans ces conditions, que devrait retourner ta fonction "nom_variable" ?

[1] toutes considérations liées à la gestion de mémoire mises à part,
bien sûr...
</op>

mais si tu as besoin d'une telle fonction, c'est
que ton code n'est pas "pythonique". Si tu nous dis pourquoi tu en as
besoin, on te dira comment faire autrement



+1
Avatar
Encolpe Degoute
Denis Bitouzé a écrit :
Bonjour,

y a-t-il moyen de construire une fonction nom_variable telle que, si :

ma_variable='test'

alors :

nom_variable(ma_variable)

renvoie la chaîne :

'ma_variable'




ça ressemble à la création d'une liste d'objets en PHP...

class nomVariable:
"""Attention code identé avec 2 caractère"""

variables = {}
reciproque = {}

def add_variable(self, cle, valeur):
"""ajout d'une variable"""
self.variable[cle] = valeur
self.reciproque[valeur] = cle

def nom_variable(self, valeur):
"""récupération du nom de la variable"""
return self.reciproque.get(valeur)

def get(self, cle):
"""le get standard"""
return self.variables.get(cle)


Évidemment il y a plein d'effets de bord et c'est vraiment crade

--
Encolpe DEGOUTE
http://encolpe.degoute.free.fr/
Logiciels libres, hockey sur glace et autres activités cérébrales
Avatar
Kobayashi
Denis Bitouzé a écrit :
Bonjour,

y a-t-il moyen de construire une fonction nom_variable telle que, si :

ma_variable='test'

alors :

nom_variable(ma_variable)

renvoie la chaîne :

'ma_variable'

Merci d'avance.



Bonjour,

J'ai eu besoin de faire cela dans un cas très particulier :
un éditeur de jeux de données ... C'est surement très loin
de ce que tu veux faire mais je poste quand même au cas
où quelqu'un connait une solution plus simple !

L'utilisateur écrit un jeu de donnée python :

a = A(1, 2, 3)
b = B(a, [2, 3])
...

et quand, il fait "import" dans mon éditeur (en pyqt),
je voulais qu'apparaisse les noms "a" et "b" qui sont
à gauche du signe égal.

Ma solution ne fonctionne que pour les classes dérivant
d'une classe de base appelée XObject et est soumise à
quelques restrictions décrites ailleurs dans la discussion,
par exemple, si l'utilisateur écrit :

a = A(1, 2, 3)
aa = a
b = B(aa, [2, 3])
...

Il ne verra que a et b dans l'éditeur.

Enfin, dans 99% des cas, cela marche puisque mon éditeur
fait Export / Import et que les jeux de donnée importés
ont habituellement été créés par l'éditeur lui-même.

Alors, attention, on accroche la ceinture !!

Pour, faire cela, j'ai créé une metaclass pour ma classe
XObject et dans le __call__ de la metaclass, j'appelle
une fonction getCreationInformations qui me donne
trois informations sur la création de l'object :

code_next_operation, instance_name, code_percent = getCreationInformations()

code_next_operation me dit si l'objet est créé à la racine
du jeu de donnée, instance_name me donne son nom et code_percent
me donne en pourcentage où on en est du jeu de donnée (pour
être affichée dans une progress bar)

Bon, voici le code (bon courage !!):

# --
#

class DisassembledCodeItem(object):
def __init__(self, code):
lasti, instruction, name = None, None, None
fields = code.split()
lasti = int(fields[0])
instruction = fields[1]
if instruction in [
'STORE_NAME',
'STORE_ATTR',
'STORE_FAST',
]:
name = fields[2]
pass
self.lasti = lasti
self.instruction = instruction
self.name = name
return
pass

class DisassembledCode(object):
def __init__(self, disco):
lasti_max = 0
lasti2item = {}
lines = disco.split('n')
for i in range(len(lines)):
item = DisassembledCodeItem(lines[i])
lasti2item[item.lasti] = item
#
if i > 0:
previous_item.next = item
pass
previous_item = item
#
lasti = item.lasti
if lasti > lasti_max:
lasti_max = lasti
pass
#
pass
self.lasti2item = lasti2item
self.lasti_max = lasti_max
return
pass

code2disco = {}


def Disassemble(co, lasti=-1):
"""Disassemble a code object."""
import dis
aString = ""
code = co.co_code
n = len(code)
i = 0
while i < n:
c = code[i]
op = ord(c)
#
# In python 2.3.x, dis has no attribute SET_LINENO
try:
is_set_lineno = ( op == dis.SET_LINENO )
except AttributeError:
is_set_lineno = 0
pass
if is_set_lineno:
i = i+3
continue
#
aList = []
aList.append(`i`)
aList.append(dis.opname[op])
i = i+1
if op >= dis.HAVE_ARGUMENT:
oparg = ord(code[i]) + ord(code[i+1])*256
i = i+2
if 0:
pass
elif op in dis.hasname:
aList.append(co.co_names[oparg])
elif op in dis.haslocal:
aList.append(co.co_varnames[oparg])
pass
pass
aList.append("n")
aString += ' '.join(aList)
pass
# Remove the last "n"
aString = aString[:-1]
return aString

def getDisassembledCode(code):
#
if code.co_filename == "<string>":
aString = Disassemble(code)
return DisassembledCode(aString)
#
code_id = id(code)
try:
return code2disco[code_id]
except KeyError:
pass
aString = Disassemble(code)
disco = DisassembledCode(aString)
# --
# If the code is defined in an exec "string" statement
# do not register it ...
#
if code.co_filename == "<string>":
return disco
#
code2disco[code_id] = disco

return getDisassembledCode(code)


def getCreationInformations(shift=0):
# --
# stacks contains all the frames
from inspect import currentframe
frame = currentframe()
# --
# the frame is here --> frame back
frame = frame.f_back
# the frame is the frame which called the function --> frame back
frame = frame.f_back
# --
while 1:
#
code = frame.f_code
code = getDisassembledCode(code)
item = code.lasti2item[frame.f_lasti]
item = item.next
# --
next_operation, name = item.instruction, item.name
# --
if next_operation == 'LOAD_FAST':
# -- shift to the next item
item = item.next
next_operation, name = item.instruction, item.name
pass
# --
if next_operation == "RETURN_VALUE":
frame = frame.f_back
continue
# --
if next_operation == "STORE_NAME":
percent = float(frame.f_lasti) / code.lasti_max
else:
percent = None
pass
# --
break
return next_operation, name, percent


Qu'est ce qu'on rigole, hein ??


K.
Avatar
Denis Bitouzé
Le jeudi 18/06/09 à 12h30,
Pierre Quentel a écrit :

Si tu nous dis pourquoi tu en as besoin, on te dira comment faire
autrement



Bon, je vais essayer d'être synthétique.

Le cadre est celui de la validation d'un formulaire dans Plone. Certains
champs du formulaire ont pour noms (disons) :

champ_1
...
champ_n

Je récupère la valeur qui leur est passée au moyen de :

champ_1 = context.REQUEST.get('champ_1', None)
...
champ_n = context.REQUEST.get('champ_n', None)

puis je valide les valeurs au moyen de :

if champ_1=="Mauvais choix":
message_erreur('champ_1')
...
if champ_n=="Mauvais choix":
message_erreur('champ_n')

Et c'est dans cette dernière partie que j'aurais aimé pourvoir disposer
d'une fonction nom_variable pour pouvoir n'écrire qu'un truc du genre :

champs = [champ_1,...,champ_n]

for champ in champs:
if champ=="Mauvais choix":
message_erreur(nom_variable(champ))

Je sais, je suis flemmard, mais il faut dire que n est grand et les
champs ne portent en fait pas tous des noms semblables...

Merci !
--
Denis
Avatar
Pierre Quentel
On 20 juin, 17:54, Denis Bitouzé wrote:
Le jeudi 18/06/09 à 12h30,
Pierre Quentel a écrit :

> Si tu nous dis pourquoi tu en as besoin, on te dira comment faire
> autrement

Bon, je vais essayer d'être synthétique.

Le cadre est celui de la validation d'un formulaire dans Plone. Certains
champs du formulaire ont pour noms (disons) :

champ_1
...
champ_n

Je récupère la valeur qui leur est passée au moyen de :

champ_1 = context.REQUEST.get('champ_1', None)
...
champ_n = context.REQUEST.get('champ_n', None)

puis je valide les valeurs au moyen de :

if champ_1=="Mauvais choix":
    message_erreur('champ_1')
...
if champ_n=="Mauvais choix":
    message_erreur('champ_n')

Et c'est dans cette dernière partie que j'aurais aimé pourvoir dispos er
d'une fonction nom_variable pour pouvoir n'écrire qu'un truc du genre :

champs = [champ_1,...,champ_n]

for champ in champs:
    if champ=="Mauvais choix":
        message_erreur(nom_variable(champ))

Je sais, je suis flemmard, mais il faut dire que n est grand et les
champs ne portent en fait pas tous des noms semblables...

Merci !
--
Denis



Bonsoir,

Il y a peut-être quelque chose qui m'échappe, mais je ne vois pas
pourquoi tu as besoin de créer les variables champ_1, etc. Ce code
devrait faire la meme chose :

===========
noms_champs = ['champ_1','champ_2',...,'champ_n']

for nom_champ in noms_champs:
valeur = context.REQUEST.get(nom_champ,None)
if valeur == "Mauvais choix":
message_erreur(nom_champ,valeur)
===========

- Pierre
Avatar
Denis Bitouzé
Le dimanche 21/06/09 à 13h07,
Pierre Quentel a écrit :

Il y a peut-être quelque chose qui m'échappe, mais je ne vois pas
pourquoi tu as besoin de créer les variables champ_1, etc. Ce code
devrait faire la meme chose :

===========
noms_champs = ['champ_1','champ_2',...,'champ_n']

for nom_champ in noms_champs:
valeur = context.REQUEST.get(nom_champ,None)
if valeur == "Mauvais choix":
message_erreur(nom_champ,valeur)
===========



C'est en effet une (bonne !) solution, notamment dans le cas qui
m'occupe parce que nulle part ailleurs dans le code je n'ai besoin de
réutiliser les variables et/ou noms de variables. Dans le cas
contraire par contre, peut-être faudrait-il trouver une autre
solution...

Merci !
--
Denis
Avatar
Denis Bitouzé
Le samedi 20/06/09 à 20h24,
Francois a écrit :

Je vais dire peut-être une bêtise, mais pourquoi ne pas faire des
objets de type Champ qui auraient comme attributs nom_du_champ et
valeur_du_champ ?



Euh... je vais essayer de voir comment faire cela.

Merci !
--
Denis
Avatar
Denis Bitouzé
Le lundi 22/06/09 à 11h02,
Bruno Desthuilliers a
écrit :

Utilise un dictionnaire, ce sera plus maniable...



Effectivement.

Et elle fait quoi ta fonction "message_erreur" ?



Elle réaffiche la page avec, en haut de celle-ci, un message annonçant
qu'il faut corriger les champs fautifs et met ceux-ci dans une boîte
de couleur de façon à ce qu'on les repère rapidement. Cette fonction
n'est pas de moi : elle est livrée avec Plone.

> Je sais, je suis flemmard,

Ca c'est plutôt une qualité - ça pousse à généraliser le code au lieu
de faire du copié/collé comme un gros bourrin.



;)

Par contre, il faut généraliser proprement. Accessoirement,
l'automatisation de la validation de formulaires web n'est pas
exactement un problème nouveau - y a déjà pas mal de solutions
existantes. Dont certaines inclues dans Plone si mon souvenir est
bon...



Oui, c'est justement celle que j'utilise, mais pour un formulaire que
j'ai créé moi-même (sans l'aide d'outils du genre Archetype ou
Formulator), donc avec de nouveaux champs...

Merci !
--
Denis
Avatar
Denis Bitouzé
Le mercredi 01/07/09 à 12h29,
Bruno Desthuilliers a
écrit :

Vu l'exemple de code que tu donnais, tu te retrouve avec un système
qui s'arrête à la première erreur de validation - au lieu de
collecter toutes les erreurs en une seule passe, et de toutes les
afficher d'un coup.



Euh, le terme générique message_erreur que j'ai choisi n'est peut-être
pas très heureux : j'aurais dû choisir plutôt procedure_erreur ou un
truc du genre. Mais, c'est en fait des :

missingtext

définis par :

def missingtext(field):
state.setError(field, 'Ce champ est requis. Merci de bien vouloir
saisir au moins une information.', 'input_required')

Du coup, ça collecte bien toutes les erreurs avant de réafficher la
page :)

je pensais à ça en l'occurrence:

http://plone.org/documentation/how-to/forms/



Oui, c'est ce genre de choses que j'utilise (en n'ayant pas lu cette
page d'ailleurs, mais en ayant analysé les formulaires par défaut de
Plone).
--
Denis