1

我在 Linux 机器上使用 Python 3,在同一主机上使用经典 rpyc。在当前目录中拥有简单的 python 文件 tst.py,其中包含两行:

a = {'a': 0}

b = 3

然后我运行以下命令:

>>> import rpyc; conn = rpyc.classic.connect('127.0.0.1')
>>> conn.execute('import tst')
>>> conn.eval('dir(tst)')
['__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', 
    '__package__', '__spec__', 'a', 'b']
>>> conn.eval('tst.a, tst.b')
({'a': 0, 'b': 1}, 3)

一切都如预期的那样。如果我现在关闭连接:“conn.close()”,关闭 python 会话,从当前目录中删除“ pycache ”,编辑“tst.py”文件,只留下一行:

a = {'a': 0, 'b': 2}

并在新会话中从头开始重复上述相同的命令:

.....(跳过)...

>>> conn.eval('dir(tst)')
'__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', 
   '__package__', '__spec__', 'a', 'b']

>>> conn.eval('tst.a, tst.b')
({'a': 0, 'b': 1}, 3)

因此,令人惊讶的是,尽管 tst.py 文件更改并且本地 python 缓存已被删除,但结果仍然相同。有人可以向新手解释我做错了什么以及如何清理以前加载的代码。“rpyc”有自己的缓存吗?如果您更改此“tst.py”文件的名称并使用新名称再次重复相同的过程,那么结果将是正确的。同样,这指向缓存但不在当前目录中。

4

1 回答 1

0

如果您正在运行rpyc,则意味着您有一个服务器进程(您连接到,但未在问题中显示)和一个客户端进程(这里似乎您使用了 REPL)。

服务器继续运行,从您连接到它之前,关闭连接后的事件;这就是服务器所做的。问题是您看到的是位于服务器进程当前内存中的 Python 对象。

rpyc没有缓存,您只是两次连接到同一个进程,因此第二次看到的东西比第一次看到的相同。
如果您更改tst.py文件的名称,您将不得不使用新名称再次导入它。Python 在importing 模块时所做的是创建一个module对象并将其提供给您。

conn.eval('dir(tst)')

要求 Python 列出dir模块的内容,这是导入时在相应文件中定义的内容(以及您对其内容所做的任何后续更改)。
第二次连接到服务器进程时,您dir将完全相同的 Python 模块对象的内容存在于服务器进程内存中,因此您得到完全相同的结果。

但是更改文件名,然后导入它会创建第二个模块对象,它可能与第一个不同。

当您说“关闭 Python 会话”时,您的意思是您结束了客户端进程,但它不会影响服务器进程。

__pycache__文件夹只是 Python 放置中间编译对象的地方,这减少了再次导入文件所需的时间。您通常可以忽略它。无论如何,它与您当前的问题无关。

谈论解决方案,这将有助于了解您要实现的目标。但我会提供一些通用的答案:

  1. 您可以停止服务器进程然后重新启动它,以便您可以导入模块(您已更改其源文件内容)。如果您有能力重新启动rpyc服务器,我推荐此解决方案,因为与其他解决方案相比,它通常更简单。
  2. 只需使用设置器:在您的tst模块函数中定义以更改变量值,并远程调用它们。例子 :
    >>> import rpyc; conn = rpyc.classic.connect('127.0.0.1')
    >>> conn.execute('import tst')
    >>> conn.eval('dir(tst)')
    ['__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', 
        '__package__', '__spec__', 'a', 'b']
    >>> conn.eval('tst.a, tst.b')
    ({'a': 0, 'b': 1}, 3)
    >>> conn.eval('tst.set_a(4)')
    >>> conn.eval('tst.a, tst.b')
    (4, 3)
    
    它要求您处理所有要重置的事情,可能必须通知服务器的某些部分已完成重置并且应该更新一些变量。它比上一个答案更难,但不需要重新启动服务器进程。
  3. 您可以使用importlib.reload强制 Python 构造一个具有相同名称的新模块对象,从而考虑最近对源文件内容的更改。但这可能会导致NASTY问题,因为您的旧模块可能仍然存在一些引用,因此这两种内容(重新加载之前的内容和重新加载之后的内容)可能会在应用程序的不同部分共存,从而导致许多令人困惑的错误并且难以调查。我建议这样做。
于 2021-06-08T12:51:11.427 回答