最近一直没有写博客,在忙着准备申请各大公司的实习,如今基本已经定下来了,特将这段时间面试中遇到的问题进行总结和解答,主要包括一些网络、算法、操做系统、python的问题,这些问题并非以往比较常见的题目,更多的都是更加细节的或者以往没有见到的题目。文章更多的是面向技术,而不是面经,同时关于问题的解答都是本身一家之言,若有问题,还望你们指正。本文的知识点是关于python中的可变对象与不可变对象,面试官问我在python中是如何实现的。python
我最开始想到的是这个问题要考察的是python的内部实现机制,因此先简述下python的可变对象和不可变对象,再从python内部实现的角度分析下这个题目。
众所周知,python在堆中分配的对象按照是否可变分为两类:可变对象和不可变对象。关于他们各自的定义我想你们比较熟悉,特复制一段官方解释以下:In general, data types in Python can be distinguished based on whether objects of the type are mutable or immutable. The content of objects of immutable types cannot be changed after they are created. Only mutable objects support methods that change the object in place, such as reassignment of a sequence slice下面列举出一些常见的可变对象和不可变对象。面试
咱们用一个很简单的例子来看看可变对象和不可变对象。算法
# code a = [1, 2, 3] a[1] = 4 print a b = "123" b[1] = '4' print b # output [1, 4, 3] Traceback (most recent call last): File "test.py", line 5, in <module> b[1] = '4' TypeError: 'str' object does not support item assignment
在上述例子中,list中的第二个元素能够被改变,可是若是试图改变string中的第二个元素,就会报错。可是有人可能有以下疑惑,好比下面的代码:网络
# code a = 1 print a a = 2 print a # output 1 2
有些人以为上面的代码中a为一个int型的对象,可是他的值发生了变化,而解释器也没有报错。这里有必要提一下python的赋值语句,在python中,赋值语句实际上是创建对对象的引用值,而不是复制对象,即更像是指针。因此在语句a=1执行后,只是创建了一个引用值a来指向int对象1,因此当再执行a=2这个语句的时候,是将这个引用值指向了int对象2,因此这里并无改变int对象。
既然如今明白了python中的可变对象和不可变对象,那么在python中他们分别是如何实现的呢?
这个问题的答案我以为很简单,若是对象中定义了修改对象的成员方法,则这个对象是可变的,不然是不可变对象,因此咱们能够经过修改python的源码让String也变成一个可变对象。这个能够从python源码中获得证明,好比下面的python代码:a = [1,2] a[0]=3就调用了下面的函数:app
int PyList_SetItem(PyObject *op, Py_ssize_t i, PyObject *newitem) { PyObject **p; if (!PyList_Check(op)) { Py_XDECREF(newitem); PyErr_BadInternalCall(); return -1; } if (i < 0 || i >= Py_SIZE(op)) { Py_XDECREF(newitem); PyErr_SetString(PyExc_IndexError, "list assignment index out of range"); return -1; } p = ((PyListObject *)op) -> ob_item + i; Py_SETREF(*p, newitem); return 0; }
在上面的代码中,首先会进行类型检查,随后进行索引的有效性检查,当类型检查和索引有效性检查经过以后,将待加入的指针放到指定的位置。这是设置元素,经常使用的还有插入元素,代码以下:函数
static PyObject * listinsert(PyListObject *self, PyObject *args) { Py_ssize_t i; PyObject *v; if (!PyArg_ParseTuple(args, "nO:insert", &i, &v)) return NULL; if (ins1(self, i, v) == 0) Py_RETURN_NONE; return NULL; }
关于list中的成员属性,均可以在源代码中看到,下面只列举出在python中的方法名和python源码中的实现函数的对象关系:ui
static PyMethodDef list_methods[] = { {"__getitem__", (PyCFunction)list_subscript, METH_O|METH_COEXIST, getitem_doc}, {"__reversed__",(PyCFunction)list_reversed, METH_NOARGS, reversed_doc}, {"__sizeof__", (PyCFunction)list_sizeof, METH_NOARGS, sizeof_doc}, {"clear", (PyCFunction)listclear, METH_NOARGS, clear_doc}, {"copy", (PyCFunction)listcopy, METH_NOARGS, copy_doc}, {"append", (PyCFunction)listappend, METH_O, append_doc}, {"insert", (PyCFunction)listinsert, METH_VARARGS, insert_doc}, {"extend", (PyCFunction)listextend, METH_O, extend_doc}, {"pop", (PyCFunction)listpop, METH_VARARGS, pop_doc}, {"remove", (PyCFunction)listremove, METH_O, remove_doc}, {"index", (PyCFunction)listindex, METH_VARARGS, index_doc}, {"count", (PyCFunction)listcount, METH_O, count_doc}, {"reverse", (PyCFunction)listreverse, METH_NOARGS, reverse_doc}, {"sort", (PyCFunction)listsort, METH_VARARGS | METH_KEYWORDS, sort_doc}, {NULL, NULL} /* sentinel */ };
我也想过,这个题目可能更想考察的是python的内存管理机制和对象机制,这部门的内容也曾经被单独问到过,因此之后会专门写一篇博客来说述python的内存管理机制。
python的实现包含了不少智慧,用本身粗浅的理解来加深对python的认识和理解。操作系统