احصل على اسم فئة مؤهلة بالكامل للكائن في Python
-
19-09-2019 - |
سؤال
لأغراض التسجيل وأريد استرداد اسم الفئة المؤهلة بالكامل لكائن Python. (مع مؤهلة بالكامل أعني اسم الفصل بما في ذلك الحزمة واسم الوحدة النمطية.)
وأنا أعلم عن x.__class__.__name__
, ، ولكن هل هناك طريقة بسيطة للحصول على الحزمة والوحدة؟
المحلول
مع البرنامج التالي
#! /usr/bin/env python
import foo
def fullname(o):
# o.__module__ + "." + o.__class__.__qualname__ is an example in
# this context of H.L. Mencken's "neat, plausible, and wrong."
# Python makes no guarantees as to whether the __module__ special
# attribute is defined, so we take a more circumspect approach.
# Alas, the module name is explicitly excluded from __qualname__
# in Python 3.
module = o.__class__.__module__
if module is None or module == str.__class__.__module__:
return o.__class__.__name__ # Avoid reporting __builtin__
else:
return module + '.' + o.__class__.__name__
bar = foo.Bar()
print fullname(bar)
و Bar
معرف ك
class Bar(object):
def __init__(self, v=42):
self.val = v
الناتج هو
$ ./prog.py
foo.Bar
نصائح أخرى
الإجابات المقدمة لا تتعامل مع فصول متداخلة. على الرغم من أنها غير متوفرة حتى الثيثون 3.3 (بيب 3155.)، أنت تريد حقا استخدام __qualname__
الطبقة. في النهاية (3.4؟ بيب 395.), __qualname__
سيكون موجودا أيضا للحصول على وحدات للتعامل مع الحالات التي يتم فيها إعادة تسمية الوحدة النمطية (أي عند إعادة تسميتها __main__
).
النظر في استخدام 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'>
إليك واحدة تعتمد على إجابة جريج بيكون الممتازة، ولكن مع اثنين من الشيكات الإضافية:
__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__
)
__module__
سوف تفعل الخدعة.
محاولة:
>>> import re
>>> print re.compile.__module__
re
هذا الموقع يقترح أن __package__
قد تعمل من أجل بيثون 3.0؛ ومع ذلك، فإن الأمثلة الممنوحة لن تعمل تحت وحدة التحكم بيثون 2.5.2.
هذا هو الاختراق ولكني أؤيد 2.6 واحتاج فقط إلى شيء بسيط:
>>> from logging.handlers import MemoryHandler as MH
>>> str(MH).split("'")[1]
'logging.handlers.MemoryHandler'
بعض الناس (على سبيل المثال 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>
ل python3.7 أنا استخدم:
".".join([obj.__module__, obj.__name__])
الحصول:
package.subpackage.ClassName
نظرا لأن مصلحة هذا الموضوع هو الحصول على أسماء مؤهلة بالكامل، فهناك مفلع يحدث عند استخدام الواردات النسبية إلى جانب الوحدة النمطية الموجودة في نفس الحزمة. على سبيل المثال، مع إعداد الوحدة النمطية أدناه:
$ 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
عندما يكون شريط الواردات المزماء باستخدام المسار النسبي، يرى البار Baz.__module__
فقط "Baz"، ولكن في الاستيراد الثاني الذي يستخدم الاسم الكامل، يرى الشريط نفس "foo.baz".
إذا كنت تستمر في الأسماء المؤهلات بالكامل في مكان ما، فمن الأفضل تجنب الواردات النسبية لتلك الفئات.
أيا من الإجابات هنا عملت بالنسبة لي. في حالتي، كنت أستخدم بيثون 2.7 وعرفت أنني لن أعمل إلا مع NewStyle object
الطبقات.
def get_qualified_python_name_from_class(model):
c = model.__class__.__mro__[0]
name = c.__module__ + "." + c.__name__
return name