gpt4 book ai didi

python - python字节码中的load name和load global有什么区别?

转载 作者:太空狗 更新时间:2023-10-30 00:47:47 33 4
gpt4 key购买 nike

load name 接受它的参数,并将 store name 存储在参数指示的位置的 name 的值压入堆栈。 load global 做了类似的事情,但字节码中似乎没有 store global。那么有什么区别以及load global是如何工作的呢

最佳答案

LOAD_NAMELOAD_GLOBAL 之间的区别在于它们在何处搜索给定的 name

LOAD_NAME

当 Python 遇到 LOAD_NAME 操作码时:

  • 它首先在 f_locals 中搜索 - 当前框架对象的本地名称。
  • 如果它在 f_locals 中找不到给定的名称,它将继续在 f_globals 中搜索 - 框架对象的全局名称。这些是框架对象周围范围内的名称。
  • 如果在f_globals 中没有找到名称,它就会搜索f_builtinsf_builtins 是 Python 使用的内置名称的字典。
  • 如果以上所有方法都失败,Python 会抛出一个NameError

这里是虚拟机执行LOAD_NAME指令的相关C代码:

    TARGET(LOAD_NAME) {
PyObject *name = GETITEM(names, oparg);
PyObject *locals = f->f_locals;
PyObject *v;
if (locals == NULL) {
PyErr_Format(PyExc_SystemError,
"no locals when loading %R", name);
goto error;
}
if (PyDict_CheckExact(locals)) {
v = PyDict_GetItem(locals, name);
Py_XINCREF(v);
}
else {
v = PyObject_GetItem(locals, name);
if (v == NULL) {
if (!PyErr_ExceptionMatches(PyExc_KeyError))
goto error;
PyErr_Clear();
}
}
if (v == NULL) {
v = PyDict_GetItem(f->f_globals, name);
Py_XINCREF(v);
if (v == NULL) {
if (PyDict_CheckExact(f->f_builtins)) {
v = PyDict_GetItem(f->f_builtins, name);
if (v == NULL) {
format_exc_check_arg(
PyExc_NameError,
NAME_ERROR_MSG, name);
goto error;
}
Py_INCREF(v);
}
else {
v = PyObject_GetItem(f->f_builtins, name);
if (v == NULL) {
if (PyErr_ExceptionMatches(PyExc_KeyError))
format_exc_check_arg(
PyExc_NameError,
NAME_ERROR_MSG, name);
goto error;
}
}
}
}
PUSH(v);
DISPATCH();
}

LOAD_GLOBAL

当 Python 遇到 LOAD_GLOBAL 操作码时:

  • Python 首先在 f_globals 中搜索名称 - 当前框架对象引用的周围范围内的名称。
  • 如果在f_globals 中没有找到名称,它就会搜索f_builtinsf_builtins 是 Python 使用的内置名称的字典。
  • 如果以上所有方法都失败,Python 会抛出一个NameError

这里是虚拟机执行LOAD_GLOBAL指令的相关C代码:

    TARGET(LOAD_GLOBAL) {
PyObject *name = GETITEM(names, oparg);
PyObject *v;
if (PyDict_CheckExact(f->f_globals)
&& PyDict_CheckExact(f->f_builtins))
{
v = _PyDict_LoadGlobal((PyDictObject *)f->f_globals,
(PyDictObject *)f->f_builtins,
name);
if (v == NULL) {
if (!_PyErr_OCCURRED()) {
/* _PyDict_LoadGlobal() returns NULL without raising
* an exception if the key doesn't exist */
format_exc_check_arg(PyExc_NameError,
NAME_ERROR_MSG, name);
}
goto error;
}
Py_INCREF(v);
}
else {
/* Slow-path if globals or builtins is not a dict */

/* namespace 1: globals */
v = PyObject_GetItem(f->f_globals, name);
if (v == NULL) {
if (!PyErr_ExceptionMatches(PyExc_KeyError))
goto error;
PyErr_Clear();

/* namespace 2: builtins */
v = PyObject_GetItem(f->f_builtins, name);
if (v == NULL) {
if (PyErr_ExceptionMatches(PyExc_KeyError))
format_exc_check_arg(
PyExc_NameError,
NAME_ERROR_MSG, name);
goto error;
}
}
}
PUSH(v);
DISPATCH();
}

那么,有什么区别呢?

正如您可能看到的那样,不同之处在于 LOAD_GLOBAL 直接跳到搜索框架对象的全局名称,而 LOAD_NAME 开始搜索局部名称并使它一路攀升。 LOAD_GLOBAL 操作码对于 Python 已经知道名称不能是本地名称的情况非常有用,因此它会完全跳过搜索本地名称。

注意:如果您想了解更多关于 Python 虚拟机如何工作的信息,请查看 Byterun ,CPython 虚拟机的纯 Python 实现。它还有一个 accompanying article作者:Allison Kaptur。

关于python - python字节码中的load name和load global有什么区别?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45773382/

33 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com