احصل على اسم فئة مؤهلة بالكامل للكائن في Python

StackOverflow https://stackoverflow.com/questions/2020014

  •  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
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top