Sage的“var”如何运作?

时间:2014-01-27 18:35:05

标签: python module global cython sage

在尝试创建类似于Sagevar()function()的Python函数时,我在Python中遇到了一个明显不那么重要的问题。本质上,在Sage中调用var('x')不仅返回一个Sage符号表达式,而且还相当于x = SR.var('x'),即它将表达式对象分配给当前全局命名空间中的变量(调用模块的命名空间) )。

我的问题是,它是如何做到的?如果我做这样的事情:

B.py中的

def func():
    globals()['x'] = something
A.py

中的

from B import func
func()

我只能影响模块B的全局命名空间中的变量,而不是调用模块A的全局命名空间。

然而,与我的Sage版本一起分发的文件var.pyx如下所示:

...

def var(*args, **kwds):
    if len(args)==1:
        name = args[0]
    else:
        name = args
    G = globals()  # this is the reason the code must be in Cython.
    if 'ns' in kwds:
        # ...
        # not relevant
    v = SR.var(name, **kwds)
    if isinstance(v, tuple):
        for x in v:
            G[repr(x)] = x
    else:
        G[repr(v)] = v
    return v

...

特别是关于Cython的评论似乎很有趣。我对Cython知之甚少,所以也许这就是我的问题。如果这是Cython的一些特殊方面,那么如何在“常规Python”/ CPython中复制这个函数呢?

PS:是的,我意识到,一般来说,这种行为是个坏主意。我主要是出于好奇而问。

2 个答案:

答案 0 :(得分:1)

https://groups.google.com/d/topic/sage-devel/J-kDHlnT4/discussion

中找到了解释

我引用Volker Braun:

  

在src / setup.py中我们设置

Cython.Compiler.Options.old_style_globals = True
  

导致Cython回归旧行为。

答案 1 :(得分:0)

查看Cython 1.5's changelog,我们可以看到

  

globals()现在返回Cython模块的全局变量的只读字典,而不是堆栈中第一个非Cython模块的全局变量

因此,这是一个仅适用于非常古老的Cython编译器的技巧。

您可以使用此代码来模拟它:

import inspect

def run():
    outer_frame = inspect.stack()[1][0]
    outer_frame_locals = inspect.getargvalues(outer_frame).locals

    outer_frame_locals["new_variable"] = "I am new"

虽然注意它是非常实现定义。