Python中的符号表

17

如何查看Python源代码的符号表?

我的意思是,在实际运行程序之前,Python会为每个程序创建一个符号表。那么我的问题是,如何将该符号表作为输出获取?


4
你认为Python如何生成符号表? - Winston Ewert
5
@WinstonEwert :: http://docs.python.org/library/symtable.html - Rahul Gupta
Python在各个命名空间级别维护符号表的相关帖子 - globals(),locals()和vars()有什么区别? - RBT
4个回答

11

Python的特性是动态而非静态。虚拟机具有可寻址命名空间,而不是编译对象代码中的符号表,用于存储变量。

dir()dir(module)函数返回代码在该点处的有效命名空间。它主要用于交互式解释器,但也可以被代码使用。它返回一个字符串列表,其中每个字符串都是带有某些值的变量。

globals()函数返回一个变量名到变量值的字典,其中变量名在该时刻被认为是全局范围内的。

locals()函数返回一个变量名到变量值的字典,其中变量名在该时刻被认为是局部范围内的。

$ python
Python 2.6.5 (r265:79063, Apr 16 2010, 13:57:41)
[GCC 4.4.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> locals()
{'__builtins__': <module '__builtin__' (built-in)>, '__name__': '__main__', '__doc__': None, '__package__': None}
>>> globals()
{'__builtins__': <module '__builtin__' (built-in)>, '__name__': '__main__', '__doc__': None, '__package__': None}
>>> dir()
['__builtins__', '__doc__', '__name__', '__package__']
>>> import base64
>>> dir(base64)
['EMPTYSTRING', 'MAXBINSIZE', 'MAXLINESIZE', '__all__', '__builtins__', '__doc__', '__file__', '__name__', '__package__', '_b32alphabet', '_b32rev', '_b32tab', '_translate', '_translation', '_x', 'b16decode', 'b16encode', 'b32decode', 'b32encode', 'b64decode', 'b64encode', 'binascii', 'decode', 'decodestring', 'encode', 'encodestring', 'k', 're', 'standard_b64decode', 'standard_b64encode', 'struct', 'test', 'test1', 'urlsafe_b64decode', 'urlsafe_b64encode', 'v']

@voithos 他特别询问了Python源代码的问题。我没有使用过那个模块,但我相信它是用于访问VM内部或C扩展内部的,这与其它不同。 - wberry
@voithos 但也许他真的是指虚拟机内部。我认为你应该把它发表为一个答案。 - wberry
不确定这里发生了什么,但符号表实际上是CPython编译器的重要资源,而语言的"动态性"与手头的问题无关。这个回答没有回答到提问者的问题。 - undefined
之前有关此事的评论现已被澄清。 - undefined

11
如果您询问的是生成字节码时使用的符号表,请查看symtable模块。此外,Eli Bendersky撰写的这两篇文章非常有趣且详细:

Python Internals: Symbol tables, part 1

Python Internals: Symbol tables, part 2

在第二部分中,他详细介绍了一个函数,可以打印出符号表的描述,但它似乎是为Python 3编写的。以下是适用于Python 2.x的版本:
def describe_symtable(st, recursive=True, indent=0):
    def print_d(s, *args):
            prefix = ' ' *indent
            print prefix + s + ' ' + ' '.join(args)

    print_d('Symtable: type=%s, id=%s, name=%s' % (
            st.get_type(), st.get_id(), st.get_name()))
    print_d('  nested:', str(st.is_nested()))
    print_d('  has children:', str(st.has_children()))
    print_d('  identifiers:', str(list(st.get_identifiers())))

    if recursive:
            for child_st in st.get_children():
                    describe_symtable(child_st, recursive, indent + 5)

4

在程序执行之前,Python不会创建符号表。实际上,类型和函数可以在执行期间(通常是)定义。

您可能会对阅读为什么要编译Python代码?感兴趣。

此外,请参阅@wberry的详细答案。


这完全是错误的。CPython的编译器确实会创建一个带有作用域的符号列表。这是在生成字节码之前完成的。 - undefined

3
您可能会喜欢Eli Bendersky在这个主题上的写作这里
在CPython中,您可以使用symtable模块。
第二部分中,Eli描述了一种遍历符号表的方法,非常有帮助。
def describe_symtable(st, recursive=True, indent=0):
    def print_d(s, *args):
        prefix = ' ' * indent
        print(prefix + s, *args)

    assert isinstance(st, symtable.SymbolTable)
    print_d('Symtable: type=%s, id=%s, name=%s' % (
                st.get_type(), st.get_id(), st.get_name()))
    print_d('  nested:', st.is_nested())
    print_d('  has children:', st.has_children())
    print_d('  identifiers:', list(st.get_identifiers()))

    if recursive:
        for child_st in st.get_children():
            describe_symtable(child_st, recursive, indent + 5)

注意,describe_symtable 似乎是为Python3编写的。 - voithos

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接