简体   繁体   English

这个Python变量的数据类型是什么:node(抽象语法树)

[英]What is the datatype of this Python variable: node (Abstract Syntax Tree)

I'm building my own interpreter in C# using Ruslan Pavik's Guide . 我正在使用Ruslan Pavik的指南在C#中构建自己的解释器。 I am at part 7 where we are creating an Abstract Syntax Tree. 我在第7部分,我们正在创建一个抽象语法树。 I was able to get by the first parts and was able to translate the Python code in the guide into C#. 我能够通过第一部分获得并能够将指南中的Python代码翻译成C#。 But in Part 7, it became entirely difficult for a guy with no Python experience. 但在第7部分中,对于没有Python经验的人来说变得非常困难。

I am having difficulty figuring out what the datatypes and the return types are, with Python being a dynamic programming language. 我很难弄清楚数据类型和返回类型是什么,Python是一种动态编程语言。

I am confused on this part: 我对这部分感到困惑:

 def visit(self, node):
    method_name = 'visit_' + type(node).__name__
    visitor = getattr(self, method_name, self.generic_visit)
    return visitor(node)
  1. I don't know the datatype for visitor but I think it's a string. 我不知道visitor的数据类型,但我认为它是一个字符串。
  2. visitor gets assigned getattr although I don't know what object it tries to get the attribute from. visitor获得分配getattr虽然我不知道它试图从哪个对象获取属性。
  3. I don't know what datatype does node have. 我不知道node有什么数据类型。

Later on in the guide, he declares this class: 后来在指南中,他宣布了这堂课:

class AST(object):
pass

But I know that in C# it's just a class with nothing inside the braces: public class AST { } . 但是我知道在C#中它只是一个在大括号内没有任何内容的public class AST { }public class AST { }

The next class after AST is the BinOp that inherits AST : AST之后的下一个类是继承ASTBinOp

class BinOp(AST):
def __init__(self, left, op, right):
    self.left = left
    self.token = self.op = op
    self.right = right

Basically I'm really confused right now. 基本上我现在真的很困惑。 But my main confusion is the node since I don't know what datatype it has. 但我的主要困惑是node因为我不知道它有什么数据类型。 Since a lot of classes in the parser and interpreter use node , I really can't go forward in my interpreter without knowing what datatype it has. 由于解析器和解释器中的许多类都使用node ,因此我真的不能在我的解释器中继续前进而不知道它具有什么数据类型。

node is an instance of a subclass of AST here. node是这里AST的子类的实例。 visitor is a method on a subclass (which you are supposed to write yourself) of the NodeVisitor class. visitorNodeVisitor类的子类(您应该自己编写)的方法。 It is looked up dynamically because the passed in node is going to be any one of the possible subclasses of AST , and you are expected to implement specific visit_ methods for specific nodes on your custom subclass. 它是动态查找的,因为传入的node将是AST任何一个可能的子类,并且您应该为自定义子类上的特定节点实现特定的visit_方法。 The fallback is to use the self.generic_visit method. 后备是使用self.generic_visit方法。

AST is the base class for nodes. AST是节点的基类。 BinOp is a specific node class; BinOp是一个特定的节点类; the different classes are documented in the Abstract Grammar section ; 摘要语法部分记录了不同的类; each camel-cased name is also an AST subclass. 每个camel-cased名称也是AST子类。

By looking up methods dynamically by the name of the specific node, the developers avoided having to create specific concrete methods for every node type that the grammar defines. 通过按特定节点的名称动态查找方法,开发人员避免必须为语法定义的每个节点类型创建特定的具体方法。

To make this a little more concrete: say you are interested in specific BinOp operator nodes; 为了使这更具体:说你对特定的BinOp运算符节点感兴趣; perhaps because you want to analyse how + is used in a piece of code. 也许是因为你想分析一段代码中如何使用+

