程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> 更多編程語言 >> Python >> python中的可變對象與不可變對象的實現

python中的可變對象與不可變對象的實現

編輯:Python
網易游戲面試經驗和問題——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下面列舉出一些常見的可變對象和不可變對象。

  • 可變對象:list, dictionary, set, byte array
  • 不可變對象:int,long, complex, string, float, tuple, frozen set

我們用一個很簡單的例子來看看可變對象和不可變對象。

# 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就調用了下面的函數:

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源碼中的實現函數的對象關系:

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的認識和理解。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved