亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Python內置函數(shù)詳細解析

 更新時間:2022年05月12日 08:31:44   作者:??編程學習網????  
這篇文章主要介紹了Python內置函數(shù)詳細解析,Python?自帶了很多的內置函數(shù),極大地方便了我們的開發(fā),下文小編總結了一些內置函數(shù)的相關內容,需要的小伙伴可以參考一下

前言:

Python 自帶了很多的內置函數(shù),極大地方便了我們的開發(fā),下面就來挑幾個內置函數(shù),看看底層是怎么實現(xiàn)的。
內置函數(shù)位于 Python/bitlinmodule.c 中。

1.abs

abs 的功能是取一個整數(shù)的絕對值,或者取一個復數(shù)的模。

static PyObject *
builtin_abs(PyObject *module, PyObject *x)
{
    return PyNumber_Absolute(x);
}

該函數(shù)調用了 PyNumber_Absolute。

//Objects/abstract.c
PyObject *
PyNumber_Absolute(PyObject *o)
{
    PyNumberMethods *m;
    if (o == NULL) {
        return null_error();
    }
    //通過類型對象獲取操作簇 PyNumberMethods
    m = o->ob_type->tp_as_number;
    //調用 nb_absolute 
    if (m && m->nb_absolute)
        return m->nb_absolute(o);

    return type_error("bad operand type for abs(): '%.200s'", o);
}

我們以整型為例,它的 nb_absoulte 指向 long_absolute。

//Objects/longobject.c
static PyObject *
long_abs(PyLongObject *v)
{
    if (Py_SIZE(v) < 0)
        //如果 v 小于 0,那么取相反數(shù)
        return long_neg(v);
    else
        //否則返回本身
        return long_long((PyObject *)v);
}

由于 Python3 的整數(shù)是以數(shù)組的方式存儲的,所以不會直接取相反數(shù),還要做一些額外的處理,但從數(shù)學上直接理解為取相反數(shù)即可。

2.all

接收一個可迭代對象,如果里面的元素全部為真,則返回 True;只要有一個不為真,則返回 False。

static PyObject *
builtin_all(PyObject *module, PyObject *iterable)
{
    PyObject *it, *item;
    PyObject *(*iternext)(PyObject *);
    int cmp;
    //獲取可迭代對象的迭代器
    it = PyObject_GetIter(iterable);
    if (it == NULL)
        return NULL;
    //拿到內部的 __next__ 方法
    iternext = *Py_TYPE(it)->tp_iternext;

    for (;;) {
        //迭代元素
        item = iternext(it);
        //返回 NULL,說明出異常了
        //一種是迭代完畢拋出的 StopIteration
        //另一種是迭代過程中出現(xiàn)的異常
        if (item == NULL)
            break;
        //判斷 item 的布爾值是否為真
        //cmp > 0 表示為真
        //cmp == 0表示為假
        //cmp < 0 表示解釋器調用出錯(極少發(fā)生)
        cmp = PyObject_IsTrue(item);
        Py_DECREF(item);
        if (cmp < 0) {
            Py_DECREF(it);
            return NULL;
        }
        //只要有一個元素為假,就返回 False
        if (cmp == 0) {
            Py_DECREF(it);
            Py_RETURN_FALSE;
        }
    }
    Py_DECREF(it);
    //PyErr_Occurred() 為真表示出現(xiàn)異常了
    if (PyErr_Occurred()) {
        //判斷異常是不是 StopIteration
        if (PyErr_ExceptionMatches(PyExc_StopIteration))
            //如果是,那么表示迭代正常結束
            //PyErr_Clear() 負責將異常清空
            PyErr_Clear();
        else
            return NULL;
    }
    //走到這,說明所有的元素全部為真
    //返回 True,等價于 return Py_True
    Py_RETURN_TRUE;
}

因此 all 就是一層 for 循環(huán),但它是 C 的循環(huán),所以比我們寫的 Python 代碼快。

3.any

接收一個可迭代對象,只要里面有一個元素為真,則返回 True;如果全為假,則返回 False。

static PyObject *
builtin_any(PyObject *module, PyObject *iterable)
{    
    //源碼和 builtin_all 是類似的
    PyObject *it, *item;
    PyObject *(*iternext)(PyObject *);
    int cmp;
    //獲取可迭代對象的迭代器
    it = PyObject_GetIter(iterable);
    if (it == NULL)
        return NULL;
    //拿到內部的 __next__ 方法
    iternext = *Py_TYPE(it)->tp_iternext;

    for (;;) {
        //迭代元素
        item = iternext(it);
        if (item == NULL)
            break;
        cmp = PyObject_IsTrue(item);
        Py_DECREF(item);
        if (cmp < 0) {
            Py_DECREF(it);
            return NULL;
        }
        //只要有一個為真,則返回 True
        if (cmp > 0) {
            Py_DECREF(it);
            Py_RETURN_TRUE;
        }
    }
    Py_DECREF(it);
    if (PyErr_Occurred()) {
        if (PyErr_ExceptionMatches(PyExc_StopIteration))
            PyErr_Clear();
        else
            return NULL;
    }
    //全部為假,則返回 False
    Py_RETURN_FALSE;
}

4.callable

判斷一個對象是否可調用。

static PyObject *
builtin_callable(PyObject *module, PyObject *obj)
{
    return PyBool_FromLong((long)PyCallable_Check(obj));
}
PyBool_FromLong 是將一個整數(shù)轉成布爾值,所以就看 PyCallable_Check 是返回 0,還是返回非 0。

int
PyCallable_Check(PyObject *x)
{
    if (x == NULL)
        return 0;
    return x->ob_type->tp_call != NULL;
}

邏輯非常簡單,一個對象是否可調用,就看它的類型對象有沒有實現(xiàn) __call__。

5.dir

如果不接收任何對象,返回當前的 local 空間;否則返回某個對象的所有屬性的名稱。

static PyObject *
builtin_dir(PyObject *self, PyObject *args)
{
    PyObject *arg = NULL;
    //要么不接收參數(shù),要么接收一個參數(shù)
    //如果沒有接收參數(shù),那么 arg 就是 NULL,否則就是我們傳遞的參數(shù)
    if (!PyArg_UnpackTuple(args, "dir", 0, 1, &arg))
        return NULL;
    return PyObject_Dir(arg);
}

該函數(shù)調用了 PyObject_Dir。

//Objects/object.c
PyObject *
PyObject_Dir(PyObject *obj)
{   
    //當 obj 為 NULL,說明我們沒有傳參,那么返回 local 空間
    //否則返回對象的所有屬性的名稱
    return (obj == NULL) ? _dir_locals() : _dir_object(obj);
}

先來看看 _dir_locals 函數(shù)。

//Objects/object.c
static PyObject *
_dir_locals(void)
{
    PyObject *names;
    PyObject *locals;
    //獲取當前的 local 空間
    locals = PyEval_GetLocals();
    if (locals == NULL)
        return NULL;
    //拿到所有的 key,注意:PyMapping_Keys 返回的是列表
    names = PyMapping_Keys(locals);
    if (!names)
        return NULL;
    if (!PyList_Check(names)) {
        PyErr_Format(PyExc_TypeError,
            "dir(): expected keys() of locals to be a list, "
            "not '%.200s'", Py_TYPE(names)->tp_name);
        Py_DECREF(names);
        return NULL;
    }
    //排序
    if (PyList_Sort(names)) {
        Py_DECREF(names);
        return NULL;
    }
    //返回
    return names;
}

還是比較簡單的,然后是 _dir_object,它的代碼比較多,這里就不看了。但是邏輯很簡單,就是調用對象的 dir 方法,將得到的列表排序后返回。

6.id

查看對象的內存地址,我們知道 Python 雖然一切皆對象,但是我們拿到的都是指向對象的指針。比如 id(name) 是查看變量 name 指向對象的地址,說白了不就是 name 本身嗎?所以直接將指針轉成整數(shù)之后返回即可,

static PyObject *
builtin_id(PyModuleDef *self, PyObject *v)

{   
    //將 v 轉成整數(shù),返回即可
    PyObject *id = PyLong_FromVoidPtr(v);

    if (id && PySys_Audit("builtins.id", "O", id) < 0) {
        Py_DECREF(id);
        return NULL;
    }

    return id;
}

7.locals 和 globals

這兩者是查看當前的 local 空間和 global 空間,顯然直接通過棧幀的 f_locals 和 f_globals 字段即可獲取。

static PyObject *
builtin_locals_impl(PyObject *module)
{
    PyObject *d;
    //在內部會通過線程狀態(tài)對象拿到棧幀
    //再通過棧幀的 f_locals 字段拿到 local 空間
    d = PyEval_GetLocals();
    Py_XINCREF(d);
    return d;
}

static PyObject *
builtin_globals_impl(PyObject *module)
{
    PyObject *d;
    //和 PyEval_GetLocals 類似
    d = PyEval_GetGlobals();
    Py_XINCREF(d);
    return d;
}