You can then implement a NodeVisitor subclass, and add a visit_BinOp() method on that subclass, and it'll be called automatically when you pass in a tree of nodes to NodeVisitorSubclass().visit(toplevel_node) ; 然后,您可以实现NodeVisitor子类,并在该子类上添加visit_BinOp()方法,并在将节点传递给NodeVisitorSubclass().visit(toplevel_node)时自动调用它visit_BinOp() NodeVisitorSubclass().visit(toplevel_node) ; for any nodes for which there is no specific visit_* method present, the NodeVisitor.generic_visit() method will make sure the child nodes of the tree are visited (through the iter_fields() function). 对于没有特定visit_*方法的任何节点, NodeVisitor.generic_visit()方法将确保访问树的子节点(通过iter_fields()函数)。

Demo: 演示:

>>> import ast
>>> class DemoVisitor(ast.NodeVisitor):
...     def visit_BinOp(self, binop_node):
...         if isinstance(binop_node.op, ast.Add):
...             print('Found addition of {} and {}'.format(
...                 ast.dump(binop_node.left), ast.dump(binop_node.right)))
...
>>> tree = ast.parse('function(foo + bar)', '', 'eval')
>>> ast.dump(tree)
"Expression(body=Call(func=Name(id='function', ctx=Load()), args=[BinOp(left=Name(id='foo', ctx=Load()), op=Add(), right=Name(id='bar', ctx=Load()))], keywords=[]))"
>>> DemoVisitor().visit(tree)
Found addition of Name(id='foo', ctx=Load()) and Name(id='bar', ctx=Load())

In the above demo, the NodeWalker.visit() method found the visit_BinOp method and called it for us, but since there are no visit_Expression or visit_Call , etc. methods, those nodes were passed to the NodeWalker.generic_visit() method instead, which processes each field and calls self.visit() for any further nodes. 在上面的演示中, NodeWalker.visit()方法找到了visit_BinOp方法并为我们调用了它,但由于没有visit_Expressionvisit_Call等方法,所以这些节点被传递给NodeWalker.generic_visit()方法,处理每个字段并为任何其他节点调用self.visit()

Regarding your question about getattr : This is just a function which returns an attribute with a given name (in the 2nd parameter) of an object (in the 1st parameter) and with a fall back (in the 3rd parameter) if there is no attribute. 关于你关于getattr的问题:这只是一个函数,它返回一个具有给定名称(在第二个参数中)的对象(在第一个参数中)和一个回退(在第三个参数中)的属性,如果没有属性。

So in your case getattr(self, method_name, self.generic_visit) it tries to get an attribute with the name method_name from itself. 因此,在您的情况下, getattr(self, method_name, self.generic_visit)会尝试从其自身获取名称为method_name的属性。 And if it doesn't exist it uses self.generic_visit . 如果它不存在,则使用self.generic_visit Now if method_name is "visit_BinOp" , it'll try to get self.visit_BinOp , and if that doesn't exist it'll instead get self.generic_visit . 现在,如果method_name"visit_BinOp" ,它将尝试获取self.visit_BinOp ,如果不存在,它将改为获得self.generic_visit

In the end, without running the code, it cannot be determined what it'll return or what type visitor is going to be. 最后,如果不运行代码,就无法确定它将返回什么类型或visitor将会是什么类型。 It could be anything in theory, but usually it is a method. 它可以是理论上的任何东西,但通常它是一种方法。 But that is a difference from Python and C#, that the type of a variables in Python depends on what is assigned to it. 但这与Python和C#不同,Python中变量的类型取决于分配给它的内容。 You can do the following without an issue: 您可以执行以下操作而不会出现问题:

i = 42
# i is now an int, but you can easily overwrite it with a string
i = "Hello World"

And the same is with node , in theory it can be anything, but if used correctly it'll be a subclass of AST . 同样是node ,理论上它可以是任何东西,但如果使用正确,它将是AST的子类。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM