webentwicklung-frage-antwort-db.com.de

Attribute einer Klasse abrufen

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

60
Mohamed Khamis

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;)

82
Matt Luongo
def props(cls):   
  return [i for i in cls.__dict__.keys() if i[:1] != '_']

properties = props(MyClass)
23
Doug

myfuncist 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']
17
Ben

MyClass().__class__.__dict__

Das "Recht", dies zu tun, ist jedoch über das Inspect-Modul .

6
Borealid
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('__'))]
2
JD Graham

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.

2
Henry On

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.

2
Corey Bailey

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 .

1
carmellose

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.

1
Scott Howard

Es ist einfach, nur die Instanzattribute zu erhalten.
Aber auch die class-Attribute ohne die Funktionen zu bekommen, ist etwas schwieriger.

Nur Instanzattribute

Wenn Sie nur Instanzattribute auflisten müssen, verwenden Sie einfach
for 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

Instanz- und Klassenattribute

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))

Beispiel

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.

Ergebnis für python2

$ python2 ./print_attributes.py
[class attributes]
a = 12
b = 34
[instance attributes]
c = 4
d = 2

Gleiches Ergebnis für python3

$ python3 ./print_attributes.py
[class attributes]
b = 34
a = 12
[instance attributes]
c = 4
d = 2
1
olibre

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('_')]
1
Rotareti

Sie können MyClass.__attrs__ verwenden. Es gibt nur alle Attribute dieser Klasse. Nichts mehr.

0
jimxliu

Python 2 & 3, ohne zu importieren, filtert Objekte nach ihrer Adresse

Lösungen in Kürze:

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)]

Objekte nicht filtern

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()}

Lösung in lang

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.


Versuchen Sie es selbst

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

0
Marco D.G.

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.

0
fralau

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'}
0
redscarf