web-dev-qa-db-fra.com

Comment puis-je obtenir le nom d'un objet en Python?

Est-il possible d'obtenir le nom d'un objet en Python? Par exemple:

my_list = [x, y, z] # x, y, z have been previously defined

for bla in my_list:
    print "handling object ", name(bla) # <--- what would go instead of `name`?
    # do something to bla

Edit: / Quelques contextes:

En réalité, je crée une liste de fonctions que je peux spécifier à l'aide de la ligne de commande.

J'ai:

def fun1:
    pass
def fun2
    pass
def fun3:
    pass

fun_dict = {'fun1': fun1,
            'fun2': fun2,
            'fun3': fun3}

Je reçois le nom de la fonction à partir de la ligne de commande et je veux appeler la fonction correspondante:

func_name = parse_commandline()

fun_dict[func_name]()

Et la raison pour laquelle je veux avoir le nom de la fonction est parce que je veux créer fun_dict sans écrire deux fois le nom des fonctions, car cela semble être un bon moyen de créer des bugs. Ce que je veux faire c'est:

fun_list = [fun1, fun2, fun3] # and I'll add more as the need arises

fun_dict = {}
[fun_dict[name(t) = t for t in fun_list] # <-- this is where I need the name function

De cette façon, je n'ai besoin d'écrire qu'une seule fois les noms des fonctions.

20
Nathan Fellman

Les objets n'ont pas nécessairement de nom en python, vous ne pouvez donc pas obtenir le nom . Il n'est pas rare que les objets aient un attribut __name__ dans les cas où ils ont un nom, mais cela ne fait pas partie du python standard et la plupart des types intégrés n'en ont pas.

Lorsque vous créez une variable, comme les x, y, z ci-dessus, ces noms agissent simplement comme des "pointeurs" ou des "références" aux objets. L'objet lui-même ne sait pas quel nom vous utilisez pour cet objet et vous ne pouvez pas obtenir facilement (le cas échéant) les noms de toutes les références à cet objet.

Mise à jour: Cependant, les fonctions ont un __name__ (à moins qu'il s'agisse de lambdas). Dans ce cas, vous pouvez faire:

dict([(t.__name__, t) for t in fun_list])
26
Lennart Regebro

Ce n'est pas vraiment possible, car plusieurs variables peuvent avoir la même valeur, une valeur peut ne pas avoir de variable ou une valeur peut avoir la même valeur qu'une variable par hasard.

Si vous voulez vraiment faire ça, vous pouvez utiliser

def variable_for_value(value):
    for n,v in globals().items():
        if v == value:
            return n
    return None

Cependant, il serait préférable que vous parcouriez les noms en premier lieu:

my_list = ["x", "y", "z"] # x, y, z have been previously defined

for name in my_list:
    print "handling variable ", name
    bla = globals()[name]
    # do something to bla

10
Martin v. Löwis

Si vous souhaitez obtenir le nom des fonctions, des lambdas ou d'autres objets similaires à des fonctions définis dans l'interpréteur, vous pouvez utiliser dill.source.getname à partir de dill . Il cherche à peu près la méthode __name__, mais dans certains cas, il connaît une autre magie pour trouver le nom ... ou un nom pour l'objet. Je ne veux pas me disputer pour trouver le seul vrai nom d'un objet python, peu importe ce que cela signifie.

>>> from dill.source import getname
>>> 
>>> def add(x,y):
...   return x+y
... 
>>> squared = lambda x:x**2
>>> 
>>> print getname(add)
'add'
>>> print getname(squared)
'squared'
>>> 
>>> class Foo(object):
...   def bar(self, x):
...     return x*x+x
... 
>>> f = Foo()
>>> 
>>> print getname(f.bar)
'bar'
>>> 
>>> woohoo = squared
>>> plus = add
>>> getname(woohoo)
'squared'
>>> getname(plus)
'add'
6
Mike McKerns

Ce one-liner fonctionne pour tous les types d’objets, à condition qu’ils soient dans la règle globals() dict, qu’ils soient:

def name_of_global_obj(xx):
    return [objname for objname,oid in globals().items() if id(oid)==id(xx)][0]

ou équivalent:

    def name_of_global_obj(xx):
        for objname,oid in globals().items():
             if oid is xx:
                 return objname
4
smci

Comme d'autres l'ont mentionné, la question est vraiment délicate. Les solutions à ce problème ne sont pas des solutions uniques, même à distance. La difficulté (ou la facilité) dépendra vraiment de votre situation.

Je suis venu à ce problème à plusieurs reprises, mais plus récemment en créant une fonction de débogage. Je voulais que la fonction prenne en argument des objets inconnus et imprime leurs noms et contenus déclarés. Obtenir le contenu est facile bien sûr, mais le nom déclaré est une autre histoire.

Ce qui suit est une partie de ce que je suis venu avec.

Renvoie le nom de la fonction

Déterminer le nom d'une fonction est vraiment facile car il possède l'attribut_NAME_contenant le nom déclaré de la fonction.

name_of_function = lambda x : x.__name__

def name_of_function(arg):
    try:
        return arg.__name__
    except AttributeError:
        pass`

À titre d’exemple, si vous créez la fonction def test_function(): pass, puis copy_function = test_function, puis name_of_function(copy_function), elle renverra test_function .

Retourne le premier nom d'objet correspondant

  1. Vérifiez si l'objet a un attribut_NAME_et le renvoyer si tel est le cas (fonctions déclarées uniquement). Notez que vous pouvez supprimer ce test car le nom sera toujours dans globals().

  2. Comparez la valeur de arg avec les valeurs des éléments de globals() et renvoyez le nom de la première correspondance. Notez que je filtre les noms commençant par '_'.

Le résultat consistera en le nom du premier objet correspondant sinon Aucune.

def name_of_object(arg):
    # check __attribute (functions)
    try:
        return arg.__name__
    except AttributeError:
        pass

    for name, value in globals().items():
        if value is arg and not name.startswith('_'):
            return name

Renvoie tous les noms d'objet correspondants

  • Comparez la valeur de arg avec les valeurs des éléments de globals() et stockez les noms dans une liste. Notez que je filtre les noms commençant par '_'.

Le résultat consistera en une liste (pour plusieurs correspondances), une chaîne (pour une seule correspondance), sinon aucune. Bien sûr, vous devez ajuster ce comportement si nécessaire.

def names_of_object(arg):
    results = [n for n, v in globals().items() if v is arg and not n.startswith('_')]
    return results[0] if len(results) is 1 else results if results else None
2
Six

Voici une autre façon de penser. Supposons qu'une fonction name() renvoie le nom de son argument. Étant donné le code suivant:

def f(a):
    return a

b = "x"
c = b
d = f(c)

e = [f(b), f(c), f(d)]

Qu'est-ce que name(e[2]) devrait retourner et pourquoi?

2
Robert Rossney

Et la raison pour laquelle je veux avoir le nom de la fonction est parce que je veux créer fun_dict sans écrire deux fois le nom des fonctions, car cela semble être un bon moyen de créer des bugs.

Pour cela, vous avez une fonction merveilleuse getattr , qui vous permet d’obtenir un objet sous un nom connu. Donc vous pouvez faire par exemple:

funcs.py:

def func1(): pass
def func2(): pass

main.py:

import funcs
option = command_line_option()
getattr(funcs, option)()
1
SilentGhost

Utilisez un dict inverse.

fun_dict = {'fun1': fun1,
            'fun2': fun2,
            'fun3': fun3}

r_dict = dict(Zip(fun_dict.values(), fun_dict.keys()))

Le dict inverse inverse mappera chaque référence de fonction au nom exact que vous lui avez donné dans fun_dict, qui peut être ou non le nom que vous avez utilisé lors de la définition de la fonction. Et, cette technique se généralise à d'autres objets, y compris des entiers.

Pour plus de plaisir et de folie, vous pouvez stocker les valeurs avant et arrière dans le même dict. Je ne ferais pas cela si vous mappiez des chaînes à des chaînes, mais si vous faites quelque chose comme des références de fonction et des chaînes, ce n'est pas trop fou.

1
steveha

Notez que, comme indiqué, les objets en général ne savent pas et ne peuvent pas savoir quelles variables leur sont liées, les fonctions définies avec def ont des noms dans l'attribut __name__ (le nom utilisé dans def). De plus, si les fonctions sont définies dans le même module (comme dans votre exemple), alors globals() contiendra un sur-ensemble du dictionnaire que vous souhaitez. 

def fun1:
  pass
def fun2:
  pass
def fun3:
  pass

fun_dict = {}
for f in [fun1, fun2, fun3]:
  fun_dict[f.__name__] = f
1
Kathy Van Stone

Généralement, lorsque vous voulez faire quelque chose comme ceci, vous créez une classe pour contenir toutes ces fonctions et vous les nommez avec un préfixe clair, cmd_, ou similaire. Vous prenez ensuite la chaîne de la commande et essayez d’obtenir cet attribut de la classe avec le préfixe cmd_. Il ne vous reste plus qu'à ajouter une nouvelle fonction/méthode à la classe, et celle-ci est disponible pour vos appelants. Et vous pouvez utiliser les chaînes de documentation pour créer automatiquement le texte d'aide.

Comme décrit dans d'autres réponses, vous pourrez peut-être utiliser la même approche avec globals() et les fonctions habituelles de votre module pour correspondre plus étroitement à ce que vous avez demandé.

Quelque chose comme ça:

class Tasks:
    def cmd_doit(self):
        # do it here

func_name = parse_commandline()
try:
    func = getattr('cmd_' + func_name, Tasks())
except AttributeError:
    # bad command: exit or whatever
func()
0
retracile

J'ai parcouru cette page en me posant la même question.

Comme d'autres l'ont noté, il est assez simple de simplement saisir l'attribut __name__ d'une fonction afin de déterminer le nom de la fonction. C'est un peu plus délicat avec des objets qui n'ont pas un moyen sain de déterminer __name__, c'est-à-dire des objets de base/primitifs tels que des instances basestring, ints, long, etc.

En résumé, vous pourriez probablement utiliser le module inspect pour deviner lequel il correspond, mais vous devriez probablement savoir dans quel cadre vous travaillez/parcourez la pile pour trouver le bon. Mais je n'aimerais pas imaginer à quel point cela serait amusant d'essayer de gérer le code eval/exec'ed.

% python2 whats_my_name_again.py
needle => ''b''
['a', 'b']
[]
needle => '<function foo at 0x289d08ec>'
['c']
['foo']
needle => '<function bar at 0x289d0bfc>'
['f', 'bar']
[]
needle => '<__main__.a_class instance at 0x289d3aac>'
['e', 'd']
[]
needle => '<function bar at 0x289d0bfc>'
['f', 'bar']
[]
%

whats_my_name_again.py:

#!/usr/bin/env python

import inspect

class a_class:
    def __init__(self):
        pass

def foo():
    def bar():
        pass

    a = 'b'
    b = 'b'
    c = foo
    d = a_class()
    e = d
    f = bar

    #print('globals', inspect.stack()[0][0].f_globals)
    #print('locals', inspect.stack()[0][0].f_locals)

    assert(inspect.stack()[0][0].f_globals == globals())
    assert(inspect.stack()[0][0].f_locals == locals())

    in_a_haystack = lambda: value == needle and key != 'needle'

    for needle in (a, foo, bar, d, f, ):
        print("needle => '%r'" % (needle, ))
        print([key for key, value in locals().iteritems() if in_a_haystack()])
        print([key for key, value in globals().iteritems() if in_a_haystack()])


foo()
0
yaneurabeya

Les noms de variables peuvent être trouvés dans les dictures globals () et locals (). Mais ils ne vous donneront pas ce que vous recherchez ci-dessus. "bla" contiendra la valeur de chaque élément de my_list, pas la variable.

0
Todd

Voici ma réponse, j'utilise aussi globals (). Items ()

    def get_name_of_obj(obj, except_Word = ""):

        for name, item in globals().items():
            if item == obj and name != except_Word:
                return name

J'ai ajouté except_Word parce que je veux filtrer certains mots utilisés dans la boucle for. Si vous ne l'avez pas ajouté, le mot-clé de la boucle for peut confondre cette fonction. Parfois, le mot clé "each_item" dans le cas suivant peut apparaître dans le résultat de la fonction, en fonction de ce que vous avez fait pour votre boucle.

par exemple.

    for each_item in [objA, objB, objC]:
        get_name_of_obj(obj, "each_item")

par exemple.

    >>> objA = [1, 2, 3]
    >>> objB = ('a', {'b':'thi is B'}, 'c')
    >>> for each_item in [objA, objB]:
    ...     get_name_of_obj(each_item)
    ...
    'objA'
    'objB'
    >>>
    >>>
    >>> for each_item in [objA, objB]:
    ...     get_name_of_obj(each_item)
    ...
    'objA'
    'objB'
    >>>
    >>>
    >>> objC = [{'a1':'a2'}]
    >>>
    >>> for item in [objA, objB, objC]:
    ...     get_name_of_obj(item)
    ...
    'objA'
    'item'  <<<<<<<<<< --------- this is no good
    'item'
    >>> for item in [objA, objB]:
    ...     get_name_of_obj(item)
    ...
    'objA'
    'item'     <<<<<<<<--------this is no good
    >>>
    >>> for item in [objA, objB, objC]:
    ...     get_name_of_obj(item, "item")
    ...
    'objA'
    'objB'  <<<<<<<<<<--------- now it's ok
    'objC'
    >>>

J'espère que cela peut aider.

0
ZoomRui

Python a des noms qui sont mappés sur des objets dans une table de hachage appelée un espace de noms. À tout moment, un nom fait toujours référence à un seul objet, mais un seul objet peut être désigné par un nombre quelconque de noms. Étant donné un nom, il est très efficace pour le hashmap de rechercher le seul objet auquel ce nom fait référence. Cependant, étant donné un objet qui, comme mentionné, peut être désigné par plusieurs noms, il n’existe aucun moyen efficace de rechercher les noms qui y font référence. Ce que vous devez faire, c'est parcourir tous les noms de l'espace de noms, vérifier chacun d'eux individuellement et voir s'il correspond à votre objet. Cela peut facilement être fait avec une compréhension de liste:

[k for k,v in locals().items() if v is myobj]

Cela se traduira par une liste de chaînes contenant les noms de toutes les "variables" locales mappées à l'objet myobj.

>>> a = 1
>>> this_is_also_a = a
>>> this_is_a = a
>>> b = "ligma"
>>> c = [2,3, 534]
>>> [k for k,v in locals().items() if v is a]

['a', 'this_is_also_a', 'this_is_a']

Bien sûr, locals() peut être remplacé par toute dict pour laquelle vous souhaitez rechercher des noms qui pointent vers un objet donné. Il est évident que cette recherche peut être lente pour les très grands espaces de noms car ils doivent être parcourus dans leur intégralité. 

0
RBF06

Vous définissez une class et ajoutez la fonction privée Unicode, insérez la class comme

class example:
  def __init__(self, name):
    self.name = name

  def __unicode__(self):
    return self.name

Bien sûr, vous devez ajouter une variable supplémentaire self.name qui est le nom de l'objet.

0
Sergej Kychkn