最近一直沒有寫博客,在忙着準備申請各大公司的實習,如今基本已經定下來了,特將這段時間面試中遇到的問題進行總結和解答,主要包括一些網絡、算法、操做系統、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的認識和理解。操作系統