รับชื่อคลาสของอินสแตนซ์?


1437

ฉันจะหาชื่อของคลาสที่สร้างอินสแตนซ์ของวัตถุใน Python ได้อย่างไรถ้าฟังก์ชันที่ฉันทำนี้เป็นคลาสพื้นฐานที่คลาสของอินสแตนซ์ได้รับมา

กำลังคิดว่าบางทีโมดูลตรวจสอบอาจช่วยฉันที่นี่ แต่ดูเหมือนจะไม่ให้สิ่งที่ฉันต้องการ และขาดการแยก__class__สมาชิกฉันไม่แน่ใจว่าจะรับข้อมูลนี้ได้อย่างไร


คุณกำลังแยกวิเคราะห์อะไรจากตัวแปรคลาส ?
sykora

1
ชื่อระดับบนสุดของชั้นที่อินสแตนซ์เป็น (ไม่มีชื่อโมดูล ฯลฯ ... )
แดน

ฉันคิดว่าสิ่งที่ตรงกันข้ามจะยากกว่านี้ (เพื่อให้ได้ระดับที่กำหนดวิธีการ / ฟังก์ชั่น)
Alexey

คำตอบ:


1908

คุณได้ลอง__name__คุณสมบัติของชั้นเรียนหรือไม่? คือtype(x).__name__จะให้ชื่อของชั้นเรียนซึ่งฉันคิดว่าเป็นสิ่งที่คุณต้องการ

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

หากคุณยังใช้ Python 2 อยู่โปรดทราบว่าวิธีการด้านบนใช้ได้กับคลาสสไตล์ใหม่เท่านั้น (ใน Python 3+ คลาสทั้งหมดเป็นคลาส "สไตล์ใหม่") รหัสของคุณอาจใช้คลาสเก่าบางคลาส ผลงานต่อไปนี้สำหรับทั้งสอง:

x.__class__.__name__

41
เรียบง่ายน่าอัศจรรย์ สงสัยว่าทำไมdir(x.__class__)ไม่มีรายการ?
cfi

43
ทำไมต้องใช้__class__มากกว่าtypeวิธี? type(x).__name__เพื่อต้องการ: การเรียกสมาชิกที่ขีดเส้นใต้สองครั้งไม่ท้อแท้หรือไม่ ฉันไม่สามารถดูวิธีการใช้รอบ__name__แม้ว่า
jpmc26

25
คุณต้องใช้โดยตรงจะเข้ากันได้กับการเรียนแบบเก่าตั้งแต่ชนิดของพวกเขาเป็นเพียง__class__ instance
Quantum7

14
นี่ใช้บ่อยในการเข้าสู่ระบบ orm และรหัสเฟรมเวิร์กที่ควรมีชื่อไฟล์ในตัว (x) ... กำหนดให้ผู้ใช้ดู "guts" เพื่อรับชื่อไม่ใช่ pythonic ที่น่ากลัว
Erik Aronesty

5
@ErikAronestydef typename(x): return type(x).__name__
sleblanc

390

คุณต้องการชื่อของคลาสเป็นสตริงหรือไม่?

instance.__class__.__name__

6
หรืออินสแตนซ์. _ class__ เพื่อรับวัตถุคลาส: D
Pencilcheck

8
การใช้คุณสมบัติขีดเส้นใต้คู่ปลอดภัยหรือไม่?
Eduard Luca

5
@EduardLuca ทำไมมันไม่ปลอดภัยเหรอ? คุณสมบัติในตัวใช้ขีดล่างเพื่อไม่ให้เกิดความขัดแย้งกับรหัสที่คุณเขียน
JC Rocamonde

3
ฉันรู้ว่าขีดเส้นใต้เดียวหมายความว่า / แนะนำว่าวิธีการ / คุณสมบัติควรเป็นแบบส่วนตัว (แม้ว่าคุณจะไม่สามารถใช้วิธีการส่วนตัวใน Python AFAIK ได้) และฉันก็สงสัยว่ามันไม่ใช่กรณีที่มีขีดเส้นใต้สองเท่า (บ้าง)
Eduard Luca

28
@EduardLuca ขีดเส้นใต้คู่ที่จุดเริ่มต้นเท่านั้นจะคล้ายกับขีดเส้นใต้เดียวที่จุดเริ่มต้น แต่ยิ่ง "ส่วนตัว" (ค้นหา "python name mangling") ยิ่งกว่านั้น เครื่องหมายขีดล่างคู่ที่จุดเริ่มต้นและจุดสิ้นสุดแตกต่างกัน - ซึ่งสงวนไว้สำหรับงูใหญ่และไม่เป็นส่วนตัว (เช่นวิธีมายากลเช่น __init__ และ __add__)
Leagsaidh Gordon

