ได้รับชื่อชั้นปัจจุบัน?


103

ฉันจะได้รับชื่อชั้นเรียนที่ฉันอยู่ในขณะนี้ได้อย่างไร?

ตัวอย่าง:

def get_input(class_name):
    [do things]
    return class_name_result

class foo():
    input = get_input([class name goes here])

เนื่องจากลักษณะของโปรแกรมที่ฉันกำลังเชื่อมต่อกับ (vistrails) ฉันจึงไม่สามารถใช้__init__()เพื่อเริ่มต้นinputได้

คำตอบ:


159

obj.__class__.__name__ จะทำให้คุณได้รับชื่อวัตถุใด ๆ ดังนั้นคุณสามารถทำได้:

class Clazz():
    def getName(self):
        return self.__class__.__name__

การใช้งาน:

>>> c = Clazz()
>>> c.getName()
'Clazz'

1
เหตุใดจึงไม่เป็นคำตอบที่ยอมรับ แก้ไข: ตกลงขอบเขตของ OP ไม่ได้อยู่ภายใน แต่อยู่ในระดับชั้นเรียน
KomodoDave

6
@KomodoDave เพราะสิ่งนี้ผิดแม้ว่าจะอยู่ในขอบเขตวิธีการก็ตาม เมื่อคุณเรียกgetNameจากคลาสลูกมันจะส่งออกชื่อคลาสลูก จากนั้นมันจะยุ่งยากถ้าคุณต้องการชั้นเรียนที่คุณทำงานด้วยจริงๆ
Kenet Jervet

@KenetJervet คุณหมายถึงเมื่อคุณเรียกgetNameจากคลาสแม่มันจะส่งออกชื่อคลาสลูก? ตกลงเพื่อชี้สิ่งนั้น
KomodoDave

5
ในเงื่อนไข OO วิธีแก้ปัญหา (ส่งคืนชื่อคลาสย่อยของรันไทม์จริงแม้ว่าgetName()เมธอดจะถูกกำหนดไว้ในซูเปอร์คลาส) นั้นถูกต้อง
sxc731

22

ภายในเนื้อหาของคลาสยังไม่ได้กำหนดชื่อคลาสดังนั้นจึงไม่สามารถใช้ได้ พิมพ์ชื่อชั้นเรียนไม่ได้หรอ บางทีคุณอาจต้องพูดเพิ่มเติมเกี่ยวกับปัญหาเพื่อที่เราจะได้หาทางแก้ไขให้คุณ

ฉันจะสร้างเมตาคลาสเพื่อทำงานนี้ให้คุณ เรียกใช้เมื่อเวลาสร้างคลาส (ตามแนวคิดที่ส่วนท้ายสุดของคลาส: บล็อก) และสามารถจัดการกับคลาสที่กำลังสร้าง ฉันยังไม่ได้ทดสอบสิ่งนี้:

class InputAssigningMetaclass(type):
    def __new__(cls, name, bases, attrs):
        cls.input = get_input(name)
        return super(MyType, cls).__new__(cls, name, bases, newattrs)

class MyBaseFoo(object):
    __metaclass__ = InputAssigningMetaclass

class foo(MyBaseFoo):
    # etc, no need to create 'input'

class foo2(MyBaseFoo):
    # etc, no need to create 'input'

เพื่อชี้แจงสิ่งที่ฉันพยายามที่จะทำ: ฉันต้องสร้างและเริ่มต้นตัวแปรระดับ 'ป้อนข้อมูล' ด้านนอกของวิธีการ ฉันมีคลาสเล็ก ๆ มากมายแต่ละคลาสต้องเรียก 'get_input' โดยใช้ชื่อคลาสเป็นพารามิเตอร์ ฉันกำลังพยายามสรุปสิ่งนี้โดยไม่ต้องไปที่แต่ละคลาส (จะมี 100 หรือมากกว่านั้น) และพิมพ์ชื่อคลาส
Jonathan Ginsburg

โอเคฉันได้อัปเดตคำตอบด้วยเมตาคลาสที่น่าจะช่วยได้
Ned Batchelder

1
อะไรMyTypeอยู่ในsuperเส้นInputAssigningMetaclassหมายถึง?
58

16

คุณสามารถเข้าถึงได้โดยแอตทริบิวต์ส่วนตัวของคลาส:

cls_name = self.__class__.__name__

แก้ไข:

ตามที่กล่าวไว้Ned Batchelerสิ่งนี้จะไม่ได้ผลในเนื้อหาของชั้นเรียน แต่จะเป็นวิธีการ


12

PEP 3155นำมาใช้__qualname__ซึ่งนำมาใช้ใน Python 3.3

สำหรับฟังก์ชันและคลาสระดับบนสุด__qualname__แอตทริบิวต์จะเท่ากับ__name__แอตทริบิวต์ สำหรับคลาสเมธอดและฟังก์ชันที่ซ้อนกัน__qualname__แอ็ตทริบิวต์จะมีเส้นทางจุดที่นำไปสู่อ็อบเจ็กต์จากระดับบนสุดของโมดูล

สามารถเข้าถึงได้จากภายในนิยามของคลาสหรือฟังก์ชันตัวอย่างเช่น:

class Foo:
    print(__qualname__)

Fooได้อย่างมีประสิทธิภาพจะพิมพ์ คุณจะได้รับชื่อที่ผ่านการรับรองแบบเต็ม (ไม่รวมชื่อโมดูล) ดังนั้นคุณอาจต้องการแยกออกเป็น.ตัวอักษร

อย่างไรก็ตามไม่มีวิธีใดที่จะได้รับหมายเลขอ้างอิงจริงในคลาสที่กำหนดไว้

>>> class Foo:
...     print('Foo' in globals())
... 
False

7

แก้ไข:ใช่คุณสามารถ; แต่คุณต้องโกง: ชื่อคลาสที่กำลังรันอยู่ใน call stack และtracebackโมดูลช่วยให้คุณเข้าถึงสแต็กได้

>>> import traceback
>>> def get_input(class_name):
...     return class_name.encode('rot13')
... 
>>> class foo(object):
...      _name = traceback.extract_stack()[-1][2]
...     input = get_input(_name)
... 
>>> 
>>> foo.input
'sbb'

อย่างไรก็ตามฉันจะไม่ทำเช่นนี้ คำตอบเดิมของฉันยังคงเป็นความชอบของตัวเองในการแก้ปัญหา คำตอบเดิม:

อาจเป็นวิธีแก้ปัญหาที่ง่ายที่สุดคือการใช้มัณฑนากรซึ่งคล้ายกับคำตอบของเน็ดเกี่ยวกับเมตาแว่นตา แต่มีพลังน้อยกว่า (มัณฑนากรมีความสามารถในการใช้มนต์ดำ แต่ metaclasses สามารถใช้มนต์ดำโบราณลึกลับได้ )

>>> def get_input(class_name):
...     return class_name.encode('rot13')
... 
>>> def inputize(cls):
...     cls.input = get_input(cls.__name__)
...     return cls
... 
>>> @inputize
... class foo(object):
...     pass
... 
>>> foo.input
'sbb'
>>> 

1
import sys

def class_meta(frame):
    class_context = '__module__' in frame.f_locals
    assert class_context, 'Frame is not a class context'

    module_name = frame.f_locals['__module__']
    class_name = frame.f_code.co_name
    return module_name, class_name

def print_class_path():
    print('%s.%s' % class_meta(sys._getframe(1)))

class MyClass(object):
    print_class_path()

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