8.hash

獲取對象的哈希值。

static PyObject *
builtin_hash(PyObject *module, PyObject *obj)
{
    Py_hash_t x;
    //在內部會調用 obj -> ob_type -> tp_hash(obj)
    x = PyObject_Hash(obj);
    if (x == -1)
        return NULL;
    return PyLong_FromSsize_t(x);
}

9.sum

接收一個可迭代對象,計算它們的和。但是這里面有一個需要注意的地方。

print(sum([1, 2, 3]))  # 6

try:
    print(sum(["1", "2", "3"]))
except TypeError as e:
    print(e)  # unsupported operand type(s) for +: 'int' and 'str'

咦,字符串明明也支持加法呀,為啥不行呢?其實 sum 還可以接收第二個參數(shù),我們不傳的話就是 0。

也就是說 sum([1, 2, 3]) 其實是 0 + 1 + 2 + 3;那么同理,sum(["a", "b", "c"]) 其實是 0 + "a" + "b" + "c";所以上面的報錯信息是不支持類型為 int 和 str 的實例進行相加。

try:
    print(sum(["1", "2", "3"], ""))
except TypeError as e:
    print(e)  # sum() can't sum strings [use ''.join(seq) instead]

# 我們看到還是報錯了,只能說明理論上是可以的
# 但 Python 建議我們使用 join

# 我們用列表舉例吧
try:
    print(sum([[1], [2], [3]]))
except TypeError as e:
    print(e)  # unsupported operand type(s) for +: 'int' and 'list'

# 告訴我們 int 的實例和 list 的實例不可以相加
# 將第二個參數(shù)換成空列表
print(sum([[1], [2], [3]], []))  # [1, 2, 3]

# 如果不是空列表呢?
print(
    sum([[1], [2], [3]], ["古明地覺"])
)  # ['古明地覺', 1, 2, 3]

所以 sum 是將第二個參數(shù)和第一個參數(shù)(可迭代對象)里面的元素依次相加,然后看一下底層實現(xiàn)。

static PyObject *
builtin_sum_impl(PyObject *module, PyObject *iterable, PyObject *start)
{   
    //result 就是返回值,初始等于第二個參數(shù)
    //如果可迭代對象為空,那么返回的就是第二個參數(shù)
    //比如 sum([], 123) 得到的就是 123
    PyObject *result = start;
    PyObject *temp, *item, *iter;
    //獲取可迭代對象的類型對象
    iter = PyObject_GetIter(iterable);
    if (iter == NULL)
        return NULL;
    
    //如果 result 為 NULL,說明我們沒有傳遞第二個參數(shù)
    if (result == NULL) {
        //那么 result 賦值為 0
        result = PyLong_FromLong(0);
        if (result == NULL) {
            Py_DECREF(iter);
            return NULL;
        }
    } else {
        //否則的話,檢測是不是 str、bytes、bytearray 類型
        //如果是的話,依舊報錯,并提示使用 join 方法
        if (PyUnicode_Check(result)) {
            PyErr_SetString(PyExc_TypeError,
                "sum() can't sum strings [use ''.join(seq) instead]");
            Py_DECREF(iter);
            return NULL;
        }
        if (PyBytes_Check(result)) {
            PyErr_SetString(PyExc_TypeError,
                "sum() can't sum bytes [use b''.join(seq) instead]");
            Py_DECREF(iter);
            return NULL;
        }
        if (PyByteArray_Check(result)) {
            PyErr_SetString(PyExc_TypeError,
                "sum() can't sum bytearray [use b''.join(seq) instead]");
            Py_DECREF(iter);
            return NULL;
        }
        Py_INCREF(result);
    }

#ifndef SLOW_SUM
    //這里是快分支
    //假設所有元素都是整數(shù)
    if (PyLong_CheckExact(result)) {
        //將所有整數(shù)都迭代出來,依次相加
        //...
    }

    if (PyFloat_CheckExact(result)) {
        //將所有浮點數(shù)都迭代出來,依次相加
        //...
    }
#endif
    
    //如果不全是整數(shù)或浮點數(shù),執(zhí)行通用邏輯
    for(;;) {
        //迭代元素
        item = PyIter_Next(iter);
        if (item == NULL) {
            /* error, or end-of-sequence */
            if (PyErr_Occurred()) {
                Py_DECREF(result);
                result = NULL;
            }
            break;
        }
        //和 result 依次相加
        temp = PyNumber_Add(result, item);
        Py_DECREF(result);
        Py_DECREF(item);
        result = temp;
        if (result == NULL)
            break;
    }
    Py_DECREF(iter);
    //返回
    return result;
}

一個小小的 sum,代碼量還真不少呢,我們還省略了一部分。

10.getattr、setattr、delattr

這幾個應該已經很熟悉了,先來看看 getattr,它是獲取對象的某個屬性,并且還可以指定默認值。

static PyObject *
builtin_getattr(PyObject *self, PyObject *const *args, Py_ssize_t nargs)
{
    PyObject *v, *name, *result;
    //參數(shù)個數(shù)必須是 2 或 3
    //對象、屬性名、可選的默認值
    if (!_PyArg_CheckPositional("getattr", nargs, 2, 3))
        return NULL;
    //獲取對象和屬性名
    v = args[0];
    name = args[1];
    //name必須是字符串
    if (!PyUnicode_Check(name)) {
        PyErr_SetString(PyExc_TypeError,
                        "getattr(): attribute name must be string");
        return NULL;
    }
    //調用對象的 __getattr__,找不到返回默認值
    if (nargs > 2) {
        if (_PyObject_LookupAttr(v, name, &result) == 0) {
            PyObject *dflt = args[2];
            Py_INCREF(dflt);
            return dflt;
        }
    }
    else {
        result = PyObject_GetAttr(v, name);
    }
    return result;
}

同理 setattr 是調用對象的 __setattr__,delattr 是調用對象的 __delattr__。

到此這篇關于Python內置函數(shù)詳細解析的文章就介紹到這了,更多相關Python內置函數(shù)內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • 對python使用http、https代理的實例講解

    對python使用http、https代理的實例講解

    今天小編就為大家分享一篇對python使用http、https代理的實例講解,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-05-05
  • Python如何實現(xiàn)拆分數(shù)據集

    Python如何實現(xiàn)拆分數(shù)據集

    這篇文章主要介紹了Python如何實現(xiàn)拆分數(shù)據集問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-09-09
  • Python的flask接收前臺的ajax的post數(shù)據和get數(shù)據的方法

    Python的flask接收前臺的ajax的post數(shù)據和get數(shù)據的方法

    這篇文章主要介紹了Python的flask接收前臺的ajax的post數(shù)據和get數(shù)據的方法,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-04-04
  • 基于Python實現(xiàn)文件分類器的示例代碼

    基于Python實現(xiàn)文件分類器的示例代碼

    這篇文章主要為大家詳細介紹了如何基于Python實現(xiàn)文件分類器,目的主要是為了將辦公過程中產生的各種格式的文件完成整理,感興趣的可以了解一下
    2023-04-04
  • 在Python3.74+PyCharm2020.1 x64中安裝使用Kivy的詳細教程

    在Python3.74+PyCharm2020.1 x64中安裝使用Kivy的詳細教程

    這篇文章主要介紹了在Python3.74+PyCharm2020.1 x64中安裝使用Kivy的詳細教程,本文通過圖文實例相結合給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-08-08
  • Python多線程及其基本使用方法實例分析

    Python多線程及其基本使用方法實例分析

    這篇文章主要介紹了Python多線程及其基本使用方法,結合實例形式分析了Python相關概念、原理、使用方法及操作注意事項,需要的朋友可以參考下
    2019-10-10
  • python簡單分割文件的方法

    python簡單分割文件的方法

    這篇文章主要介紹了python簡單分割文件的方法,涉及Python針對文件的讀取與寫入技巧,具有一定參考借鑒價值,需要的朋友可以參考下
    2015-07-07
  • pyqt5數(shù)據庫使用詳細教程(打包解決方案)

    pyqt5數(shù)據庫使用詳細教程(打包解決方案)

    這篇文章主要介紹了pyqt5數(shù)據庫使用教程(打包解決方案),本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-03-03
  • Python使用jsonpath-rw模塊處理Json對象操作示例

    Python使用jsonpath-rw模塊處理Json對象操作示例

    這篇文章主要介紹了Python使用jsonpath-rw模塊處理Json對象操作,結合實例形式分析了Python使用requests與response處理json的方法,并給出了jsonpath_rw模塊操作json對象的基本示例,需要的朋友可以參考下
    2018-07-07
  • python Flask 裝飾器順序問題解決

    python Flask 裝飾器順序問題解決

    這篇文章主要介紹了python Flask 裝飾器順序問題解決,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-08-08

最新評論