ロギングの目的で、Pythonオブジェクトの完全修飾クラス名を取得したいと思います。(完全修飾とは、パッケージとモジュール名を含むクラス名を意味します。)
私は知ってx.__class__.__name__
いますが、パッケージとモジュールを取得する簡単な方法はありますか?
ロギングの目的で、Pythonオブジェクトの完全修飾クラス名を取得したいと思います。(完全修飾とは、パッケージとモジュール名を含むクラス名を意味します。)
私は知ってx.__class__.__name__
いますが、パッケージとモジュールを取得する簡単な方法はありますか?
次のプログラムで
#!/usr/bin/env python
import foo
def fullname(o):
klass = o.__class__
module = klass.__module__
if module == 'builtins':
return klass.__qualname__ # avoid outputs like 'builtins.str'
return module + '.' + klass.__qualname__
bar = foo.Bar()
print(fullname(bar))
とBar
定義されます
class Bar(object):
def __init__(self, v=42):
self.val = v
出力は
$ ./prog.py
foo.Bar
それでもPython2を使い続ける場合は、__name__
の代わりにを使用する必要があります。__qualname__
これは、ネストされたクラスの情報量が少なくなります。クラスにBar
ネストされたクラスは、次の代わりにFoo
表示されます。Bar
Foo.Bar
def fullname(o):
klass = o.__class__
module = klass.__module__
if module == '__builtin__':
return klass.__name__ # avoid outputs like '__builtin__.str'
return module + '.' + klass.__name__
提供された回答は、ネストされたクラスを扱いません。
Python 3.3(PEP 3155__qualname__
)以降、の代わりにクラスを使用できます__name__
。そうでなければ、のようなクラス
class Foo:
class Bar: # this one
pass
Bar
の代わりにとして表示されFoo.Bar
ます。
__module__
(それでも、を個別にqualnameに付加する必要があります-__qualname__
モジュール名を含めることを意図していません。)
これはGregBaconの優れた回答に基づいていますが、いくつかの追加のチェックがあります。
__module__
None
(ドキュメントによると)可能性があり、また、可能性のあるタイプ(str
ログ__builtin__
などに表示したくない場合もあります)の場合もあります。以下は、これらの両方の可能性をチェックします。
def fullname(o):
module = o.__class__.__module__
if module is None or module == str.__class__.__module__:
return o.__class__.__name__
return module + '.' + o.__class__.__name__
(チェックするためのより良い方法があるかもしれません__builtin__
。上記は、strが常に利用可能であり、そのモジュールが常に利用可能であるという事実に依存しています__builtin__
)
探しているものinspect
のような機能を持つモジュールの使用を検討してください。getmodule
>>>import inspect
>>>import xml.etree.ElementTree
>>>et = xml.etree.ElementTree.ElementTree()
>>>inspect.getmodule(et)
<module 'xml.etree.ElementTree' from
'D:\tools\python2.5.2\lib\xml\etree\ElementTree.pyc'>
python3.7の場合、私は以下を使用します。
".".join([obj.__module__, obj.__name__])
取得:
package.subpackage.ClassName
__module__
トリックを行います。
試す:
>>> import re
>>> print re.compile.__module__
re
このサイト__package__
は、 Python3.0で機能する可能性があることを示唆しています。ただし、そこに示されている例は、私のPython2.5.2コンソールでは機能しません。
一部の人々(例えばhttps://stackoverflow.com/a/16763814/5766934__qualname__
)はそれがより良いと主張してい__name__
ます。違いを示す例を次に示します。
$ cat dummy.py
class One:
class Two:
pass
$ python3.6
>>> import dummy
>>> print(dummy.One)
<class 'dummy.One'>
>>> print(dummy.One.Two)
<class 'dummy.One.Two'>
>>> def full_name_with_name(klass):
... return f'{klass.__module__}.{klass.__name__}'
>>> def full_name_with_qualname(klass):
... return f'{klass.__module__}.{klass.__qualname__}'
>>> print(full_name_with_name(dummy.One)) # Correct
dummy.One
>>> print(full_name_with_name(dummy.One.Two)) # Wrong
dummy.Two
>>> print(full_name_with_qualname(dummy.One)) # Correct
dummy.One
>>> print(full_name_with_qualname(dummy.One.Two)) # Correct
dummy.One.Two
ビルトインでも正しく機能することに注意してください。
>>> print(full_name_with_qualname(print))
builtins.print
>>> import builtins
>>> builtins.print
<built-in function print>
これはハックですが、私は2.6をサポートしており、単純なものが必要です。
>>> from logging.handlers import MemoryHandler as MH
>>> str(MH).split("'")[1]
'logging.handlers.MemoryHandler'
このトピックの関心は完全修飾名を取得することであるため、同じパッケージに存在するメインモジュールと一緒に相対インポートを使用するときに発生する落とし穴があります。たとえば、以下のモジュール設定で:
$ cat /tmp/fqname/foo/__init__.py
$ cat /tmp/fqname/foo/bar.py
from baz import Baz
print Baz.__module__
$ cat /tmp/fqname/foo/baz.py
class Baz: pass
$ cat /tmp/fqname/main.py
import foo.bar
from foo.baz import Baz
print Baz.__module__
$ cat /tmp/fqname/foo/hum.py
import bar
import foo.bar
同じモジュールを異なる方法でインポートした結果を示す出力は次のとおりです。
$ export PYTHONPATH=/tmp/fqname
$ python /tmp/fqname/main.py
foo.baz
foo.baz
$ python /tmp/fqname/foo/bar.py
baz
$ python /tmp/fqname/foo/hum.py
baz
foo.baz
humが相対パスを使用してbarをインポートする場合、barはBaz.__module__
単に「baz」と見なされますが、フルネームを使用する2番目のインポートでは、barは「foo.baz」と同じように表示されます。
完全修飾名をどこかに永続化する場合は、それらのクラスの相対的なインポートを避けることをお勧めします。
これは、修飾されたクラス名を使用するためのGregBaconとMBによる回答の適応です。質問は修飾されたクラス名を求めていたことに注意してください。Python3.8でテストされました。
def fullname(obj: object) -> str:
"""Return the full name of the given object using its module and qualified class names."""
# Ref: https://stackoverflow.com/a/66508248/
module_name, class_name = obj.__class__.__module__, obj.__class__.__qualname__
if module_name in (None, str.__class__.__module__):
return class_name
return module_name + "." + class_name
Bellowは、Greg Baconの答えを改良したものであり、組み込みとユーザー定義の両方のクラス、インスタンス、メソッド、関数についてテストされています。
def fullname(o):
try:
# if o is a class or function, get module directly
module = o.__module__
except AttributeError:
# then get module from o's class
module = o.__class__.__module__
try:
# if o is a class or function, get name directly
name = o.__qualname__
except AttributeError:
# then get o's class name
name = o.__class__.__qualname__
# if o is a method of builtin class, then module will be None
if module == 'builtins' or module is None:
return name
return module + '.' + name
ここでの答えはどれも私にはうまくいきませんでした。私の場合、Python 2.7を使用していて、新しいスタイルobject
のクラスでのみ作業することを知っていました。
def get_qualified_python_name_from_class(model):
c = model.__class__.__mro__[0]
name = c.__module__ + "." + c.__name__
return name