101

ประเภท ()?

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

นี้เป็นเช่นเดียวกับระดับสมาชิก แต่ฉันมีการแยกผลนี้ด้วยมือซึ่งเป็นบิตที่น่ารำคาญ ...
แดน

8
ฉันชอบอันนี้ ด้วยวิธีนี้มันเป็นไปได้ในคลาสฐานเพื่อรับชื่อของคลาสย่อย
joctee

6
หรือself.__class__.__name__แทนที่จะtype(self).__name__ได้รับพฤติกรรมเดียวกัน type()ฟังก์ชั่นใดที่ฉันไม่ทราบถ้าไม่มีสิ่งใด
อังเดร

2
หากคุณกำลังใช้type(item)รายการอยู่ผลลัพธ์จะอยู่<type 'instance'>ในขณะที่item.__class__.__name__เก็บชื่อคลาสไว้
Grochni

1
ฉันคิดว่าปัญหาที่ @Grochni กล่าวถึงนั้นเกี่ยวข้องกับบางคลาสใน Python 2.x เท่านั้นดูที่นี่: stackoverflow.com/questions/6666856//
เนท CK

43
class A:
  pass

a = A()
str(a.__class__)

โค้ดตัวอย่างด้านบน (เมื่อป้อนข้อมูลในล่ามแบบโต้ตอบ) จะสร้างขึ้น'__main__.A'เมื่อเทียบกับ'A'สิ่งที่สร้างขึ้นหาก__name__มีการเรียกใช้แอตทริบิวต์ เพียงแค่ส่งผลลัพธ์ของA.__class__ตัวstrสร้างไปที่การแยกวิเคราะห์จะจัดการให้คุณ อย่างไรก็ตามคุณสามารถใช้รหัสต่อไปนี้หากคุณต้องการบางสิ่งที่ชัดเจนยิ่งขึ้น

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

พฤติกรรมนี้สามารถทำได้ดีกว่าถ้าคุณมีคลาสที่มีชื่อเดียวกันที่กำหนดไว้ในโมดูลแยกต่างหาก

ตัวอย่างโค้ดที่ให้ไว้ข้างต้นได้รับการทดสอบใน Python 2.7.5


ทดสอบใน 2.6.6 ยังใช้งานได้ดี
Hamlett

29
type(instance).__name__ != instance.__class__.__name  #if class A is defined like
class A():
   ...

type(instance) == instance.__class__                  #if class A is defined like
class A(object):
  ...

ตัวอย่าง:

>>> class aclass(object):
...   pass
...
>>> a = aclass()
>>> type(a)
<class '__main__.aclass'>
>>> a.__class__
<class '__main__.aclass'>
>>>
>>> type(a).__name__
'aclass'
>>>
>>> a.__class__.__name__
'aclass'
>>>


>>> class bclass():
...   pass
...
>>> b = bclass()
>>>
>>> type(b)
<type 'instance'>
>>> b.__class__
<class __main__.bclass at 0xb765047c>
>>> type(b).__name__
'instance'
>>>
>>> b.__class__.__name__
'bclass'
>>>

5
นี่ถือเป็นจริงสำหรับ Python 2.x ตัวเก่าเท่านั้น ใน 3.x, bclass () จะแก้ไขเป็น bclass (วัตถุ) และถึงแม้ว่าจะมีคลาสใหม่ปรากฏใน Python 2.2
alcalde

16

คำถามที่ดี.

ตัวอย่างง่ายๆของ 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

13

หรือคุณสามารถใช้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'

10

นอกเหนือจากการคว้า__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'

เนื่องจากวิปัสสนาเป็นสิ่งที่คุณหลังจากนี้เป็นเสมอคุณอาจต้องการพิจารณา


2
ควรสังเกตว่า__qualname__สำหรับ Python 3.3+
FireAphis

10
และฉันจะหลีกเลี่ยงการตั้งชื่ออะไรในซอฟต์แวร์ "ปรุงยา" ของฉัน
Bobort

คำอธิบายที่เกี่ยวข้องสำหรับ__qualname__vs __name__: stackoverflow.com/questions/58108488/what-is-qualname-in-python
ti7

0

ในการรับ classname อินสแตนซ์:

type(instance).__name__

หรือ

instance.__class__.__name__

ทั้งสองเหมือนกัน

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.