2010-05-06 20 views
11

है, मैं उस विधि का नाम ढूंढने की कोशिश कर रहा हूं जिसमें विधि कोड है।क्लास का नाम जिसमें विधि कोड

नीचे उदाहरण में मैं self.__class__.__name__ का उपयोग करता हूं, लेकिन निश्चित रूप से यह उस वर्ग का नाम देता है जिसकी स्वयं एक उदाहरण है और कक्षा नहीं जिसमें test() विधि कोड शामिल है। b.test()'B' प्रिंट करेगा जबकि मैं 'A' प्राप्त करना चाहता हूं।

मैंने inspect मॉड्यूल दस्तावेज में देखा लेकिन सीधे कुछ भी उपयोगी नहीं मिला।

class A: 
    def __init__(self): 
    pass 
    def test(self): 
    print self.__class__.__name__ 

class B(A): 
    def __init__(self): 
    A.__init__(self) 



a = A() 
b = B() 

a.test() 
b.test() 
+1

आप इसे कोडिंग समय पर जानते हैं, नहीं? यह ए है: 'डीफ टेस्ट (स्वयं): प्रिंट "ए" '। –

+0

मैं कक्षा के नाम को दोहराने से बचना चाहता हूं। यदि मैं 'ए' से' एए 'तक कक्षा का नाम बदलता हूं तो मैं' प्रिंट 'ए' कथन को स्वीकार करने वाला पहला व्यक्ति बनूंगा। – user266940

उत्तर

7

अजगर 3.x, आप बस __class__.__name__ उपयोग कर सकते हैं। __class__ नाम हल्का जादू है, और self की विशेषता के समान नहीं है।

पायथन 2.x में, उस जानकारी को प्राप्त करने का कोई अच्छा तरीका नहीं है। आप कोड ऑब्जेक्ट प्राप्त करने के लिए स्टैक निरीक्षण का उपयोग कर सकते हैं, फिर कक्षा पदानुक्रम को सही विधि की तलाश में चलें, लेकिन यह धीमा और थकाऊ है और जब आप इसे नहीं चाहते हैं तो शायद तोड़ देगा। आप किसी भी तरह से कक्षा को पोस्ट-प्रोसेस करने के लिए मेटाक्लास या क्लास डेकोरेटर का भी उपयोग कर सकते हैं, लेकिन दोनों ही घुसपैठ के दृष्टिकोण हैं। और आप वास्तव में कुछ बदसूरत कर सकते हैं, self.__nonexistant_attribute तक पहुंचने, विशेषता Error को पकड़ने और गले लगाए गए नाम से कक्षा का नाम निकालने की तरह। यदि आप सिर्फ दो बार नाम लिखना नहीं चाहते हैं तो उनमें से कोई भी दृष्टिकोण वास्तव में इसके लायक नहीं है; कम से कम नाम को अपडेट करना भूल की तरह कुछ कर रही द्वारा एक छोटे से अधिक स्पष्ट किया जा सकता है:

class C: 
    ... 
    def report_name(self): 
     print C.__name__ 
4

inspect.getmro आप कक्षाएं जहां विधि क्रम में, से आ सकते हैं की एक टपल देता है। जैसे ही आप उनमें से एक को खोजने के अपने dict में विधि का नाम है, आपका काम हो गया:

for c in inspect.getmro(self.__class__): 
    if 'test' in vars(c): break 
return c.__name__ 
+1

दुर्भाग्य से यह आपको एमआरओ में पहली श्रेणी का नाम देता है जिसमें उस नाम के साथ एक विशेषता है, जो आवश्यक रूप से वही नहीं है जैसा आप कर रहे हैं (यदि आपकी विधि एमआरओ से आगे है।) –

+0

