Nhận tên lớp đầy đủ của một đối tượng trong Python


136

Đối với mục đích ghi nhật ký, tôi muốn lấy tên lớp đủ điều kiện của một đối tượng Python. (Với đủ điều kiện tôi có nghĩa là tên lớp bao gồm tên gói và tên mô-đun.)

Tôi biết về x.__class__.__name__, nhưng có một phương pháp đơn giản để có được gói và mô-đun?

Câu trả lời:


147

Với chương trình sau

#! /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được định nghĩa là

class Bar(object):
  def __init__(self, v=42):
    self.val = v

đầu ra là

$ ./prog.py
foo.Bar

2
Điều này dường như trả về mô-đun nơi thanh được xác định, không phải nơi thanh được xác định. Nếu mục đích của việc đăng nhập là để biết chính xác đó là loại đối tượng nào, thì điều này dường như không có ích.
Đánh dấu E. Haase

o.__class__.__module__bao giờ khác với o.__module__?
larsks


1
Tôi đặc biệt giới thiệu ".".join([o.__module__, o.__name__])cho Python3
Piotr Pęczek

Đôi khi không hoạt động:AttributeError: 'AttributeError' object has no attribute '__module__'
Hendy I Girls

38

Các câu trả lời được cung cấp không đối phó với các lớp lồng nhau. Mặc dù nó không có sẵn cho đến Python 3.3 ( PEP 3155 ), bạn thực sự muốn sử dụng __qualname__lớp. Cuối cùng (3.4? PEP 395 ), __qualname__cũng sẽ tồn tại cho các mô-đun để xử lý các trường hợp mô-đun được đổi tên (nghĩa là khi nó được đổi tên thành __main__).


3
Nếu bạn sử dụng github.com/wbolster/qualname, bạn có thể nhận được một tên tương đương trên các phiên bản cũ hơn.
đồ trang sức bolsterlee

3
Tức Type.__module__ + '.' + Type.__qualname__.
Kentzo

4
Với Python 3.6, cái này chỉ cho tôi tên lớp. Nó không bao gồm các mô-đun.
jpmc26

2
@ jpmc26 Trong Python 3.7, __qualname__vẫn chỉ phân giải thành tên lớp
zepp.lee

22

Xem xét sử dụng inspectmô-đun có các chức năng giống như getmodulecó thể là những gì đang tìm kiếm:

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

7
inspect.getmodule()trả về các đối tượng mô-đun - tên lớp không đủ điều kiện. Trong thực tế, inspectmô-đun cung cấp không có chức năng nào thực sự sẽ giải quyết câu hỏi này. Câu trả lời này là một câu trả lời không. </facepalm>
Cecil Curry

19

Đây là một câu trả lời dựa trên câu trả lời xuất sắc của Greg Bacon, nhưng với một vài kiểm tra bổ sung:

__module__có thể là None(theo các tài liệu), và đối với một loại giống như strnó có thể __builtin__(mà bạn có thể không muốn xuất hiện trong nhật ký hoặc bất cứ điều gì). Các kiểm tra sau cho cả hai khả năng đó:

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__

(Có thể có một cách tốt hơn để kiểm tra __builtin__. Ở trên chỉ dựa vào thực tế là str luôn có sẵn và mô-đun của nó luôn luôn __builtin__)


1
Để tiết kiệm cho người khác nỗ lực so sánh hai câu trả lời: mã trong câu trả lời của Greg Bacon giờ giống hệt với mã trong câu này, ngoài ra Greg đã thêm một tuyên bố vô nghĩa khác và một số nhận xét về mã. MB là anh hùng thực sự.
MarredCheese

11

Đối với python3.7 tôi sử dụng:

".".join([obj.__module__, obj.__name__])

Bắt:

package.subpackage.ClassName

lưu ý rằng objphải là một lớp chứ không phải là một thể hiện đối tượng.
Ivan De Paz Centeno

9

__module__ sẽ làm các mẹo.

Thử:

>>> import re
>>> print re.compile.__module__
re

Trang web này gợi ý rằng __package__có thể hoạt động cho Python 3.0; Tuy nhiên, các ví dụ đưa ra sẽ không hoạt động trong bảng điều khiển Python 2.5.2 của tôi.


6
Đó là mẹo, cảm ơn! Đối với tên đủ điều kiện tôi sẽ sử dụng "%s.%s" % (x.__class__.__module__, x.__class__.__name__)
Hanno S.

7

Đây là một hack nhưng tôi đang hỗ trợ 2.6 và chỉ cần một cái gì đó đơn giản:

>>> from logging.handlers import MemoryHandler as MH
>>> str(MH).split("'")[1]

'logging.handlers.MemoryHandler'

1
Điều này phụ thuộc vào __repr__()thực hiện trong lớp kiểm tra ( trên __str__()không được overriden). Vô dụng trong hầu hết các trường hợp.
z33k

7

Một số người (ví dụ: https://stackoverflow.com/a/16763814/5766934 ) cho rằng điều đó __qualname__tốt hơn __name__. Dưới đây là một ví dụ cho thấy sự khác biệt:

$ 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

Lưu ý, nó cũng hoạt động chính xác cho các bản dựng:

>>> print(full_name_with_qualname(print))
builtins.print
>>> import builtins
>>> builtins.print
<built-in function print>

2

Vì sự quan tâm của chủ đề này là để có được các tên đủ điều kiện, đây là một cạm bẫy xảy ra khi sử dụng nhập khẩu tương đối cùng với mô-đun chính hiện có trong cùng một gói. Ví dụ, với thiết lập mô-đun bên dưới:

$ 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

Đây là đầu ra hiển thị kết quả của việc nhập cùng một mô-đun khác nhau:

$ 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

Khi hum nhập thanh sử dụng đường dẫn tương đối, thanh chỉ xem Baz.__module__là "baz", nhưng trong lần nhập thứ hai sử dụng tên đầy đủ, thanh sẽ thấy giống như "foo.baz".

Nếu bạn đang duy trì các tên đủ điều kiện ở đâu đó, tốt hơn là tránh nhập khẩu tương đối cho các lớp đó.


0

Không có câu trả lời nào ở đây làm việc cho tôi. Trong trường hợp của tôi, tôi đã sử dụng Python 2.7 và biết rằng tôi sẽ chỉ làm việc với objectcác lớp newstyle .

def get_qualified_python_name_from_class(model):
    c = model.__class__.__mro__[0]
    name = c.__module__ + "." + c.__name__
    return name
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.