2011-12-16 16 views
11

मान लीजिए हम निम्नलिखित वर्ग पदानुक्रम है: अगर मैं ऐसा तरह ClassB पर __ __ dict का पता लगानेक्या __dict__ (या ऐसा कुछ) तक पहुंचने का कोई तरीका है जिसमें बेस क्लास शामिल हैं?

class ClassA: 

    @property 
    def foo(self): return "hello" 

class ClassB(ClassA): 

    @property 
    def bar(self): return "world" 

, मैं सिर्फ बार विशेषता देखें:

for name,_ in ClassB.__dict__.items(): 

    if name.startswith("__"): 
     continue 

    print(name) 

आउटपुट बार

है

मैं न केवल निर्दिष्ट प्रकार बल्कि इसके पूर्वजों पर विशेषताओं को प्राप्त करने के लिए अपने स्वयं के साधन रोल कर सकता हूं। हालांकि, मेरा सवाल यह है कि क्या मेरे लिए एक पहिया का पुन: आविष्कार किए बिना ऐसा करने के लिए पहले से ही पाइथन में एक तरीका है।

def return_attributes_including_inherited(type): 
    results = [] 
    return_attributes_including_inherited_helper(type,results) 
    return results 

def return_attributes_including_inherited_helper(type,attributes): 

    for name,attribute_as_object in type.__dict__.items(): 

     if name.startswith("__"): 
      continue 

     attributes.append(name) 

    for base_type in type.__bases__: 
     return_attributes_including_inherited_helper(base_type,attributes) 

मेरे कोड चल रहा है इस प्रकार है ...

for attribute_name in return_attributes_including_inherited(ClassB): 
    print(attribute_name) 

... दोनों बार और foo वापस देता है।

ध्यान दें कि मैं कुछ चीजों को सरल बना रहा हूं: आइटम टकराव, वस्तुओं का उपयोग करके() इस उदाहरण के लिए जब मैं __ से शुरू होने वाली किसी भी चीज पर छोड़ देता हूं, तो संभावना है कि दो पूर्वजों के पास एक आम पूर्वज है, आदि।

EDIT1 - मैंने उदाहरण को सरल रखने की कोशिश की। लेकिन मैं वास्तव में प्रत्येक वर्ग और पूर्वजों वर्ग के लिए विशेषता नाम और विशेषता संदर्भ दोनों चाहता हूं। नीचे दिए गए उत्तरों में से एक ने मुझे एक बेहतर ट्रैक पर रखा है, जब मैं इसे काम करने के लिए कुछ बेहतर कोड पोस्ट करूंगा।

EDIT2 - यह वही करता है जो मैं चाहता हूं और बहुत संक्षिप्त है। यह नीचे एली के जवाब पर आधारित है।

def get_attributes(type): 

    attributes = set(type.__dict__.items()) 

    for type in type.__mro__: 
     attributes.update(type.__dict__.items()) 

    return attributes 

यह विशेषता नाम और उनके संदर्भ दोनों को वापस देता है।

EDIT3 - inspect.getmembers का उपयोग करके सुझाए गए उत्तरों में से एक। यह बहुत उपयोगी प्रतीत होता है क्योंकि यह केवल ताना की तरह है, यह केवल पूर्वजों के वर्गों पर भी चलता है।

class MyCustomDescriptor: 

    # This is greatly oversimplified 

    def __init__(self,foo,bar): 
     self._foo = foo 
     self._bar = bar 
     pass 

    def __call__(self,decorated_function): 
     return self 

    def __get__(self,instance,type): 

     if not instance: 
      return self 

     return 10 

class ClassA: 

    @property 
    def foo(self): return "hello" 

    @MyCustomDescriptor(foo="a",bar="b") 
    def bar(self): pass 

    @MyCustomDescriptor(foo="c",bar="d") 
    def baz(self): pass 

class ClassB(ClassA): 

    @property 
    def something_we_dont_care_about(self): return "world" 

    @MyCustomDescriptor(foo="e",bar="f") 
    def blah(self): pass 

# This will get attributes on the specified type (class) that are of matching_attribute_type. It just returns the attributes themselves, not their names. 
def get_attributes_of_matching_type(type,matching_attribute_type): 

    return_value = [] 

    for member in inspect.getmembers(type): 

     member_name = member[0] 
     member_instance = member[1] 

     if isinstance(member_instance,matching_attribute_type): 
      return_value.append(member_instance) 

    return return_value 

# This will return a dictionary of name & instance of attributes on type that are of matching_attribute_type (useful when you're looking for attributes marked with a particular descriptor) 
def get_attribute_name_and_instance_of_matching_type(type,matching_attribute_type): 

    return_value = {} 

    for member in inspect.getmembers(ClassB): 

     member_name = member[0] 
     member_instance = member[1] 

     if isinstance(member_instance,matching_attribute_type): 
      return_value[member_name] = member_instance 

    return return_value 