नाइस समाधान है, लेकिन यह काम नहीं करता है के रूप में थॉमस का उल्लेख है जब 'वर्ग b' को' परीक्षण ओवरराइड करता है() 'विधि: वर्ग एक: डीईएफ़ __init __ (स्वयं): पास डीईएफ़ परीक्षण (स्वयं): आयात का निरीक्षण के लिए inspect.getmro में ग (आत्म .__ class__): अगर वार्स में 'परीक्षण' (ग): तोड़ प्रिंट ग .__ name__ वर्ग बी (ए): +०१२३५१६४१०६डीईएफ़ __init __ (स्वयं): एक .__ init __ (स्वयं) डीईएफ़ परीक्षण (स्वयं): A.test (स्वयं) एक = एक() ख = बी() a.test() # प्रिंट्स b.test() # प्रिंट्स बी – user266940

+0

पिछली टिप्पणी में गड़बड़ी के लिए खेद है। यह मेरी पहली स्टैक ओवरफ्लो टिप्पणी है और मुझे टिप्पणियों में कोड जोड़ने की अक्षमता से अवगत नहीं था। – user266940

2

उपयोग वर्ग वस्तु के ही __dict__:

class A(object): 
    def foo(self): 
     pass 

class B(A): 
    pass 

def find_decl_class(cls, method): 
    if method in cls.__dict__: 
     return cls 
    for b in cls.__bases__: 
     decl = find_decl_class(b, method) 
     if decl: 
      return decl 

print 'foo' in A.__dict__ 
print 'foo' in B.__dict__ 
print find_decl_class(B, 'foo').__name__ 

यह सच है, झूठी प्रिंट, एक

+0

यह एलेक्स के एमआरओ समाधान के समान समस्या है। –

+0

सहमत हैं। लेकिन अगर यह पहले से ही ज्ञात है कि केवल एकल श्रेणी की विरासत होगी, समाधान ठीक और सरल है। नोट के लिए धन्यवाद। – nkrkv

2

इस प्रभाव को पूरा करने के लिए आप (दुरुपयोग?) private name mangling का उपयोग कर सकते हैं। यदि आप self पर एक विशेषता देखते हैं जो __ से किसी विधि के अंदर से शुरू होता है, तो पाइथन __attribute से _classThisMethodWasDefinedIn__attribute पर नाम बदलता है।

बस किसी भी तरह से उस वर्गनाम को छेड़छाड़ करें जिसे आप मंगल-रूप में चाहते हैं जहां विधि इसे देख सकती है।

def mangle(cls, attrname): 
    if not attrname.startswith('__'): 
     raise ValueError('attrname must start with __') 
    return '_%s%s' % (cls.__name__, attrname) 

class A(object): 

    def __new__(cls, *args, **kwargs): 
     obj = object.__new__(cls) 
     for c in cls.mro(): 
      setattr(obj, mangle(c, '__defn_classname'), c.__name__) 
     return obj 

    def __init__(self): 
     pass 

    def test(self): 
     print self.__defn_classname 

class B(A): 

    def __init__(self): 
     A.__init__(self) 



a = A() 
b = B() 

a.test() 
b.test() 

जो प्रिंट: एक उदाहरण के रूप में, हम आधार वर्ग करता है पर एक __new__ विधि यह परिभाषित कर सकते हैं ध्यान रखें

A 
A 
0

आप

>>> class A(object): 
... def __init__(self): 
...  pass 
... def test(self): 
...  for b in self.__class__.__bases__: 
...  if hasattr(b, 'test'): 
...   return b.__name__ 
...  return self.__class__.__name__ 
... 
>>> class B(A): 
... def __init__(self): 
...  A.__init__(self) 
... 
>>> B().test() 
'A' 
>>> A().test() 
'A' 
>>> 

कर सकते हैं कि आप __class__.__base__ का उपयोग कर इसे सरल बना सकते हैं, लेकिन यदि आप एकाधिक विरासत का उपयोग करते हैं, तो यह संस्करण बेहतर काम करेगा।

यह test के लिए बस अपने बेसक्लास पर पहले जांचता है। यह सबसे सुंदर नहीं है, लेकिन यह काम करता है।

संबंधित मुद्दे