id()是否返回CPython中的实际内存地址?

时间:2018-09-11 14:34:44

标签: python

何时使用id()获取不同子进程中全局变量的标识返回相同的值,但是当我在子进程中修改全局变量但在主进程中不起作用时?如果id()返回变量的实际内存地址,但是为什么我不能在子进程中修改值? (我在MacOS中使用Python3.6 [CPython])

import os
from multiprocessing import Process


Global_list = []
Global_number = 0


def foo(x):
    global Global_list, Global_number
    print("Pid {}, id(Global_list)={}, id(Global_number)={}".format(os.getpid(), id(Global_list), id(Global_number)))
    Global_list.append(x)
    Global_number += x
    print("After: Pid {}, id(Global_list)={}, id(Global_number)={}\n".format(os.getpid(), id(Global_list), id(Global_number)))

if __name__ == '__main__':
    la = [1, 2, 3, 4]

    p_list = []

    for i in la:
        process = Process(target=foo, args=(i,))
        p_list.append(process)
        process.start()

    for p in p_list:
        p.join()

    print("In main process, id(Global_list)={}, id(Global_number)={}".format(id(Global_list), id(Global_number)))
    print("After all: Global_list={}, Global_number={}".format(Global_list, Global_number))

结果:

Pid 42061, id(Global_list)=4347140936, id(Global_number)=4305316864
After: Pid 42061, id(Global_list)=4347140936, id(Global_number)=4305316896

Pid 42062, id(Global_list)=4347140936, id(Global_number)=4305316864
After: Pid 42062, id(Global_list)=4347140936, id(Global_number)=4305316928

Pid 42063, id(Global_list)=4347140936, id(Global_number)=4305316864
After: Pid 42063, id(Global_list)=4347140936, id(Global_number)=4305316960

Pid 42064, id(Global_list)=4347140936, id(Global_number)=4305316864
After: Pid 42064, id(Global_list)=4347140936, id(Global_number)=4305316992

In main process, id(Global_list)=4347140936, id(Global_number)=4305316864
After all: Global_list=[], Global_number=0

2 个答案:

答案 0 :(得分:0)

>>> Global_list = []
>>> id(Global_list)
4351947464
>>> Global_list.append(1)
>>> id(Global_list)
4351947464

>>> Global_number = 0
>>> id(Global_number)
4305328480
>>> Global_number += 1
>>> id(Global_number)
4305328512  ----> different address

如果尝试为相同的变量名称分配值,则其内存地址将更改。

答案 1 :(得分:0)

您似乎有一个基本的误解。 在同一过程中,如果id()为两个不同的对象返回相同的值,则意味着它们具有相同的对象标识(对另一个对象的修改将对另一个对象可见)。

id()仅在一个进程中是唯一的。如果您正在使用多个进程,则可以(很可能会!)让id()不同对象返回相同的值,该值可能是相同的类型,甚至可能具有相同的值(例如,如果您使用os.fork()创建子流程),但 not 具有相同的标识:对一个的更改不会反映在另一个中。

更笼统地说,在所有现代操作系统中都是如此:每个进程都有其自己独立的内存“视图”(称为“虚拟内存”),并且可以使用其喜欢的任何地址(受各种操作系统级别的限制,例如sbrkmmap)。系统中的每个进程都可以在地址4347140936处有一个对象,并且它们都可以是彼此不同的对象。许多操作系统都依赖于这种行为-例如,共享库可能总是在同一位置加载到内存中,而调用共享库的函数可能取决于实际情况。

也就是说,如果您正在使用各种共享内存或对象远程处理机制,则可以 在一个进程中对对象进行修改,从而将其反映到另一个进程中的对象。但是在那种情况下,实际上您有两个 对象,只有两个“互连”对象-这意味着id()将返回不同值,即使对象在概念上是“相同的”。