+0

वास्तव में क्या आप एक बार तुम्हारे पास है विशेषता सूची के साथ क्या करने जा रहे हैं? –

+0

प्रश्न में कक्षाएं संदेश का प्रतिनिधित्व करती हैं जो deserialized किया गया है। संदेश फ़ील्ड साझा करते समय विरासत का उपयोग करते हैं। एक विधि है जिसे प्रत्येक संदेश के प्रत्येक फ़ील्ड के बारे में जानकारी प्रिंट करने की आवश्यकता होती है। इन संदेश वर्गों की प्रत्येक विशेषता वास्तव में एक वर्णक के साथ चिह्नित की जाती है लेकिन मैंने उस विवरण को छोड़ दिया क्योंकि मैंने सोचा था कि यह अप्रासंगिक था। –

+0

... तो, वर्णनकर्ता को अद्यतन करें ताकि यह वर्णित विशेषता को किसी सूची में जोड़ सके? या - और यह थोड़ा बहुत कट्टरपंथी हो सकता है - अलग-अलग गुणों के बजाय स्ट्रिंग कुंजियों वाला एक नियम का उपयोग करें? –

उत्तर

9

आप किसी भी तरह के आत्मविश्लेषी क्षमताओं के लिए अजगर के inspect मॉड्यूल का उपयोग करना चाहिए।

. 
. 
>>> class ClassC(ClassB): 
...  def baz(self): 
...   return "hiya" 
... 
>>> import inspect 
>>> for attr in inspect.getmembers(ClassC): 
... print attr 
... 
('__doc__', None) 
('__module__', '__main__') 
('bar', <property object at 0x10046bf70>) 
('baz', <unbound method ClassC.baz>) 
('foo', <property object at 0x10046bf18>) 

inspect मॉड्यूल here बारे में अधिक पढ़ें।

+0

स्वीट, यह dict के बेहतर संस्करण की तरह है क्योंकि जबकि कक्षा सिर्फ वर्ग पर चलती है, निरीक्षण करें .getmembers पूर्वजों पर भी काम करता प्रतीत होता है। मैं इस तकनीक का उपयोग कर अपने मूल दृष्टिकोण पर कुछ अतिरिक्त कोड नमूने पोस्ट करूंगा। –

5
:

के बाद से मुझे क्या करना है कोशिश कर रहा था का एक बड़ा हिस्सा एक विशेष वर्णनकर्ता के साथ चिह्नित गुण मिल जाए, और पूर्वजों कक्षाएं शामिल था, यहाँ कुछ कोड है कि उस मामले में यह किसी को भी मदद करता है ऐसा करने में मदद मिलेगी है

आप dir उपयोग करना चाहते हैं:

for attr in dir(ClassB): 
    print attr 
+0

दिलचस्प। मैं dir() बस वापस __dict__ से चाबी दे दी मान लिया लेकिन तुम सही हो, एक प्रमुख अंतर यह है कि निर्देशिका() वर्ग और उसके सभी पूर्वजों पर चल रही है, जबकि __dict__ सिर्फ वर्ग (नहीं अपने पूर्वजों) पर संचालित करने के लिए लगता है। मुझे विशेषताओं तक पहुंच की आवश्यकता है (केवल नाम नहीं) लेकिन ऐसा लगता है कि मैं dir() और getattr() के संयोजन का उपयोग कर सकता हूं। धन्यवाद! –

+1

Yep 'dir()' और 'gettattr()' इसके बारे में जाने का सामान्य तरीका है। – zeekay

+0

सिडेनोटे: 'निरीक्षण' मॉड्यूल वह है जो मुझे विश्वास है कि dir() कमांड बनाया गया है। मुझे लगता है कि यह ऑब्जेक्ट के "सभी पहुंच योग्य गुण" को खोजने के लिए mro और getmembers() का उपयोग करता है। – jdi

2

दुर्भाग्य से वहाँ एक भी समग्र वस्तु नहीं है। एक (सामान्य) पायथन ऑब्जेक्ट के लिए प्रत्येक विशेषता पहुंच पहले obj.__dict__ की जांच करती है, फिर उसके सभी बेस क्लास के गुण; जबकि कुछ आंतरिक कैश और अनुकूलन हैं, वहां एक भी वस्तु नहीं है जिसे आप एक्सेस कर सकते हैं।

