2011-12-01 15 views
7

मैं "मजेदार और लाभ" के लिए पायथन कोड द्वारा उत्पन्न एएसटी का विश्लेषण कर रहा हूं, और वास्तव में एएसटी जेनरेट करने के लिए "ast.dump" से कुछ और ग्राफिकल होना चाहता हूं।पायथन अल्ट ग्राफ

सिद्धांत में पहले से ही एक पेड़ है, इसलिए ग्राफ बनाने के लिए यह बहुत कठिन नहीं होना चाहिए, लेकिन मुझे समझ में नहीं आता कि मैं इसे कैसे कर सकता हूं।

ast.walk एक BFS रणनीति के साथ चलने के लिए लगता है, और visitX तरीकों मैं वास्तव में माता-पिता को नहीं देख सकते या मैं रेखाचित्र बनाने के लिए एक रास्ता खोजने के लिए नहीं लग रहे ...

ऐसा लगता है जैसे ही मेरा खुद का डीएफएस चलना फ़ंक्शन लिखना है, क्या यह समझ में आता है?

उत्तर

6

यदि आप Ast.NodeVisitor को देखते हैं, तो यह काफी मामूली कक्षा है। आप या तो इसे उपclass कर सकते हैं या अपनी जरूरत की रणनीति के लिए बस अपनी चलती रणनीति को फिर से लागू कर सकते हैं। उदाहरण के लिए, जब नोड्स का दौरा किया जाता है तो माता-पिता के संदर्भों को ध्यान में रखना बहुत आसान है, बस visit विधि जोड़ें जो माता-पिता को तर्क के रूप में स्वीकार करता है, और इसे अपने generic_visit से पास करता है।

पीएस वैसे, ऐसा लगता है कि NodeVisitor.generic_visit डीएफएस लागू करता है, इसलिए आपको केवल इतना करना है कि पैरेंट नोड पास हो।

+0

हाँ, आप कर रहे हैं सही एक बहुत ही सरल कार्यान्वयन है, मैं पहले सोचा था कि मैं सभी संभव मामलों की जांच करने के लिए किया था कि, लेकिन वास्तव में पता चल सके कि यह एक सूची है पहले से ही काफी पेड़ के माध्यम से चलने के लिए है या नहीं .. धन्यवाद बहुत –

6

बढ़िया, यह काम करता है और यह वास्तव में सरल

class AstGraphGenerator(object): 

    def __init__(self): 
     self.graph = defaultdict(lambda: []) 

    def __str__(self): 
     return str(self.graph) 

    def visit(self, node): 
     """Visit a node.""" 
     method = 'visit_' + node.__class__.__name__ 
     visitor = getattr(self, method, self.generic_visit) 
     return visitor(node) 

    def generic_visit(self, node): 
     """Called if no explicit visitor function exists for a node.""" 
     for _, value in ast.iter_fields(node): 
      if isinstance(value, list): 
       for item in value: 
        if isinstance(item, ast.AST): 
         self.visit(item) 

      elif isinstance(value, ast.AST): 
       self.graph[type(node)].append(type(value)) 
       self.visit(value) 

तो यह एक सामान्य NodeVisitor के रूप में ही है, लेकिन मैं एक defaultdict जहां मैं एक बेटे के लिए नोड के प्रकार जोड़ने की है। फिर मैं इस शब्दकोश को pygraphviz.AGraph में पास करता हूं और मुझे अपना अच्छा परिणाम मिलता है।

एकमात्र समस्या यह है कि प्रकार बहुत कुछ नहीं कहता है, लेकिन दूसरी तरफ ast.dump() का उपयोग करना भी वर्बोज़ है।

प्रत्येक नोड के लिए वास्तविक स्रोत कोड प्राप्त करना सबसे अच्छा बात है, क्या यह संभव है?

संपादित करें: अब यह बेहतर है, मैं कन्स्ट्रक्टर में स्रोत कोड भी पास करता हूं और यदि संभव हो तो मैं कोड लाइन प्राप्त करने का प्रयास करता हूं, अन्यथा बस प्रकार को प्रिंट करें।

class AstGraphGenerator(object): 

    def __init__(self, source): 
     self.graph = defaultdict(lambda: []) 
     self.source = source # lines of the source code 

    def __str__(self): 
     return str(self.graph) 

    def _getid(self, node): 
     try: 
      lineno = node.lineno - 1 
      return "%s: %s" % (type(node), self.source[lineno].strip()) 

     except AttributeError: 
      return type(node) 

    def visit(self, node): 
     """Visit a node.""" 
     method = 'visit_' + node.__class__.__name__ 
     visitor = getattr(self, method, self.generic_visit) 
     return visitor(node) 

    def generic_visit(self, node): 
     """Called if no explicit visitor function exists for a node.""" 
     for _, value in ast.iter_fields(node): 
      if isinstance(value, list): 
       for item in value: 
        if isinstance(item, ast.AST): 
         self.visit(item) 

      elif isinstance(value, ast.AST): 
       node_source = self._getid(node) 
       value_source = self._getid(value) 
       self.graph[node_source].append(value_source) 
       # self.graph[type(node)].append(type(value)) 
       self.visit(value) 
संबंधित मुद्दे