我已经有了这个程序来测试exec()函数在将它放入My程序之前的行为。我期待最后我将收到一个由b="last_trade_id"
代表的数字(在下面显示的情况下为13621701),但我得到的是None
或ost_tranzakcja
{
"last_trade_id": 13621701,
"product_id": "BTC-EUR",
"sequence": 3542855617,
"time": "2018-04-01T18:38:32.455000Z",
"type": "heartbeat"
}
printed [a] before exec: ost_tranzakcja
printed [a] after exec: ost_tranzakcja
printed [a] after modified exec: None
printed [a] after local exec: None
printed [a] after modified local exec: None
printed [a]without and after exec: : None
以下是我用于测试的程序:
import time
import json
from websocket import create_connection
ws=create_connection("wss://ws-feed.gdax.com")
ws.send(json.dumps({"type": "subscribe", "channels": [{"name": "heartbeat", "product_ids": ["BTC-EUR"],}]}))
def KonektorWebsocket():
dane=ws.recv()
dane=json.loads(dane)
print(json.dumps(dane, indent=4, sort_keys=True))
a='ost_tranzakcja'
b="last_trade_id"
exec("print('printed [a] before exec:', a)")
exec("a=dane.get('"+ b +"', None)")
exec("print('printed [a] after exec:', a)")
a=exec("dane.get('"+ b +"', None)")
exec("print('printed [a] after modified exec:', a)")
exec("a=dane.get('"+ b +"', None)",locals())
exec("print('printed [a] after local exec:', a)")
a=exec("dane.get('"+ b +"', None)",locals())
exec("print('printed [a] after modified local exec:', a)")
print("printed [a]without and after exec: ", a)
while True:
KonektorWebsocket()
time.sleep(0.15)
答案 0 :(得分:1)
我怀疑有两个问题会让您的代码无法满足您的需求。主要问题是您无法使用exec
直接修改函数内的局部变量。如果您在模块的顶层(全局和本地命名空间相同)中运行全局变量,可以修改全局变量。但函数中的局部变量在Python中得到了特殊处理,你不能总是把它们搞得一团糟。
除了exec
个调用之外的所有调用都在修改locals()
返回的字典(默认情况下,不传递命名空间字典时,或者显式传递它时{ {1}})。不幸的是,对函数中locals()
的修改不会对名称空间中的实际变量产生任何影响,只会(暂时)在字典对象中。当再次调用locals()
并且命名空间中的实际值再次保存到字典时,修改将被撤消。
因此,大多数locals()
来电都没有效果。他们不会修改exec
,因此您可以继续打印出之前的值(您初始化它的值,或者在分配该值后a
,原因是I&I #39;接下来解释一下。)
另一个问题出现在"修改过的"你打电话给exec,你要将None
的返回值分配给exec
。这并不能达到您的期望。 a
函数始终返回exec
,因此这是函数其余部分的值None
。
如果要评估Python表达式并将其返回,请使用a
而不是eval
。您不能在exec
中放置语句(因此只有"修改过的"调用可以按照书面形式工作)。
以下是一些可能适合您的方法:
eval
如果有其他选择,使用# use eval
a = eval("dane.get('" + b + "', None)")
# use a separate namespace for exec, and assign the value to a separately afterwards
namespace = {}
exec("a = dane.get('" + b + "', None)", namespace)
a = namespace['a']
# or the obvious, don't use either eval or exec, and just call the method you want directly:
a = dane.get(b, None)
或eval
通常是个坏主意。您肯定不应该exec
任何您不完全信任的字符串,因为它可以运行任意Python代码。您的示例过于简单,因此无法清楚地了解您最终要尝试实现的目标,但我非常确定会为您的真正目标提供比exec
更好的解决方案。 / p>
答案 1 :(得分:0)
由于我的上一个示例代码过于简化,我提出了一个新的更复杂的版本,它可以工作并完成我想要它做的事情。 (除非当然有一种方法可以用更少的代码来完成)
import time
import json
from websocket import create_connection
ws=create_connection("wss://ws-feed.gdax.com")
ws.send(json.dumps({"type": "subscribe", "channels": [{"name": "heartbeat", "product_ids": ["BTC-EUR"],}]}))
newdict={}
def KonektorWebsocket():
dane=ws.recv()
dane=json.loads(dane)
print(json.dumps(dane, indent=4, sort_keys=True))
b=["last_trade_id","product_id","sequence","time","type"]
c=['ost_tranzakcja', 'parawalut','sekwencja','czas', 'typtranzakcji']
i=0
while i<5:
a = eval("dane.get('" + b[i] + "', None)")
print(" A: ", a)
print(" B[i]: ", b[i])
newdict[c[i]]=a
i=i+1
while True:
KonektorWebsocket()
print(newdict)
time.sleep(0.5)