जिसके अनुसार, एक बात है कि अपने कोड को बेहतर बना सकते बजाय वर्ग के तत्काल माता-पिता की cls.__bases__ के बजाय cls.__mro__ उपयोग करने के लिए ... है, cls.__mro__ वर्ग के सभी पूर्वजों, सटीक क्रम अजगर खोज करेंगे, सभी के साथ होता है आम पूर्वजों को केवल एक बार होता है। यह आपकी टाइप-सर्चिंग विधि को गैर-पुनरावर्ती होने की अनुमति भी देगा। ढीले ...

def get_attrs(obj): 
    attrs = set(obj.__dict__) 
    for cls in obj.__class__.__mro__: 
     attrs.update(cls.__dict__) 
    return sorted(attrs) 

...डिफ़ॉल्ट dir(obj) कार्यान्वयन का उचित अनुमान है।

+0

ओह, यह जानना बहुत अच्छा है! लगता है कि मेरे पास अब दो विकल्प हैं। zeekay dir() (जिसमें पूर्वजों के वर्गों के गुण नाम शामिल थे) का उपयोग करने का सुझाव दिया गया है, हालांकि मुझे प्रत्येक नाम पर getattr() की आवश्यकता होगी। या मैं आपकी विधि का उपयोग कर सकता था। मेरे उदाहरण में यह प्रतीत होता है कि मुझे केवल विशेषता नामों की आवश्यकता है, लेकिन हकीकत में मुझे विशेषताओं के संदर्भों की आवश्यकता है। तो मुझे लगता है कि मैं आपके कोड का उपयोग करूंगा। धन्यवाद! –

+0

इसके अलावा, __mro__ पर टिप के लिए धन्यवाद। मुझे लगता है कि मैंने किसी को इसका इस्तेमाल किया होगा लेकिन मुझे नहीं पता था कि यह क्या था। यह बहुत आसान है! –

+0

तो यह सिर्फ विशेषता नाम वापस देता है, है ना? मैं अभी दोनों विशेषता नामों और उनके संदर्भों को वापस देने के लिए इसे संशोधित करने पर काम कर रहा हूं। यदि आपके पास ऐसा करने के लिए पहले से कुछ है, तो क्या आप इसे पोस्ट कर सकते हैं? –

1

यहाँ एक समारोह मैंने लिखा, दिन में वापस आ गया है। सबसे अच्छा जवाब है, inspect मॉड्यूल उपयोग कर रहा है के रूप में __dict__ का उपयोग करके हमसे सभी कार्यों देता है (हमारा + विरासत में मिला है) और (सभी?) डेटा के सदस्यों और गुण। जहां inspect हमें वही जानकारी देता है जो हम नहीं चाहते हैं। जब ClassB उदाहरण का उपयोग करते हुए (<property object...> के बजाय)

def _inspect(a, skipFunctionsAlways=True, skipMagic = True): 
    """inspects object attributes, removing all the standard methods from 'object', 
    and (optionally) __magic__ cruft. 

    By default this routine skips __magic__ functions, but if you want these on 
    pass False in as the skipMagic parameter. 

    By default this routine skips functions, but if you want to see all the functions, 
    pass in False to the skipFunctionsAlways function. This works together with the 
    skipMagic parameter: if the latter is True, you won't see __magic__ methods. 
    If skipFunctionsAlways = False and skipMagic = False, you'll see all the __magic__ 
    methods declared for the object - including __magic__ functions declared by Object 

    NOT meant to be a comprehensive list of every object attribute - instead, a 
    list of every object attribute WE (not Python) defined. For a complete list 
    of everything call inspect.getmembers directly""" 

    objType = type(object) 
    def weWantIt(obj): 
     #return type(a) != objType 
     output= True 
     if (skipFunctionsAlways): 
      output = not (inspect.isbuiltin(obj)) #not a built in 

     asStr = "" 
     if isinstance(obj, types.MethodType): 
      if skipFunctionsAlways: #never mind, we don't want it, get out. 
       return False 
      else: 
       asStr = obj.__name__ 
       #get just the name of the function, we don't want the whole name, because we don't want to take something like: 
       #bound method LotsOfThings.bob of <__main__.LotsOfThings object at 0x103dc70> 
       #to be a special method because it's module name is special 
       #WD-rpw 02-23-2008 

       #TODO: it would be great to be able to separate out superclass methods 
       #maybe by getting the class out of the method then seeing if that attribute is in that class? 
     else: 
      asStr = str(obj) 

     if (skipMagic): 
      output = (asStr.find("__") == -1) #not a __something__ 

     return (output) 

    for value in inspect.getmembers(a, weWantIt): 
     yield value 
+0

इसे पोस्ट करने के लिए धन्यवाद! –

0
{k: getattr(ClassB, k) for k in dir(ClassB)} 

उचित मूल्यों प्रस्तुत किया जाएगा।

और निश्चित रूप से आप अंत में if not k.startswith('__') तरह बातें जोड़कर इस फ़िल्टर कर सकते हैं।

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