سؤال

هل لدى أي شخص مثال بسيط باستخدام AST.NODEVITITOR للمشي شجرة بناء الجملة مجردة في بيثون 2.6؟ الفرق بين الزيارة والأعمار_Visit غير واضح بالنسبة لي، ولا يمكنني العثور على أي مثال باستخدام Google Codesearch أو Google عادي.

هل كانت مفيدة؟

المحلول

ast.visit - ما لم تتجاوزه في فئة فرعية، بالطبع - عند دعا لزيارة ast.Node من صنف foo, ، المكالمات self.visit_foo إذا كانت هذه الطريقة موجودة، وإلا self.generic_visit. وبعد هذا الأخير، مرة أخرى في تنفيذها في الفصل ast نفسه، فقط يدعو self.visit على كل عقدة الطفل (ويعمل أي إجراء آخر).

لذلك، اعتبر، على سبيل المثال:

>>> class v(ast.NodeVisitor):
...   def generic_visit(self, node):
...     print type(node).__name__
...     ast.NodeVisitor.generic_visit(self, node)
... 

هنا، نحن نتجاوز generic_visit لطباعة اسم الفصل، ولكن أيضا الدعوة إلى الفئة الأساسية (حتى تتم زيارة جميع الأطفال أيضا). لذلك على سبيل المثال ...:

>>> x = v()
>>> t = ast.parse('d[x] += v[y, x]')
>>> x.visit(t)

تنبعث منها:

Module
AugAssign
Subscript
Name
Load
Index
Name
Load
Store
Add
Subscript
Name
Load
Index
Tuple
Name
Load
Name
Load
Load
Load

لكن لنفترض أننا لم نهتم بعقد حمل (وأطفال منها - إذا كان لديهم أي ؛-). ثم طريقة بسيطة للتعامل مع ذلك قد تكون، على سبيل المثال:

>>> class w(v):
...   def visit_Load(self, node): pass
... 

الآن عندما نستمر عقدة الحمل، visit إفرازات، وليس ل generic_visit أي أكثر، ولكن لدينا الجديد visit_Load... التي لا تفعل أي شيء على الإطلاق. وبالتالي:

>>> y = w()
>>> y.visit(t)
Module
AugAssign
Subscript
Name
Index
Name
Store
Add
Subscript
Name
Index
Tuple
Name
Name

أو لنفترض أننا أردنا أيضا أن نرى الأسماء الفعلية لعقد الاسم؛ ومن بعد...:

>>> class z(v):
...   def visit_Name(self, node): print 'Name:', node.id
... 
>>> z().visit(t)
Module
AugAssign
Subscript
Name: d
Index
Name: x
Store
Add
Subscript
Name: v
Index
Tuple
Name: y
Name: x
Load
Load

لكن nodeevisitor هو فئة لأن هذا يتيح لها تخزين المعلومات أثناء الزيارة. لنفترض أن كل ما نريده هو مجموعة الأسماء في "وحدة". ثم لا نحتاج إلى تجاوز generic_visit أي أكثر، ولكن ...:

>>> class allnames(ast.NodeVisitor):
...   def visit_Module(self, node):
...     self.names = set()
...     self.generic_visit(node)
...     print sorted(self.names)
...   def visit_Name(self, node):
...     self.names.add(node.id)
... 
>>> allnames().visit(t)
['d', 'v', 'x', 'y']

هذا النوع من الأشياء هو حالة استخدام أكثر نموذجية من تلك التي تتطلب تجاوزات generic_visit - عادة، أنت مهتم فقط ببعض أنواع العقد، كما نحن هنا في الوحدة النمطية والاسم، لذلك يمكننا تجاوز visit_Module و visit_Name واترك AST visit هل الإرسال نيابة عنا.

نصائح أخرى

النظر في الكود في AST.PY. ليس من الصعب نسخ معجون ولف جهاز Walker الخاص بك. على سبيل المثال

import ast
def str_node(node):
    if isinstance(node, ast.AST):
        fields = [(name, str_node(val)) for name, val in ast.iter_fields(node) if name not in ('left', 'right')]
        rv = '%s(%s' % (node.__class__.__name__, ', '.join('%s=%s' % field for field in fields))
        return rv + ')'
    else:
        return repr(node)
def ast_visit(node, level=0):
    print('  ' * level + str_node(node))
    for field, value in ast.iter_fields(node):
        if isinstance(value, list):
            for item in value:
                if isinstance(item, ast.AST):
                    ast_visit(item, level=level+1)
        elif isinstance(value, ast.AST):
            ast_visit(value, level=level+1)


ast_visit(ast.parse('a + b'))

يطبع خارج

Module(body=[<_ast.Expr object at 0x02808510>])
  Expr(value=BinOp(op=Add()))
    BinOp(op=Add())
      Name(id='a', ctx=Load())
        Load()
      Add()
      Name(id='b', ctx=Load())
        Load()

generic_visit يسمى عندما لا يمكن العثور على زائر مخصص (أي visit_name). إليك قطعة من التعليمات البرمجية كتبت مؤخرا مع AST.NODEVISTOR: https://bitbucket.org/pypy/pypy/src/6df19fd2b6df6058daf162100cf7ee4521de5259/py/_code/_assertionnew.py؟at=default&fileviewer=file-View-View-Default. يفسر عقد AST للحصول على معلومات تصحيح الأخطاء حول بعضها ويندرج generic_visit عند تنفيذ تنفيذ خاص.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top