Ich möchte die Attribute einer Klasse erhalten, sagen Sie:
class MyClass():
a = "12"
b = "34"
def myfunc(self):
return self.a
mit MyClass.__dict__
erhalten Sie eine Liste mit Attributen und Funktionen und sogar Funktionen wie __module__
und __doc__
. Während MyClass().__dict__
mir ein leeres Dikt gibt, wenn ich nicht explizit einen Attributwert dieser Instanz setze.
Ich möchte nur die Attribute, im obigen Beispiel wären dies: a
und b
Probieren Sie das Modul inspect aus. getmembers
und die verschiedenen Tests sollten hilfreich sein.
BEARBEITEN:
Zum Beispiel,
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')]
Nun gehen mir die speziellen Methoden und Attribute auf die Nerven - diese können auf verschiedene Weise behandelt werden, wobei die einfachste Methode darin besteht, nach Namen zu filtern.
>>> 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')]
... und die kompliziertere davon kann spezielle Attribut-Namensprüfungen oder sogar Metaklassen umfassen;)
def props(cls):
return [i for i in cls.__dict__.keys() if i[:1] != '_']
properties = props(MyClass)
myfunc
ist ein Attribut von MyClass
. So wurde es gefunden, wenn du rennst:
myinstance = MyClass()
myinstance.myfunc()
Es sucht nach einem Attribut auf myinstance
mit dem Namen myfunc
, findet kein Attribut, erkennt, dass myinstance
eine Instanz von MyClass
ist, und sucht dort nach.
Die complete Liste der Attribute für MyClass
lautet also:
>>> dir(MyClass)
['__doc__', '__module__', 'a', 'b', 'myfunc']
(Beachten Sie, dass ich dir nur als schnellen und einfachen Weg benutze, um die Mitglieder der Klasse aufzulisten: Es sollte nur explorativ verwendet werden, nicht im Produktionscode.)
Wenn Sie nur bestimmte Attribute wünschen, müssen Sie diese Liste anhand einiger Kriterien filtern, da __doc__
, __module__
und myfunc
in keiner Weise speziell sind. Sie sind Attribute auf dieselbe Weise wie a
und b
.
Ich habe das von Matt und Borealid erwähnte Inspect-Modul nie verwendet, aber von einem kurzen Link aus sieht es so aus, als hätte es Tests, die Ihnen dabei helfen, aber Sie müssen Ihre eigene Prädikatsfunktion schreiben, da es scheint, was Sie wollen In etwa sind die Attribute, die nicht den isroutine
-Test bestehen und nicht mit zwei Unterstrichen beginnen und enden.
Beachten Sie auch: Wenn Sie class MyClass():
in Python 2.7 verwenden, verwenden Sie die veralteten Old-Class-Klassen. Wenn Sie dies nicht aus Gründen der Kompatibilität mit extrem alten Bibliotheken tun, sollten Sie stattdessen Ihre Klasse als class MyClass(object):
definieren. In Python 3 gibt es keine Klassen "im alten Stil". Dieses Verhalten ist der Standard. Wenn Sie jedoch Newstyle-Klassen verwenden, erhalten Sie lot mehr automatisch definierte Attribute:
>>> 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__
Das "Recht", dies zu tun, ist jedoch über das Inspect-Modul .
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('__'))]
Für eine Instanz von MyClass wie z
mc = MyClass()
verwenden Sie type(mc)
anstelle von MyClass
im Listenverständnis. Wenn Sie jedoch dynamisch ein Attribut zu mc
hinzufügen, wie z. B. mc.c = "42"
, wird das Attribut nicht angezeigt, wenn Sie type(mc)
in dieser Strategie verwenden. Sie gibt nur die Attribute der ursprünglichen Klasse an.
Um das vollständige Wörterbuch für eine Klasseninstanz zu erhalten, müssen Sie die Wörterbücher von type(mc).__dict__
und mc.__dict__
KOMBINIEREN.
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('__'))]
Meine Lösung zum Abrufen aller Attribute (nicht Methoden) einer Klasse (wenn die Klasse über einen ordnungsgemäß geschriebenen Docstring verfügt, dessen Attribute eindeutig angegeben sind)
def get_class_attrs(cls):
return re.findall(r'\w+(?=[,\)])', cls.__dict__['__doc__'])
Dieses Stück cls.__dict__['__doc__']
extrahiert den Docstring der Klasse.
Ich weiß nicht, ob inzwischen etwas Ähnliches gemacht wurde oder nicht, aber ich habe mit Nars () eine Attributsuchfunktion erstellt. vars () erstellt ein Wörterbuch mit den Attributen einer Klasse, die Sie durchlaufen.
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))
Ich entwickle ein ziemlich umfangreiches Textabenteuer in Python, meine Player-Klasse hat bisher über 100 Attribute. Ich suche hier nach bestimmten Attributen, die ich sehen muss.
Ich denke, das kann ohne Inspektion gemacht werden.
Nehmen Sie an der folgenden Klasse teil:
class Test:
a = 1
b = 2
def __init__(self):
self.c = 42
@staticmethod
def toto():
return "toto"
def test(self):
return "test"
Betrachtet man die Mitglieder zusammen mit ihren Typen:
t = Test()
l = [ (x, eval('type(x.%s).__name__' % x)) for x in dir(a) ]
... gibt:
[('__doc__', 'NoneType'),
('__init__', 'instancemethod'),
('__module__', 'str'),
('a', 'int'),
('b', 'int'),
('c', 'int'),
('test', 'instancemethod'),
('toto', 'function')]
Um nur die Variablen auszugeben, müssen Sie lediglich die Ergebnisse nach Typ und Namen filtern, die nicht mit '__' beginnen. Z.B.
filter(lambda x: x[1] not in ['instancemethod', 'function'] and not x[0].startswith('__'), l)
[('a', 'int'), ('b', 'int'), ('c', 'int')] # actual result
Das ist es.
Hinweis: Wenn Sie Python 3 verwenden, konvertieren Sie die Iteratoren in Listen.
Wenn Sie eine robustere Methode möchten, verwenden Sie inspect .
Ich musste vor kurzem etwas Ähnliches zu dieser Frage herausfinden, also wollte ich Hintergrundinformationen posten, die für andere hilfreich sein könnten, die sich in der Zukunft mit diesem Problem befassen.
So funktioniert es in Python (von https://docs.python.org/3.5/reference/datamodel.html#the-standard-type-hierarchy ):
MyClass
ist ein Klassenobjekt, MyClass()
ist eine Instanz des Klassenobjekts. __dict__
einer Instanz enthält nur für diese Instanz spezifische Attribute und Methoden (z. B. self.somethings
). Wenn ein Attribut oder eine Methode Teil einer Klasse ist, ist sie im __dict__
der Klasse enthalten. Wenn Sie MyClass().__dict__
ausführen, wird neben den Klassenattributen eine Instanz von MyClass
ohne Attribute oder Methoden erstellt. Daher ist der leere __dict__
Wenn Sie also print(MyClass().b)
sagen, überprüft Python zuerst das Diktat MyClass().__dict__['b']
der neuen Instanz und kann b
nicht finden. Dann prüft es die Klasse MyClass.__dict__['b']
und findet b
.
Deshalb benötigen Sie das Modul inspect
, um denselben Suchprozess zu emulieren.
Es ist einfach, nur die Instanzattribute zu erhalten.
Aber auch die class-Attribute ohne die Funktionen zu bekommen, ist etwas schwieriger.
Wenn Sie nur Instanzattribute auflisten müssen, verwenden Sie einfachfor 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
Um auch die class-Attribute ohne Funktionen zu erhalten, ist der Trick die Verwendung von callable()
.
Aber statische Methoden sind nicht immer callable
!
Verwenden Sie daher anstelle von callable(value)
callable
( 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()
Hinweis:print_class_attributes()
sollte @staticmethod
sein.
aber nicht in diesem dumm und einfach Beispiel.
$ 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
Sie können dir()
in einem List-Verständnis verwenden, um die Attributnamen zu erhalten:
names = [p for p in dir(myobj) if not p.startswith('_')]
Verwenden Sie getattr()
, um die Attribute selbst zu erhalten:
attrs = [getattr(myobj, p) for p in dir(myobj) if not p.startswith('_')]
Sie können MyClass.__attrs__
verwenden. Es gibt nur alle Attribute dieser Klasse. Nichts mehr.
Return dict {attribute_name: attribute_value} , Objekte gefiltert. das heißt {'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)}
Rückgabe Liste [attribute_names] , Objekte gefiltert. das heißt ['a', 'b', 'c', 'd']
[k for k, val in self.__dict__.items() if not str(hex(id(val))) in str(val)]
Rückgabe Liste [attribute_values] , Objekte gefiltert. das heißt [1, (2, 2), [3, 3], {4: 4}]
[val for k, val in self.__dict__.items() if not str(hex(id(val))) in str(val)]
Entfernen der Bedingung if
. Return {'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()}
Solange die Standardimplementierung von __repr__
nicht überschrieben wird , gibt die if
-Anweisung True
zurück, wenn sie hexadezimal ist Die Darstellung der Position im Speicher von val
befindet sich in der __repr__
-Rückgabezeichenfolge.
Bezüglich der Standardimplementierung von __repr__
könnten Sie nützlich sein diese Antwort . Zusamenfassend:
def __repr__(self):
return '<{0}.{1} object at {2}>'.format(
self.__module__, type(self).__name__, hex(id(self)))
Wich gibt einen String zurück wie:
<__main__.Bar object at 0x7f3373be5998>
Die Position im Speicher jedes Elements wird über die Methode id()
ermittelt.
Python Docs sagt über id ():
Gibt die "Identität" eines Objekts zurück. Dies ist eine Ganzzahl, die für dieses Objekt während seiner Lebensdauer garantiert eindeutig und konstant ist. Zwei Objekte mit nicht überlappenden Lebensdauern können denselben id () - Wert haben.
CPython-Implementierungsdetail: Dies ist die Adresse des Objekts im Speicher.
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())
Ausgabe:
{'a': 1, 'c': [3, 3], 'b': (2, 2), 'd': {4: 4}}
Hinweis :
Getestet mit Python 2.7.13
und Python 3.5.3
In Python 2.x wird .iteritems()
gegenüber .items()
bevorzugt
Es gibt eine sehr einfache Antwort , die offensichtlich sein sollte: 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>
Es funktioniert sowohl in Python 2.7 als auch in Python 3.x einwandfrei.
Wenn Sie eine Liste dieser Elemente wünschen, müssen Sie dennoch inspect verwenden.
zwei funktion:
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
benutzen:
>>> class MyClass:
a = "12"
b = "34"
def myfunc(self):
return self.a
>>> m = MyClass()
>>> get_class_attr_val(m)
{'a': '12', 'b': '34'}