Je veux obtenir les attributs d'une classe, disons:
class MyClass():
a = "12"
b = "34"
def myfunc(self):
return self.a
utiliser MyClass.__dict__
me donne une liste d'attributs et de fonctions, et même des fonctions telles que __module__
et __doc__
. Alors que MyClass().__dict__
me donne un dict vide, à moins que je ne définisse explicitement une valeur d'attribut de cette instance.
Je veux juste les attributs, dans l'exemple ci-dessus, ceux-ci seraient: a
et b
Essayez le module inspect . getmembers
et les divers tests devraient être utiles.
MODIFIER:
Par exemple,
class MyClass(object):
a = '12'
b = '34'
def myfunc(self):
return self.a
>>> import inspect
>>> inspect.getmembers(MyClass, lambda a:not(inspect.isroutine(a)))
[('__class__', type),
('__dict__',
<dictproxy {'__dict__': <attribute '__dict__' of 'MyClass' objects>,
'__doc__': None,
'__module__': '__main__',
'__weakref__': <attribute '__weakref__' of 'MyClass' objects>,
'a': '34',
'b': '12',
'myfunc': <function __main__.myfunc>}>),
('__doc__', None),
('__module__', '__main__'),
('__weakref__', <attribute '__weakref__' of 'MyClass' objects>),
('a', '34'),
('b', '12')]
Maintenant, les méthodes et les attributs spéciaux m'énervent - ceux-ci peuvent être traités de différentes manières, la plus simple étant de filtrer par nom.
>>> attributes = inspect.getmembers(MyClass, lambda a:not(inspect.isroutine(a)))
>>> [a for a in attributes if not(a[0].startswith('__') and a[0].endswith('__'))]
[('a', '34'), ('b', '12')]
... et les plus complexes pouvant inclure des vérifications spéciales du nom d'attribut ou même des métaclasses;)
def props(cls):
return [i for i in cls.__dict__.keys() if i[:1] != '_']
properties = props(MyClass)
myfunc
is un attribut de MyClass
. C'est comme ça qu'on le trouve quand on court:
myinstance = MyClass()
myinstance.myfunc()
Il cherche un attribut sur myinstance
nommé myfunc
, n'en trouve pas, voit que myinstance
est une instance de MyClass
et le recherche à cet endroit.
La liste d'attributs complete pour MyClass
est donc:
>>> dir(MyClass)
['__doc__', '__module__', 'a', 'b', 'myfunc']
(Notez que j'utilise dir juste comme moyen rapide et facile de lister les membres de la classe: il ne devrait être utilisé que de manière exploratoire, pas dans le code de production)
Si vous ne voulez que des attributs particuliers, vous devrez filtrer cette liste à l'aide de certains critères, car __doc__
, __module__
et myfunc
ne sont aucunement spéciaux, ils sont exactement comme les attributs a
et b
.
Je n'ai jamais utilisé le module inspect évoqué par Matt et Borealid, mais d'après un bref lien, il semble contenir des tests pour vous aider à faire cela, mais vous devrez écrire votre propre fonction de prédicat, car il semble que ce que vous voulez. est à peu près les attributs qui not ne réussissent pas le test isroutine
et ne commencent pas et se terminent par deux traits de soulignement.
Remarque: en utilisant class MyClass():
dans Python 2.7, vous utilisez des classes obsolètes et obsolètes. À moins que vous ne le fassiez délibérément pour assurer la compatibilité avec des bibliothèques extrêmement anciennes, définissez plutôt votre classe comme class MyClass(object):
. En Python 3, il n'y a pas de classes "à l'ancienne", et ce comportement est le comportement par défaut. Cependant, en utilisant les classes newstyle, vous obtiendrez un lot attributs plus automatiquement définis:
>>> class MyClass(object):
a = "12"
b = "34"
def myfunc(self):
return self.a
>>> dir(MyClass)
['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'a', 'b', 'myfunc']
MyClass().__class__.__dict__
Cependant, le "droit" était de le faire via le module d'inspection .
import re
class MyClass:
a = "12"
b = "34"
def myfunc(self):
return self.a
attributes = [a for a, v in MyClass.__dict__.items()
if not re.match('<function.*?>', str(v))
and not (a.startswith('__') and a.endswith('__'))]
Pour une instance de MyClass, telle que
mc = MyClass()
utilisez type(mc)
au lieu de MyClass
dans la liste de compréhension. Cependant, si on ajoute dynamiquement un attribut à mc
, tel que mc.c = "42"
, l'attribut n'apparaîtra pas lors de l'utilisation de type(mc)
dans cette stratégie. Il ne donne que les attributs de la classe d'origine.
Pour obtenir le dictionnaire complet pour une instance de classe, vous devez COMBINER les dictionnaires de type(mc).__dict__
et mc.__dict__
.
mc = MyClass()
mc.c = "42"
# Python 3.5
combined_dict = {**type(mc).__dict__, **mc.__dict__}
# Or Python < 3.5
def dict_union(d1, d2):
z = d1.copy()
z.update(d2)
return z
combined_dict = dict_union(type(mc).__dict__, mc.__dict__)
attributes = [a for a, v in combined_dict.items()
if not re.match('<function.*?>', str(v))
and not (a.startswith('__') and a.endswith('__'))]
Ma solution pour obtenir tous les attributs (pas les méthodes) d'une classe (si la classe a une docstring correctement écrite qui a les attributs clairement énoncés):
def get_class_attrs(cls):
return re.findall(r'\w+(?=[,\)])', cls.__dict__['__doc__'])
Cette pièce cls.__dict__['__doc__']
extrait la docstring de la classe.
Je ne sais pas si quelque chose de similaire a été fait à ce jour ou non, mais j'ai créé une fonction de recherche d'attribut Nice avec vars (). vars () crée un dictionnaire des attributs d'une classe que vous traversez.
class Player():
def __init__(self):
self.name = 'Bob'
self.age = 36
self.gender = 'Male'
s = vars(Player())
#From this point if you want to print all the attributes, just do print(s)
#If the class has a lot of attributes and you want to be able to pick 1 to see
#run this function
def play():
ask = input("What Attribute?>: ")
for key, value in s.items():
if key == ask:
print("self.{} = {}".format(key, value))
break
else:
print("Couldn't find an attribute for self.{}".format(ask))
Je développe une aventure de texte assez massive en Python, ma classe de joueurs compte jusqu'à présent plus de 100 attributs. J'utilise ceci pour rechercher des attributs spécifiques que je dois voir.
Cela peut être fait sans inspecter, je suppose.
Prenez le cours suivant:
class Test:
a = 1
b = 2
def __init__(self):
self.c = 42
@staticmethod
def toto():
return "toto"
def test(self):
return "test"
En regardant les membres avec leurs types:
t = Test()
l = [ (x, eval('type(x.%s).__name__' % x)) for x in dir(a) ]
... donne:
[('__doc__', 'NoneType'),
('__init__', 'instancemethod'),
('__module__', 'str'),
('a', 'int'),
('b', 'int'),
('c', 'int'),
('test', 'instancemethod'),
('toto', 'function')]
Donc, pour ne produire que les variables, il vous suffit de filtrer les résultats par type et par noms ne commençant pas par '__'. Par exemple.
filter(lambda x: x[1] not in ['instancemethod', 'function'] and not x[0].startswith('__'), l)
[('a', 'int'), ('b', 'int'), ('c', 'int')] # actual result
C'est tout.
Remarque: si vous utilisez Python 3, convertissez les itérateurs en listes.
Si vous voulez un moyen plus robuste de le faire, utilisez inspect .
J'ai récemment eu besoin de trouver quelque chose de similaire à cette question, alors je voulais poster des informations de fond qui pourraient être utiles aux personnes confrontées aux mêmes problèmes à l'avenir.
Voici comment cela fonctionne en Python (from https://docs.python.org/3.5/reference/datamodel.html#the-standard-type-hierarchy ):
MyClass
est un objet de classe, MyClass()
est une instance de l'objet de classe. __dict__
d'une instance ne contient que des attributs et des méthodes spécifiques à cette instance (par exemple, self.somethings
). Si un attribut ou une méthode fait partie d'une classe, il se trouve dans le __dict__
de la classe. Lorsque vous faites MyClass().__dict__
, une instance de MyClass
est créée sans aucun attribut ni méthode à part les attributs de classe, ainsi le __dict__
vide
Donc, si vous dites print(MyClass().b)
, Python commence par vérifier la fonction dict MyClass().__dict__['b']
de la nouvelle instance et ne trouve pas b
. Il vérifie ensuite la classe MyClass.__dict__['b']
et trouve b
.
C'est pourquoi vous avez besoin du module inspect
pour émuler le même processus de recherche.
Obtenir uniquement les attributs instance est facile.
Mais obtenir aussi les attributs class sans les fonctions est un peu plus compliqué.
Si vous devez seulement lister les attributs instance, utilisez simplementfor attribute, value in my_instance
. __dict__
.items()
>>> from __future__ import (absolute_import, division, print_function)
>>> class MyClass(object):
... def __init__(self):
... self.a = 2
... self.b = 3
... def print_instance_attributes(self):
... for attribute, value in self.__dict__.items():
... print(attribute, '=', value)
...
>>> my_instance = MyClass()
>>> my_instance.print_instance_attributes()
a = 2
b = 3
>>> for attribute, value in my_instance.__dict__.items():
... print(attribute, '=', value)
...
a = 2
b = 3
Pour obtenir également les attributs class sans les fonctions, l'astuce consiste à utiliser callable()
.
Mais méthodes statiques sont pas toujours callable
!
Par conséquent, au lieu d'utiliser callable(value)
, utilisezcallable
( getattr
(MyClass, attribute))
from __future__ import (absolute_import, division, print_function)
class MyClass(object):
a = "12"
b = "34" # class attributes
def __init__(self, c, d):
self.c = c
self.d = d # instance attributes
@staticmethod
def mystatic(): # static method
return MyClass.b
def myfunc(self): # non-static method
return self.a
def print_instance_attributes(self):
print('[instance attributes]')
for attribute, value in self.__dict__.items():
print(attribute, '=', value)
def print_class_attributes(self):
print('[class attributes]')
for attribute in MyClass.__dict__.keys():
if attribute[:2] != '__':
value = getattr(MyClass, attribute)
if not callable(value):
print(attribute, '=', value)
v = MyClass(4,2)
v.print_class_attributes()
v.print_instance_attributes()
Remarque:print_class_attributes()
devrait être @staticmethod
mais pas dans cet stupide et simple exemple.
$ python2 ./print_attributes.py
[class attributes]
a = 12
b = 34
[instance attributes]
c = 4
d = 2
$ python3 ./print_attributes.py
[class attributes]
b = 34
a = 12
[instance attributes]
c = 4
d = 2
Vous pouvez utiliser dir()
dans un compréhension de la liste pour obtenir les noms d'attribut:
names = [p for p in dir(myobj) if not p.startswith('_')]
Utilisez getattr()
pour obtenir les attributs eux-mêmes:
attrs = [getattr(myobj, p) for p in dir(myobj) if not p.startswith('_')]
Vous pouvez utiliser MyClass.__attrs__
. Cela donne juste tous les attributs de cette classe. Rien de plus.
Retourner dict {nom_attribut: valeur_attribut} , objets filtrés. i.e {'a': 1, 'b': (2, 2), 'c': [3, 3]}
{k: val for k, val in self.__dict__.items() if not str(hex(id(val))) in str(val)}
Retour list [noms_attributs] , objets filtrés. c'est-à-dire ['a', 'b', 'c', 'd']
[k for k, val in self.__dict__.items() if not str(hex(id(val))) in str(val)]
Retour list [valeurs_attributs] , objets filtrés. i.e [1, (2, 2), [3, 3], {4: 4}]
[val for k, val in self.__dict__.items() if not str(hex(id(val))) in str(val)]
Suppression de la condition if
. Retourne {'a': 1, 'c': [3, 3], 'b': (2, 2), 'e': <function <lambda> at 0x7fc8a870fd70>, 'd': {4: 4}, 'f': <object object at 0x7fc8abe130e0>}
{k: val for k, val in self.__dict__.items()}
Tant que l'implémentation par défaut de __repr__
n'est pas remplacée , l'instruction if
renverra True
si l'hexadécimal La représentation de l'emplacement en mémoire de val
est dans la chaîne de retour __repr__
.
En ce qui concerne l'implémentation par défaut de __repr__
, vous pourriez trouver utile cette réponse . En bref:
def __repr__(self):
return '<{0}.{1} object at {2}>'.format(
self.__module__, type(self).__name__, hex(id(self)))
Ce qui retourne une chaîne comme:
<__main__.Bar object at 0x7f3373be5998>
L'emplacement en mémoire de chaque élément est obtenu via la méthode id()
.
Python Docs dit à propos de id ():
Renvoie "l'identité" d'un objet. C'est un entier qui est garanti d'être unique et constant pour cet objet tout au long de sa vie. Deux objets dont la durée de vie ne se chevauchent pas peuvent avoir la même valeur id ().
Détail d'implémentation CPython: C'est l'adresse de l'objet en mémoire.
class Bar:
def __init__(self):
self.a = 1
self.b = (2, 2)
self.c = [3, 3]
self.d = {4: 4}
self.e = lambda: "5"
self.f = object()
#__str__ or __repr__ as you prefer
def __str__(self):
return "{}".format(
# Solution in Short Number 1
{k: val for k, val in self.__dict__.items() if not str(hex(id(val))) in str(val)}
)
# Main
print(Bar())
Sortie:
{'a': 1, 'c': [3, 3], 'b': (2, 2), 'd': {4: 4}}
Remarque :
Testé avec Python 2.7.13
et Python 3.5.3
Dans Python 2.x .iteritems()
est préférable à .items()
Il y a une réponse très simple , cela devrait être évident: getattr
class MyClass(object):
a = '12'
b = '34'
def myfunc(self):
return self.a
>>> getattr(MyClass, 'a')
'12'
>>> getattr(MyClass, 'myfunc')
<function MyClass.myfunc at 0x10de45378>
Cela fonctionne bien à la fois en Python 2.7 et en Python 3.x.
Si vous voulez une liste de ces éléments, vous devrez toujours utiliser inspecter.
deux fonctions:
def get_class_attr(Cls) -> []:
import re
return [a for a, v in Cls.__dict__.items()
if not re.match('<function.*?>', str(v))
and not (a.startswith('__') and a.endswith('__'))]
def get_class_attr_val(cls):
attr = get_class_attr(type(cls))
attr_dict = {}
for a in attr:
attr_dict[a] = getattr(cls, a)
return attr_dict
utilisation:
>>> class MyClass:
a = "12"
b = "34"
def myfunc(self):
return self.a
>>> m = MyClass()
>>> get_class_attr_val(m)
{'a': '12', 'b': '34'}