对 plpython 存储过程中奇怪的导入行为感到困惑
Confused about strange import behavior within plpython stored procedures
我是 运行 Postgresql 9.4,我对它如何处理 plpython 导入感到困惑,特别是关于 Decimal。
第一个例子:
CREATE OR REPLACE FUNCTION devel.foo()
RETURNS void AS
$BODY$
def myfoo():
eval("Decimal('40.0')")
myfoo()
plpy.notice("done")
$BODY$
LANGUAGE plpythonu VOLATILE
COST 100;
ALTER FUNCTION devel.foo()
OWNER TO postgres;
SELECT devel.foo();
结果:
ERROR: NameError: name 'Decimal' is not defined
有点令人惊讶,因为 Postgresql 9.4 中的一个变化是它应该在 plpython 中隐式使用 Decimal 而不是 float。但是没关系,让我们添加导入:
CREATE OR REPLACE FUNCTION devel.foo()
RETURNS void AS
$BODY$
from decimal import Decimal
def myfoo():
eval("Decimal('40.0')");
myfoo()
plpy.notice("done")
$BODY$
LANGUAGE plpythonu VOLATILE
COST 100;
ALTER FUNCTION devel.foo()
OWNER TO postgres;
select devel.foo()
再次:
ERROR: NameError: name 'Decimal' is not defined
现在让我们尝试将导入放入函数中:
CREATE OR REPLACE FUNCTION devel.foo()
RETURNS void AS
$BODY$
def myfoo():
from decimal import Decimal
eval("Decimal('40.0')")
myfoo()
plpy.notice("done")
$BODY$
LANGUAGE plpythonu VOLATILE
COST 100;
ALTER FUNCTION devel.foo()
OWNER TO postgres;
select devel.foo();
结果:devel.foo()
现在执行没有问题,打印 'done'。另一件奇怪的事情:以下也有效:
CREATE OR REPLACE FUNCTION devel.foo()
RETURNS void AS
$BODY$
from decimal import Decimal
def myfoo():
var = Decimal('40.0')
eval("Decimal('40.0')")
myfoo()
plpy.notice("done")
$BODY$
LANGUAGE plpythonu VOLATILE
COST 100;
ALTER FUNCTION devel.foo()
OWNER TO postgres;
问题:为什么在 myfoo()
中看不到顶级导入?为什么我在函数中使用 Decimal 会突然起作用?
这是 python 记录的 here 行为。 plpythonu 执行环境不是全局的。
Note, eval() does not have access to the nested scopes (non-locals) in
the enclosing environment.
在 python(PostgreSQL 之外)中尝试此代码:
def bar():
from decimal import Decimal
def foo():
return eval("Decimal('40.0')")
return foo()
print(bar())
失败 NameError: name 'Decimal' is not defined
。
使用 global
将 Decimal
放入您的全局变量中:
def bar():
from decimal import Decimal
global Decimal
def foo():
return eval("Decimal('40.0')")
return foo()
print(bar())
我是 运行 Postgresql 9.4,我对它如何处理 plpython 导入感到困惑,特别是关于 Decimal。
第一个例子:
CREATE OR REPLACE FUNCTION devel.foo()
RETURNS void AS
$BODY$
def myfoo():
eval("Decimal('40.0')")
myfoo()
plpy.notice("done")
$BODY$
LANGUAGE plpythonu VOLATILE
COST 100;
ALTER FUNCTION devel.foo()
OWNER TO postgres;
SELECT devel.foo();
结果:
ERROR: NameError: name 'Decimal' is not defined
有点令人惊讶,因为 Postgresql 9.4 中的一个变化是它应该在 plpython 中隐式使用 Decimal 而不是 float。但是没关系,让我们添加导入:
CREATE OR REPLACE FUNCTION devel.foo()
RETURNS void AS
$BODY$
from decimal import Decimal
def myfoo():
eval("Decimal('40.0')");
myfoo()
plpy.notice("done")
$BODY$
LANGUAGE plpythonu VOLATILE
COST 100;
ALTER FUNCTION devel.foo()
OWNER TO postgres;
select devel.foo()
再次:
ERROR: NameError: name 'Decimal' is not defined
现在让我们尝试将导入放入函数中:
CREATE OR REPLACE FUNCTION devel.foo()
RETURNS void AS
$BODY$
def myfoo():
from decimal import Decimal
eval("Decimal('40.0')")
myfoo()
plpy.notice("done")
$BODY$
LANGUAGE plpythonu VOLATILE
COST 100;
ALTER FUNCTION devel.foo()
OWNER TO postgres;
select devel.foo();
结果:devel.foo()
现在执行没有问题,打印 'done'。另一件奇怪的事情:以下也有效:
CREATE OR REPLACE FUNCTION devel.foo()
RETURNS void AS
$BODY$
from decimal import Decimal
def myfoo():
var = Decimal('40.0')
eval("Decimal('40.0')")
myfoo()
plpy.notice("done")
$BODY$
LANGUAGE plpythonu VOLATILE
COST 100;
ALTER FUNCTION devel.foo()
OWNER TO postgres;
问题:为什么在 myfoo()
中看不到顶级导入?为什么我在函数中使用 Decimal 会突然起作用?
这是 python 记录的 here 行为。 plpythonu 执行环境不是全局的。
Note, eval() does not have access to the nested scopes (non-locals) in the enclosing environment.
在 python(PostgreSQL 之外)中尝试此代码:
def bar():
from decimal import Decimal
def foo():
return eval("Decimal('40.0')")
return foo()
print(bar())
失败 NameError: name 'Decimal' is not defined
。
使用 global
将 Decimal
放入您的全局变量中:
def bar():
from decimal import Decimal
global Decimal
def foo():
return eval("Decimal('40.0')")
return foo()
print(bar())