gpt4 book ai didi

python - 为什么python 2.7中的字符串没有 "__iter__"属性,而python 3.7中的字符串有 "__iter__"属性

转载 作者:太空宇宙 更新时间:2023-11-03 23:54:31 25 4
gpt4 key购买 nike

在 python 2.7 和 python 3.7 中,我可以执行以下操作:

string = "hello world"
for letter in string:
print(letter)

但是如果我检查可迭代属性:

python 2.7

hasattr(string, "__iter__")
>> False

python 3.7

hasattr(string, "__iter__")
>> True

这是我在进行 2to3 迁移时没有找到记录的内容,它引起了一点头痛,因为我在我的代码中进行了 hasattr(entity, "__iter__") 检查。在 python 2.7 中,这可以将字符串与集合区分开来,但在 python 3.7 中则不行

我真的想问,设计决定是什么,为什么要这样实现。我希望这不是推测性的。

最佳答案

The str_iterator class for str (run type(iter("str"))) was implemented in CPython3. The object of which is returned when called "str".__iter__() or iter("str"). In CPython2 own iterator' class for str wasn't implemented. When you call iter("str") you get instance of base iterator class.

参见 1 段代码。 f = t->tp_iter; - 如果存在则返回自定义迭代器。否则 PySeqIter_New(o) - 返回 seqiterobject 结构的实例(参见 2 段代码)。从 3 段代码可以看出,这个基本迭代器在迭代时调用 PySequence_GetItem(seq, it->it_index);

如果您实现的类支持迭代,那么您需要定义 __iter__ 方法或 __getitem__。如果您选择第一个选项,则返回的对象必须实现 __iter____next__ (CPython3) 或 next (CPython2) 方法。

检查 hasattr(entity, "__iter__") 是个坏主意。

  • If you need to check if the object is iterable, then run isinstance(entity, Iterable).
  • If you need to exclude only str then run isinstance(entity, Iterable) and not isinstance(entity, str) (CPython3).

1

PyObject *
PyObject_GetIter(PyObject *o)
{
PyTypeObject *t = o->ob_type;
getiterfunc f;

f = t->tp_iter;
if (f == NULL) {
if (PySequence_Check(o)) return PySeqIter_New(o);
return type_error("'%.200s' object is not iterable", o);
}
else {
...
}
}

2

typedef struct {
PyObject_HEAD
Py_ssize_t it_index;
PyObject *it_seq; /* Set to NULL when iterator is exhausted */
} seqiterobject;

PyObject *
PySeqIter_New(PyObject *seq)
{
seqiterobject *it;

if (!PySequence_Check(seq)) {
PyErr_BadInternalCall();
return NULL;
}
it = PyObject_GC_New(seqiterobject, &PySeqIter_Type);
if (it == NULL)
return NULL;
it->it_index = 0;
Py_INCREF(seq);
it->it_seq = seq;
_PyObject_GC_TRACK(it);
return (PyObject *)it;
}

3

static PyObject *
iter_iternext(PyObject *iterator)
{
seqiterobject *it;
PyObject *seq;
PyObject *result;

assert(PySeqIter_Check(iterator));
it = (seqiterobject *)iterator;
seq = it->it_seq;
if (seq == NULL)
return NULL;
if (it->it_index == PY_SSIZE_T_MAX) {
PyErr_SetString(PyExc_OverflowError, "iter index too large");
return NULL;
}

result = PySequence_GetItem(seq, it->it_index);
if (result != NULL) {
it->it_index++;
return result;
}
if (PyErr_ExceptionMatches(PyExc_IndexError) ||
PyErr_ExceptionMatches(PyExc_StopIteration))
{
PyErr_Clear();
it->it_seq = NULL;
Py_DECREF(seq);
}
return NULL;
}

关于python - 为什么python 2.7中的字符串没有 "__iter__"属性,而python 3.7中的字符串有 "__iter__"属性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58328946/

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