クラスの属性を取得する


106

クラスの属性を取得したいのですが、

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

  def myfunc(self):
    return self.a

使用してMyClass.__dict__私のような属性や機能、さらには機能のリストを与える__module____doc__。While MyClass().__dict__は、そのインスタンスの属性値を明示的に設定しない限り、空の辞書を与えます。

私は属性が欲しいだけです、上の例では次のようになります:aそしてb


回答:


123

検査モジュールを試してください。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')]

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


うん、これは素晴らしい!私はこれを使用しました: attributes = inspect.getmembers(MyClass, lambda a:not(inspect.isroutine(a))) print [a[0] for a in attributes if '_' not in a[0]]
Mohamed Khamis 2012年

2
属性は含まれませんのでご注意くださいlike_this!また、意図的に行った「プライベート」属性も回避されます。
Matt Luongo 2012年

式の中で:こんにちは、私はあまりにもわずか明確化とそれを愛しinspect.getmembers(MyClass, ...MyClassクラスやオブジェクトに置き換えることができ、そして、あなたのオブジェクトの値のリストが必要な場合は、交換する必要がありMyClass、あなたのオブジェクト変数によって(あるいはselfあなたが置く場合def __repr__()私のような方法でのこの表現)。
herve-guerin 2017

これを(Python3で)使用して、 ' dict '値を探す関数を取得しましたi = inspect.getmembers(MyClass, lambda a:not(inspect.isroutine(a))); z = [_[1] for _ in i if _[0] in '__dict__'][0]。それから、zからキーを取得するだけです。
double0darbo

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

properties = props(MyClass)

7
これにはメソッド名が含まれます
lenhhoxung

10
チェックするより明確if not i.startswith('_')ではありif i[:1] != '_'ません:の代わりに?
Mikaelblomkvistsson 2017年

2
注:子クラス(継承)について話す場合.__dict__.keys()、親の属性は含まれません。
vishes_shell 2018

21

myfunc の属性MyClass。実行すると、次のように表示されます。

myinstance = MyClass()
myinstance.myfunc()

それはmyinstancenamedの属性を探しますが、それをmyfunc見つけられず、それmyinstanceがのインスタンスであることがわかり、MyClassそこで調べます。

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

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

(クラスのメンバーを一覧表示するための迅速かつ簡単な方法としてだけdirを使用していることに注意してください:プロダクションコードではなく、探索的な方法でのみ使用する必要があります)

あなたが唯一の特定の属性をしたい場合は、いくつかの基準を使用して、このリストをフィルタリングする必要がありますので__doc____module__、とmyfuncすることをまったく同じように、彼らしている属性は、どのような方法で特別ではないabしています。

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

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

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

6
一つは、に依存することはできませんdir(): " DIR()は、主にインタラクティブプロンプトで使用するための便宜として提供されるので、それはより多くの、それが名前の厳密または一貫して定義されたセットを提供しようとするよりも名前の興味深いセットを供給しようとすると、その詳細動作はリリース間変更される可能性があり」(参照のマニュアルを参照してdir())。
Tadeck 2012年

@タデック:良い点。私はそれをソリューションとして提案するのではなく、例示的に使用していました。それは、属性の参照に基づいて属性をフィルターすることが簡単にできないためです。しかし、私はそれについてもっと明確にすべきです。
Ben

14

インスタンス属性のみを取得するのは簡単です。
しかし、関数なしでクラス属性を取得することは、もう少しトリッキーです。

インスタンス属性のみ

インスタンス属性のみをリストする必要がある場合は、を使用してください
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

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

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

しかし、静的メソッド常にでcallableはありません

したがって、callable(value)use
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 self.__dict__.keys():
       if attribute[:2] != '__':
         value = getattr(self, 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 ./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

8

MyClass().__class__.__dict__

ただし、これを行うには「検査モジュール」を使用するのが「適切」でした。


6
MyClass().__class__.__dict__==MyClass.__dict__
ヤク

5
@yakのコメントは正確ではありません。クラス属性とインスタンス属性の違いについては、以下を参照してください。stackoverflow.com/questions/35805/…を参照してください。
sholsapp 2015

@sholsappは実際には@yakが正しいです。あなたが提供されるリンクはそれを言うMyClass().__class__.__dict__ != MyClass().__dict__が、ヤクは/彼が正しいsはその場合には、右辺の括弧を含めていません
シャディ・

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

リスト内包表記のtype(mc)代わりに使用しMyClassます。ただし、mcなどの属性を動的にに追加mc.c = "42"した場合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('__'))]

