web-dev-qa-db-ja.com

クラスの属性を取得する

クラスの属性を取得したい、と言う:

class MyClass():
  a = "12"
  b = "34"

  def myfunc(self):
    return self.a

MyClass.__dict__を使用すると、属性と関数、さらに__module____doc__などの関数のリストが表示されます。 MyClass().__dict__は、そのインスタンスの属性値を明示的に設定しない限り、空の辞書を提供します。

属性が欲しいだけです。上の例ではabになります。

69
Mohamed Khamis

inspect モジュールを試してください。 getmembersおよびさまざまなテストが役立つはずです。

編集:

例えば、

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

今、特別なメソッドと属性が私の神経になります-それらはいくつかの方法で処理できますが、最も簡単なのは名前に基づいてフィルタリングすることです。

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

...さらに複雑なものには、特別な属性名チェックやメタクラスを含めることができます;)

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

properties = props(MyClass)
29
Doug

myfuncisMyClassの属性。実行すると、次のようになります。

myinstance = MyClass()
myinstance.myfunc()

myinstanceという名前の属性をmyfuncという名前で探しますが、見つけられません。myinstanceMyClassのインスタンスであることがわかり、そこで検索されます。

したがって、MyClassの属性のcompleteリストは次のとおりです。

>>> dir(MyClass)
['__doc__', '__module__', 'a', 'b', 'myfunc']

(クラスのメンバーをリストするための迅速かつ簡単な方法としてdirを使用していることに注意してください:運用コードではなく探索的方法でのみ使用する必要があります)

特定の属性のみが必要な場合は、__doc____module__、およびmyfuncは属性ではないため、何らかの条件を使用してこのリストをフィルターする必要があります。 aおよびbとまったく同じ方法で。

MattとBorealidによって参照される検査モジュールを使用したことはありませんが、簡単なリンクからは、これを行うのに役立つテストがあるように見えますが、あなたが望むように見えるので、独自の述語関数を書く必要がありますおおよそ、しない属性はisroutineテストに合格し、2つのアンダースコアで開始および終了しない属性です。

また、注意:Python 2.7でclass MyClass():を使用することにより、非常に古い古いスタイルのクラスを使用していることになります。非常に古いライブラリとの互換性のために意図的にそうしているのでない限り、代わりにクラスをclass MyClass(object):として定義する必要があります。 Python 3には「古いスタイル」のクラスはなく、この動作がデフォルトです。ただし、newstyleクラスを使用すると、lotより自動的に定義された属性が得られます。

>>> 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']
19
Ben

MyClass().__class__.__dict__

ただし、これを行うための「正しい」方法は inspect module です。

6
Borealid

インスタンス属性のみを取得するのは簡単です。
しかし、関数なしでclass属性も取得するのは少し注意が必要です。

インスタンス属性のみ

リストインスタンス属性のみが必要な場合は、
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

インスタンスとクラスの属性

関数なしでclass属性も取得するには、 callable() を使用するのがコツです。

しかし 静的メソッド常にcallableとは限りません

したがって、callable(value)を使用する代わりに
callablegetattrMyClass, 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()

注:print_class_attributes()@staticmethod である必要があります
しかし、この愚かで単純な例ではありません。

python2 の結果

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

python と同じ結果

$ python3 ./print_attributes.py
[class attributes]
b = 34
a = 12
[instance attributes]
c = 4
d = 2
4
olibre
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('__'))]

次のようなMyClassのインスタンスの場合

mc = MyClass()

リスト内包表記のMyClassの代わりにtype(mc)を使用します。ただし、mc.c = "42"などのmcに属性を動的に追加する場合、この戦略でtype(mc)を使用すると属性は表示されません。元のクラスの属性のみを提供します。

クラスインスタンスの完全な辞書を取得するには、type(mc).__dict__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('__'))]
2
JD Graham

今までに似たようなことが行われたかどうかはわかりませんが、vars()を使用してNice属性検索関数を作成しました。 vars()は、通過するクラスの属性の辞書を作成します。

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

Pythonで非常に大規模なText Adventureを開発しています。これまでのPlayerクラスには100を超える属性があります。これを使用して、必要な特定の属性を検索します。

2
Corey Bailey

これは検査せずに行うことができると思います。

次のクラスを受講してください。

 class Test:
   a = 1
   b = 2

   def __init__(self):
     self.c = 42

   @staticmethod
   def toto():
     return "toto"

   def test(self):
     return "test"

メンバーとそのタイプを見る:

t = Test()
l = [ (x, eval('type(x.%s).__name__' % x)) for x in dir(a) ]

...与えるもの:

[('__doc__', 'NoneType'),
 ('__init__', 'instancemethod'),
 ('__module__', 'str'),
 ('a', 'int'),
 ('b', 'int'),
 ('c', 'int'),
 ('test', 'instancemethod'),
 ('toto', 'function')]

したがって、変数のみを出力するには、結果をタイプ、および「__」で始まらない名前でフィルタリングする必要があります。例えば。

filter(lambda x: x[1] not in ['instancemethod', 'function'] and not x[0].startswith('__'), l)

[('a', 'int'), ('b', 'int'), ('c', 'int')] # actual result

それでおしまい。

注:Python 3を使用している場合、イテレータをリストに変換します。

より堅牢な方法が必要な場合は、 inspect を使用します。

1
carmellose

クラスのすべての属性(メソッドではない)を取得するための私のソリューション(クラスに、属性が明確に記述された適切に記述されたdocstringがある場合):

def get_class_attrs(cls):
    return re.findall(r'\w+(?=[,\)])', cls.__dict__['__doc__'])

この部分cls.__dict__['__doc__']は、クラスのdocstringを抽出します。

1
Henry On

私は最近、この質問に似た何かを理解する必要があったので、将来同じものに直面している他の人に役立つかもしれない背景情報を投稿したいと思いました。

Python( https://docs.python.org/3.5/reference/datamodel.html#the-standard-type-hierarchy から)での動作は次のとおりです。

MyClassはクラスオブジェクト、MyClass()はクラスオブジェクトのインスタンスです。インスタンスの__dict__は、そのインスタンスに固有の属性とメソッドのみを保持します(例:self.somethings)。属性またはメソッドがクラスの一部である場合、それはクラスの__dict__にあります。 MyClass().__dict__を実行すると、MyClassのインスタンスが作成され、クラス属性以外に属性やメソッドが作成されないため、空の__dict__

したがって、print(MyClass().b)と言うと、Pythonは最初に新しいインスタンスの辞書MyClass().__dict__['b']をチェックし、bを見つけられません。次に、クラスMyClass.__dict__['b']をチェックし、bを見つけます。

そのため、同じ検索プロセスをエミュレートするには、inspectモジュールが必要です。

1
Scott Howard

リスト内包表記dir()を使用して、属性名を取得できます。

names = [p for p in dir(myobj) if not p.startswith('_')]

getattr()を使用して、属性自体を取得します。

attrs = [getattr(myobj, p) for p in dir(myobj) if not p.startswith('_')]
1
Rotareti

MyClass.__attrs__を使用できます。そのクラスのすべての属性を提供するだけです。これ以上何もない。

0
jimxliu

Python 2および3、インポートなしで、アドレスでオブジェクトをフィルタリング

要するにソリューション:

Returndict {attribute_name:attribute_value}、フィルタリングされたオブジェクト。すなわち{'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)}

Returnlist [attribute_names]、フィルタリングされたオブジェクト。すなわち['a', 'b', 'c', 'd']

[k for k, val in self.__dict__.items() if not str(hex(id(val))) in str(val)]

Returnlist [attribute_values]、フィルタリングされたオブジェクト。すなわち[1, (2, 2), [3, 3], {4: 4}]

[val for k, val in self.__dict__.items() if not str(hex(id(val))) in str(val)]

オブジェクトをフィルタリングしない

if条件を削除します。 {'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()}

長い解決策

__repr__のデフォルト実装がオーバーライドされない限りifステートメントは、16進数の場合Trueを返します。 valのメモリ内の場所の表現は、__repr__戻り文字列にあります。

__repr__のデフォルトの実装に関しては、有用な この回答 を見つけることができます。要するに:

def __repr__(self):
    return '<{0}.{1} object at {2}>'.format(
      self.__module__, type(self).__name__, hex(id(self)))

Wichは次のような文字列を返します。

<__main__.Bar object at 0x7f3373be5998>

各要素のメモリ内の場所は、id()メソッドを介して取得されます。

Python Docs はid()について述べています:

オブジェクトの「アイデンティティ」を返します。これは、このオブジェクトの存続期間中に一意で一定であることが保証されている整数です。オーバーラップしないライフタイムを持つ2つのオブジェクトは、同じid()値を持つ場合があります。

CPython実装の詳細:これは、メモリ内のオブジェクトのアドレスです。


自分で試してみてください

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

出力:

{'a': 1, 'c': [3, 3], 'b': (2, 2), 'd': {4: 4}}

  • Python 2.7.13およびPython 3.5.3でテスト済み

  • Python 2.x .iteritems().items()よりも優先されます

0
Marco D.G.

非常に簡単な答えがあります。これは明らかなはずです: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>

Python 2.7とPython 3.xの両方でうまく機能します。

これらのアイテムのリストが必要な場合は、検査を使用する必要があります。

0
fralau

2つの機能:

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

つかいます:

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