Python クラスの各プロパティとメソッドがどこで定義されているかをどのように判断しますか?
-
20-08-2019 - |
質問
Python のあるクラスのインスタンスが与えられた場合、ソース コードのどの行を特定できると便利です。 定義済み 各メソッドとプロパティ (例:実装する 1)。たとえば、モジュール ab.py が与えられたとします。
class A(object):
z = 1
q = 2
def y(self): pass
def x(self): pass
class B(A):
q = 4
def x(self): pass
def w(self): pass
ファイル名、クラス、および定義またはサブクラス化したソース コード内の行を含むタプルを返す関数 whither(class_,attribute) を定義します。 attribute
. 。これは、過度のダイナミズムによる最新の割り当てではなく、クラス本体内の定義を意味します。一部の属性に対して「不明」が返されても問題ありません。
>>> a = A()
>>> b = B()
>>> b.spigot = 'brass'
>>> whither(a, 'z')
("ab.py", <class 'a.A'>, [line] 2)
>>> whither(b, 'q')
("ab.py", <class 'a.B'>, 8)
>>> whither(b, 'x')
("ab.py", <class 'a.B'>, 9)
>>> whither(b, 'spigot')
("Attribute 'spigot' is a data attribute")
Plone をイントロスペクトするときにこれを使用したいと考えています。Plone では、すべてのオブジェクトに何百ものメソッドがあり、それらをアルファベット順だけでなくクラス別に分類できると非常に便利です。
もちろん、Python では常に合理的に知ることができるわけではありませんが、ほとんどが静的なコードの一般的なケースでは適切な答えが得られると良いでしょう。
解決 2
文書化されていない関数を探しています inspect.classify_class_attrs(cls)
. 。クラスを渡すとタプルのリストが返されます ('name', 'kind' e.g. 'method' or 'data', defining class, property)
. 。特定のインスタンスのすべてに関する情報が必要な場合は、追加の作業を行う必要があります。
例:
>>> import inspect
>>> import pprint
>>> import calendar
>>>
>>> hc = calendar.HTMLCalendar()
>>> hc.__class__.pathos = None
>>> calendar.Calendar.phobos = None
>>> pprint.pprint(inspect.classify_class_attrs(hc.__class__))
[...
('__doc__',
'data',
<class 'calendar.HTMLCalendar'>,
'\n This calendar returns complete HTML pages.\n '),
...
('__new__',
'data',
<type 'object'>,
<built-in method __new__ of type object at 0x814fac0>),
...
('cssclasses',
'data',
<class 'calendar.HTMLCalendar'>,
['mon', 'tue', 'wed', 'thu', 'fri', 'sat', 'sun']),
('firstweekday',
'property',
<class 'calendar.Calendar'>,
<property object at 0x98b8c34>),
('formatday',
'method',
<class 'calendar.HTMLCalendar'>,
<function formatday at 0x98b7bc4>),
...
('pathos', 'data', <class 'calendar.HTMLCalendar'>, None),
('phobos', 'data', <class 'calendar.Calendar'>, None),
...
]
他のヒント
これは静的解析なしでは多かれ少なかれ不可能であり、たとえ静的解析であっても常に機能するとは限りません。コード オブジェクトを調べることで、関数がどのファイルで定義されている行を取得できますが、それ以上にできることはあまりありません。の inspect
モジュールがこれに役立ちます。それで:
import ab
a = ab.A()
meth = a.x
# So, now we have the method.
func = meth.im_func
# And the function from the method.
code = func.func_code
# And the code from the function!
print code.co_firstlineno, code.co_filename
# Or:
import inspect
print inspect.getsource(meth), inspect.getfile(meth)
しかし、次のように考えてください。
def some_method(self):
pass
ab.A.some_method = some_method
ab.A.some_class_attribute = None
さらに悪いことに:
some_cls = ab.A
some_string_var = 'another_instance_attribute'
setattr(some_cls, some_string_var, None)
特に後者の場合、何を望んでいますか、何を得ることを期待していますか?
あなたが探しているのは、 検査する モジュール、特に inspect.getsourcefile()
そして inspect.getsourcelines()
. 。例えば
a.py:
class Hello(object):
def say(self):
print 1
>>> from a import Hello
>>> hi = Hello()
>>> inspect.getsourcefile(hi.say)
a.py
>>> inspect.getsourcelines(A, foo)
([' def say(self):\n print 1\n'], 2)
Python の動的な性質を考えると、より複雑な状況でこれを行うことは単純に不可能かもしれません...