本当にきちんとしたソリューション。
Gitnik 2017

2

似たようなものが今までに作成されたかどうかはわかりませんが、vars()を使用して素晴らしい属性検索関数を作成しました。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でかなり大規模なテキストアドベンチャーを開発しています。これまでのところ、私のPlayerクラスには100を超える属性があります。これを使用して、表示する必要がある特定の属性を検索します。


残念ながらvars()はクラス属性を返しません
user2682863

私が投稿したコードを実行してみましたか?Varは確実にクラス属性を返すことができます。ない例を見せてください。多分私のコードは間違っています。しかし、変数にvars()を割り当て、その変数を介してキー、値の検索を使用すると、クラス属性を返すことができます。
Corey Bailey

クラスT:x = 1; t = T(); vars(t)
user2682863

私があなたを適切に見せるためには、私が仕事を終えるまで待つ必要があります。しかし、あなたのコードは間違っています。クラスオブジェクトは__init __(self)を定義する必要があり、xはself.x = 1である必要があります。次に、t = T()を割り当て、print(vars(t))を使用すると、すべてのクラス属性の辞書が表示されます。
Corey Bailey

いいえ、これらはクラス属性ではなくインスタンス属性です。多くのサブクラスがinitを呼び出すことはありません。先に述べたように、vars()はクラス属性を返さないため、dir()またはinspect.getmembers()を使用する必要があります
user2682863

2

これは検査なしで行えると思います。

次のクラスを取ります:

 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を使用してください


2

Python 2&3、Whitoutインポート、アドレスによるオブジェクトのフィルタリング

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

dict {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)}

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

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

リスト[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ステートメントが返されますTrueのメモリ内の位置を16進数表現があれば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ドキュメントは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()


1

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

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ため、同じ検索プロセスをエミュレートするには、モジュールが必要です。


2
スコット-回答として投稿されたコメントは削除する必要があります。削除しないと、溺れてしまいます。ただし、解決策に対する部分的な回答または「役立つナッジ」は、依然として回答です。私があなたの投稿をどのように書き換えたかがわかります。うまくいけば、私はあなたの意図を保持しました。そうでない場合は、さらに形状を編集できます。乾杯!
Mogsdad 2016年

1

リスト内包表記で使用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

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

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

この部分cls.__dict__['__doc__']は、クラスのドキュメント文字列を抽出します。


1

なぜ属性をリストする必要があるのですか?意味的にあなたのクラスはコレクションであるようです。この場合、列挙型を使用することをお勧めします。

import enum

class myClass(enum.Enum):
     a = "12"
     b = "34"

あなたの属性をリストアップしますか?これより簡単なものはありません:

for attr in myClass:
    print("Name / Value:", attr.name, attr.value)

1

属性を「取得」したい場合は、非常に単純な答えがあります。これは明らかです: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のどちらでも問題なく動作します。

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


1
その答えは単純すぎて正すぎてポイントに値しませんか、悪いポイントに値するべきですか?今日では、経済とシンプルさはもはや報われないようです。
Fralau

0

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

以下は私が欲しいものです。

テストデータ

class Base:
    b = 'b'


class MyClass(Base):
    a = '12'

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

    @classmethod
    def c(cls):
        ...

    @property
    def p(self):
        return self.a

    def my_fun(self):
        return self.name
print([name for name, val in inspect.getmembers(MyClass) if not name.startswith('_') and not callable(val)])  # need `import inspect`
print([_ for _ in dir(MyClass) if not _.startswith('_') and not callable(getattr(MyClass, _))])
# both are equ: ['a', 'b', 'p']

my_instance = MyClass('c')
print([_ for _ in dir(my_instance) if not _.startswith('_') and not callable(getattr(my_instance, _))])
# ['a', 'b', 'name', 'p']

-2

私はこれが3年前だったことを知っていますが、将来この質問をする人のために、私にとっては:

class_name.attribute 

正常に動作します。


3
AttributeErrorを受け取った場合を除きます。
レディ

あなたはいつもattribute事前に何であるかを知っているわけではありません。
Matt Luongo、2015

-3

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


AttributeError:タイプオブジェクト 'X'に属性 ' attrs ' がありません
Ramazan Polat '28
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.