[英]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)
visitor
but I think it's a string. visitor
的数据类型,但我认为它是一个字符串。 visitor
gets assigned getattr
although I don't know what object it tries to get the attribute from. visitor
获得分配getattr
虽然我不知道它试图从哪个对象获取属性。 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
之后的下一个类是继承AST
的BinOp
:
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. visitor
是NodeVisitor
类的子类(您应该自己编写)的方法。 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_Expression
或visit_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.