introspection text用法 - 在Python中獲取實例的類名




matplotlib文字 python畫圖標題 (8)

我如何找到一個在Python中創建一個對象實例的類的名字,如果我這樣做的函數是派生實例類的基類?

在想,也許檢查模塊可能會幫助我在這裡,但它似乎並沒有給我想要的。 並沒有解析__class__成員,我不知道如何得到這些信息。


Answers

class A:
  pass

a = A()
str(a.__class__)

上面的示例代碼(當在交互式解釋器中輸入時)將產生'__main__.A' ,而不是'A' ,如果調用__name__屬性則產生'A' 。 只需將A.__class__的結果傳遞給str構造函數,即可為您處理解析。 不過,如果你想要更明確的東西,你也可以使用下面的代碼。

"{0}.{1}".format(a.__class__.__module__,a.__class__.__name__)

如果您在單獨的模塊中定義具有相同名稱的類,則此行為可能更好。

上面提供的示例代碼在Python 2.7.5中進行了測試。


好問題。

以下是一個基於GHZ的簡單例子,可以幫助某人:

>>> class person(object):
        def init(self,name):
            self.name=name
        def info(self)
            print "My name is {0}, I am a {1}".format(self.name,self.__class__.__name__)
>>> bob = person(name='Robert')
>>> bob.info()
My name is Robert, I am a person

你想把這個類的名字當作一個字符串嗎?

instance.__class__.__name__

除了抓住特殊的__name__屬性,你可能會發現自己需要給定類/函數的限定名稱 。 這是通過抓取類型__qualname__來完成的。

在大多數情況下,這些將完全相同,但是,在處理嵌套的類/方法時,這些輸出會有所不同。 例如:

class Spam:
    def meth(self):
        pass
    class Bar:
        pass

>>> s = Spam()
>>> type(s).__name__ 
'Spam'
>>> type(s).__qualname__
'Spam'
>>> type(s).Bar.__name__       # type not needed here
'Bar'
>>> type(s).Bar.__qualname__   # type not needed here 
'Spam.Bar'
>>> type(s).meth.__name__
'meth'
>>> type(s).meth.__qualname__
'Spam.meth'

既然內省是你追求的目標,那麼你總是可以考慮。


您是否嘗試過__name__屬性? 即type(x).__name__會給你類的名字,我認為你想要的是這個名字。

>>> import itertools
>>> x = itertools.count(0)
>>> type(x).__name__
'count'

此方法僅適用於新式類 。 你的代碼可能會使用一些舊式的類。 以下兩種作品適用於:

x.__class__.__name__

或者,您可以使用classmethod

class A:
    @classmethod
    def get_classname(cls):
        return cls.__name__

    def use_classname(self):
        return self.get_classname()

用法

>>> A.get_classname()
'A'
>>> a = A()
>>> a.get_classname()
'A'
>>> a.use_classname()
'A'

type()?

>>> class A(object):
...    def whoami(self):
...       print type(self).__name__
...
>>>
>>> class B(A):
...    pass
...
>>>
>>>
>>> o = B()
>>> o.whoami()
'B'
>>>

__call__()創建類實例時元類' 方法的作用

如果你已經完成Python編程超過幾個月,你最終會偶然發現如下所示的代碼:

# define a class
class SomeClass(object):
    # ...
    # some definition here ...
    # ...

# create an instance of it
instance = SomeClass()

# then call the object as if it's a function
result = instance('foo', 'bar')

當你__call__()在類上實現魔術方法時,後者是可能的。

class SomeClass(object):
    # ...
    # some definition here ...
    # ...

    def __call__(self, foo, bar):
        return bar + foo

__call__()當類的實例用作可調用對象時,將調用該方法。但正如我們從前面的答案中看到的,類本身是元類的一個實例,所以當我們將類用作可調用的時(即當我們創建它的實例時),我們實際上正在調用它的元類' __call__()方法。在這一點上,大多數Python程序員都有點困惑,因為他們被告知在創建這樣的實例時,instance = SomeClass()你正在調用它的__init__()方法。有些誰已經挖一個深一點知道,之前__init__()__new__()。好吧,今天還有另一層真相被揭示出來,然後__new__()才有了元類' __call__()

讓我們從創建類實例的角度研究方法調用鏈。

這是一個元類,它精確記錄實例創建之前的時刻以及它將要返回的時刻。

class Meta_1(type):
    def __call__(cls):
        print "Meta_1.__call__() before creating an instance of ", cls
        instance = super(Meta_1, cls).__call__()
        print "Meta_1.__call__() about to return instance."
        return instance

這是一個使用該元類的類

class Class_1(object):

    __metaclass__ = Meta_1

    def __new__(cls):
        print "Class_1.__new__() before creating an instance."
        instance = super(Class_1, cls).__new__(cls)
        print "Class_1.__new__() about to return instance."
        return instance

    def __init__(self):
        print "entering Class_1.__init__() for instance initialization."
        super(Class_1,self).__init__()
        print "exiting Class_1.__init__()."

現在讓我們創建一個實例 Class_1

instance = Class_1()
# Meta_1.__call__() before creating an instance of <class '__main__.Class_1'>.
# Class_1.__new__() before creating an instance.
# Class_1.__new__() about to return instance.
# entering Class_1.__init__() for instance initialization.
# exiting Class_1.__init__().
# Meta_1.__call__() about to return instance.

觀察上面的代碼實際上並沒有做任何事情,只記錄任務。每個方法都將實際工作委託給其父實現,從而保持默認行為。由於typeMeta_1父類(type作為默認父元類)並考慮上面輸出的排序順序,我們現在有一個線索,關於什麼是偽實現type.__call__()

class type:
    def __call__(cls, *args, **kwarg):

        # ... maybe a few things done to cls here

        # then we call __new__() on the class to create an instance
        instance = cls.__new__(cls, *args, **kwargs)

        # ... maybe a few things done to the instance here

        # then we initialize the instance with its __init__() method
        instance.__init__(*args, **kwargs)

        # ... maybe a few more things done to instance here

        # then we return it
        return instance

我們可以看到元類的__call__()方法是第一個被調用的方法。然後它將實例的創建委託給類的__new__()方法並初始化為實例__init__()。它也是最終返回實例的那個。

從上面可以看出,元類' __call__()也有機會決定是否打電話Class_1.__new__()Class_1.__init__()最終打電話。在執行過程中,它實際上可以返回一個未被這些方法觸及的對象。以單例模式的這種方法為例:

class Meta_2(type):
    singletons = {}

    def __call__(cls, *args, **kwargs):
        if cls in Meta_2.singletons:
            # we return the only instance and skip a call to __new__()
            # and __init__()
            print ("{} singleton returning from Meta_2.__call__(), "
                   "skipping creation of new instance.".format(cls))
            return Meta_2.singletons[cls]

        # else if the singleton isn't present we proceed as usual
        print "Meta_2.__call__() before creating an instance."
        instance = super(Meta_2, cls).__call__(*args, **kwargs)
        Meta_2.singletons[cls] = instance
        print "Meta_2.__call__() returning new instance."
        return instance

class Class_2(object):

    __metaclass__ = Meta_2

    def __new__(cls, *args, **kwargs):
        print "Class_2.__new__() before creating instance."
        instance = super(Class_2, cls).__new__(cls)
        print "Class_2.__new__() returning instance."
        return instance

    def __init__(self, *args, **kwargs):
        print "entering Class_2.__init__() for initialization."
        super(Class_2, self).__init__()
        print "exiting Class_2.__init__()."

讓我們觀察一下重複嘗試創建類型對象時會發生什麼 Class_2

a = Class_2()
# Meta_2.__call__() before creating an instance.
# Class_2.__new__() before creating instance.
# Class_2.__new__() returning instance.
# entering Class_2.__init__() for initialization.
# exiting Class_2.__init__().
# Meta_2.__call__() returning new instance.

b = Class_2()
# <class '__main__.Class_2'> singleton returning from Meta_2.__call__(), skipping creation of new instance.

c = Class_2()
# <class '__main__.Class_2'> singleton returning from Meta_2.__call__(), skipping creation of new instance.

a is b is c # True




python introspection instanceof python-datamodel