欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

淺談Python中對(duì)象是如何被調(diào)用的

 更新時(shí)間:2022年04月06日 09:47:18   作者:編程學(xué)習(xí)網(wǎng)  
本文主要介紹了淺談Python中對(duì)象是如何被調(diào)用的,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

楔子

我們知道對(duì)象是如何被創(chuàng)建的,主要有兩種方式,一種是通過Python/C API,另一種是通過調(diào)用類型對(duì)象。對(duì)于內(nèi)置類型的實(shí)例對(duì)象而言,這兩種方式都是支持的,比如列表,我們即可以通過[]創(chuàng)建,也可以通過list(),前者是Python/C API,后者是調(diào)用類型對(duì)象。

但對(duì)于自定義類的實(shí)例對(duì)象而言,我們只能通過調(diào)用類型對(duì)象的方式來創(chuàng)建。而一個(gè)對(duì)象如果可以被調(diào)用,那么這個(gè)對(duì)象就是callable,否則就不是callable。

而決定一個(gè)對(duì)象是不是callable,就取決于其對(duì)應(yīng)的類型對(duì)象中是否定義了某個(gè)方法。如果從 Python 的角度看的話,這個(gè)方法就是 __call__,從解釋器角度看的話,這個(gè)方法就是 tp_call。

從 Python 的角度看對(duì)象的調(diào)用

調(diào)用 int、str、tuple 可以創(chuàng)建一個(gè)整數(shù)、字符串、元組,調(diào)用自定義的類也可以創(chuàng)建出相應(yīng)的實(shí)例對(duì)象,說明類型對(duì)象是可調(diào)用的,也就是callable。那么這些類型對(duì)象(int、str、tuple、class等等)的類型對(duì)象(type)內(nèi)部一定有 call 方法。

# int可以調(diào)用
# 那么它的類型對(duì)象、也就是元類(type), 內(nèi)部一定有__call__方法
print(hasattr(type, "__call__"))  # True

# 而調(diào)用一個(gè)對(duì)象,等價(jià)于調(diào)用其類型對(duì)象的 __call__ 方法
# 所以 int(3.14)實(shí)際就等價(jià)于如下
print(type.__call__(int, 3.14))  # 3

注意:這里描述的可能有一些繞,我們說 int、str、float 這些都是類型對(duì)象(簡(jiǎn)單來說就是類),而 123、"你好"、3.14 是其對(duì)應(yīng)的實(shí)例對(duì)象,這些都沒問題。但type是不是類型對(duì)象,顯然是的,雖然我們稱呼它為元類,但它也是類型對(duì)象,如果 print(type) 顯示的也是一個(gè)類。

那么相對(duì) type 而言,int、str、float 是不是又成了實(shí)例對(duì)象呢?因?yàn)樗鼈兊念愋褪?type。

所以 class 具有二象性:

  • 如果站在實(shí)例對(duì)象(如:123、"satori"、[]、3.14)的角度上,它是類型對(duì)象
  • 如果站在 type 的角度上,它是實(shí)例對(duì)象

同理 type 的類型是也是 type,那么 type 既是 type 的類型對(duì)象,type 也是 type 的實(shí)例對(duì)象。雖然這里描述的會(huì)有一些繞,但應(yīng)該不難理解,并且為了避免后續(xù)的描述出現(xiàn)歧義,這里我們做一個(gè)申明:

  • 整數(shù)、浮點(diǎn)數(shù)、字符串等等,我們稱之為實(shí)例對(duì)象
  • int、float、str、dict,以及我們自定義的類,我們稱之為類型對(duì)象
  • type 雖然也是類型對(duì)象,但我們稱它為元類

所以 type 的內(nèi)部有 call 方法,那么說明類型對(duì)象都是可調(diào)用的,因?yàn)檎{(diào)用類型對(duì)象就是調(diào)用 type 的 call 方法。而實(shí)例對(duì)象能否調(diào)用就不一定了,這取決于它的類型對(duì)象中是否定義了 call 方法,因?yàn)檎{(diào)用一個(gè)對(duì)象,本質(zhì)上是執(zhí)行其類型對(duì)象內(nèi)部的 call 方法。

class A:
    pass
    
a = A()
# 因?yàn)槲覀冏远x的類 A 里面沒有 __call__
# 所以 a 是不可以被調(diào)用的
try:
    a()
except Exception as e:
    # 告訴我們 A 的實(shí)例對(duì)象不可以被調(diào)用
    print(e)  # 'A' object is not callable    
    
# 如果我們給 A 設(shè)置了一個(gè) __call__
type.__setattr__(A, "__call__", lambda self: "這是__call__")
# 發(fā)現(xiàn)可以調(diào)用了
print(a())  # 這是__call__

我們看到這就是動(dòng)態(tài)語言的特性,即便在類創(chuàng)建完畢之后,依舊可以通過type進(jìn)行動(dòng)態(tài)設(shè)置,而這在靜態(tài)語言中是不支持的。所以type是所有類的元類,它控制了我們自定義類的生成過程,type這個(gè)古老而又強(qiáng)大的類可以讓我們玩出很多新花樣。

但是對(duì)于內(nèi)置的類,type是不可以對(duì)其動(dòng)態(tài)增加、刪除或者修改屬性的,因?yàn)閮?nèi)置的類在底層是靜態(tài)定義好的。因?yàn)閺脑创a中我們看到,這些內(nèi)置的類、包括元類,它們都是PyTypeObject對(duì)象,在底層已經(jīng)被聲明為全局變量了,或者說它們已經(jīng)作為靜態(tài)類存在了。所以type雖然是所有類型對(duì)象的元類,但是只有在面對(duì)我們自定義的類,type才具有增刪改的能力。

Python 的動(dòng)態(tài)性是解釋器將字節(jié)碼翻譯成 C 代碼的時(shí)候動(dòng)態(tài)賦予的,因此給類動(dòng)態(tài)設(shè)置屬性或方法只適用于動(dòng)態(tài)類,也就是在 py 文件中使用 class 關(guān)鍵字定義的類。

而對(duì)于靜態(tài)類、或者編寫擴(kuò)展模塊時(shí)定義的擴(kuò)展類(兩者是等價(jià)的),它們?cè)诰幾g之后已經(jīng)是指向 C 一級(jí)的數(shù)據(jù)結(jié)構(gòu)了,不需要再被解釋器解釋了,因此解釋器自然也就無法在它們身上動(dòng)手腳,畢竟彪悍的人生不需要解釋。

try:
    type.__setattr__(dict, "__call__", lambda self: "這是__call__")
except Exception as e:
    print(e)  # can't set attributes of built-in/extension type 'dict'

我們看到拋異常了,提示我們不可以給內(nèi)置/擴(kuò)展類型dict設(shè)置屬性,因?yàn)樗鼈兝@過了解釋器解釋執(zhí)行這一步,所以其屬性不能被動(dòng)態(tài)設(shè)置。

同理其實(shí)例對(duì)象亦是如此,靜態(tài)類的實(shí)例對(duì)象也不可以動(dòng)態(tài)設(shè)置屬性:

class Girl: 
    pass

g = Girl()
g.name = "古明地覺"
# 實(shí)例對(duì)象我們也可以手動(dòng)設(shè)置屬性
print(g.name)  # 古明地覺

lst = list()
try:
    lst.name = "古明地覺"
except Exception as e:
    # 但是內(nèi)置類型的實(shí)例對(duì)象是不可以的
    print(e)  # 'list' object has no attribute 'name'

可能有人奇怪了,為什么列表不行呢?答案是內(nèi)置類型的實(shí)例對(duì)象沒有__dict__屬性字典,因?yàn)橄嚓P(guān)屬性或方法底層已經(jīng)定義好了,不可以動(dòng)態(tài)添加。如果我們自定義類的時(shí)候,設(shè)置了__slots__,那么效果和內(nèi)置的類是相同的。

當(dāng)然了,我們后面會(huì)介紹如何通過動(dòng)態(tài)修改解釋器來改變這一點(diǎn),舉個(gè)栗子,不是說靜態(tài)類無法動(dòng)態(tài)設(shè)置屬性嗎?下面我就來打自己臉:

import gc

try:
    type.__setattr__(list, "ping", "pong")
except TypeError as e:
    print(e)  # can't set attributes of built-in/extension type 'list'

# 我們看到無法設(shè)置,那么我們就來改變這一點(diǎn)
attrs = gc.get_referents(tuple.__dict__)[0]
attrs["ping"] = "pong"
print(().ping)  # pong

attrs["append"] = lambda self, item: self + (item,)
print(
    ().append(1).append(2).append(3)
)  # (1, 2, 3)

我臉腫了。好吧,其實(shí)這只是我們玩的一個(gè)小把戲,當(dāng)我們介紹完整個(gè) CPython 的時(shí)候,會(huì)來專門聊一聊如何動(dòng)態(tài)修改解釋器。比如:讓元組變得可修改,讓 Python 真正利用多核等等。

從解釋器的角度看對(duì)象的調(diào)用

我們以內(nèi)置類型 float 為例,我們說創(chuàng)建一個(gè) PyFloatObject,可以通過3.14或者float(3.14)的方式。前者使用Python/C API創(chuàng)建,3.14直接被解析為 C 一級(jí)數(shù)據(jù)結(jié)構(gòu),也就是PyFloatObject實(shí)例;后者使用類型對(duì)象創(chuàng)建,通過對(duì)float進(jìn)行一個(gè)調(diào)用、將3.14作為參數(shù),最終也得到指向C一級(jí)數(shù)據(jù)結(jié)構(gòu)PyFloatObject實(shí)例。

Python/C API的創(chuàng)建方式我們已經(jīng)很清晰了,就是根據(jù)值來推斷在底層應(yīng)該對(duì)應(yīng)哪一種數(shù)據(jù)結(jié)構(gòu),然后直接創(chuàng)建即可。我們重點(diǎn)看一下通過類型調(diào)用來創(chuàng)建實(shí)例對(duì)象的方式。

如果一個(gè)對(duì)象可以被調(diào)用,它的類型對(duì)象中一定要有tp_call(更準(zhǔn)確的說成員tp_call的值是一個(gè)函數(shù)指針,不可以是0),而PyFloat_Type是可以調(diào)用的,這就說明PyType_Type內(nèi)部的tp_call是一個(gè)函數(shù)指針,這在Python的層面上我們已經(jīng)驗(yàn)證過了,下面我們?cè)賮硗ㄟ^源碼看一下。

//typeobject.c
PyTypeObject PyType_Type = {
    PyVarObject_HEAD_INIT(&PyType_Type, 0)
    "type",                                     /* tp_name */
    sizeof(PyHeapTypeObject),                   /* tp_basicsize */
    sizeof(PyMemberDef),                        /* tp_itemsize */
    (destructor)type_dealloc,                   /* tp_dealloc */
    //...                                       /* tp_hash */
    (ternaryfunc)type_call,                     /* tp_call */
    //...
}

我們看到在實(shí)例化PyType_Type的時(shí)候PyTypeObject內(nèi)部的成員tp_call被設(shè)置成了type_call。這是一個(gè)函數(shù)指針,當(dāng)我們調(diào)用PyFloat_Type的時(shí)候,會(huì)觸發(fā)這個(gè)type_call指向的函數(shù)。

因此 float(3.14) 在C的層面上等價(jià)于:

(&PyFloat_Type) -> ob_type -> tp_call(&PyFloat_Type, args, kwargs);
// 即:
(&PyType_Type) -> tp_call(&PyFloat_Type, args, kwargs);
// 而在創(chuàng)建 PyType_Type 的時(shí)候,給 tp_call 成員傳遞的是 type_call
// 因此最終相當(dāng)于
type_call(&PyFloat_Type, args, kwargs)

如果用 Python 來演示這一過程的話:

# float(3.14),等價(jià)于
f1 = float.__class__.__call__(float, 3.14)
# 等價(jià)于
f2 = type.__call__(float, 3.14)

print(f1, f2)  # 3.14 3.14

這就是 float(3.14) 的秘密,相信list、dict在實(shí)例化的時(shí)候是怎么做的,你已經(jīng)猜到了,做法是相同的。

# lst = list("abcd")
lst = list.__class__.__call__(list, "abcd")
print(lst)  # ['a', 'b', 'c', 'd']

# dct = dict([("name", "古明地覺"), ("age", 17)])
dct = dict.__class__.__call__(dict, [("name", "古明地覺"), ("age", 17)])
print(dct)  # {'name': '古明地覺', 'age': 17}

最后我們來圍觀一下 type_call 函數(shù),我們說 type 的 call 方法,在底層對(duì)應(yīng)的是 type_call 函數(shù),它位于Object/typeobject.c中。

static PyObject *
type_call(PyTypeObject *type, PyObject *args, PyObject *kwds)
{  
    // 如果我們調(diào)用的是 float
    // 那么顯然這里的 type 就是 &PyFloat_Type
    
    // 這里是聲明一個(gè)PyObject *
    // 顯然它是要返回的實(shí)例對(duì)象的指針
    PyObject *obj;
  
    // 這里會(huì)檢測(cè) tp_new是否為空,tp_new是什么估計(jì)有人已經(jīng)猜到了
    // 我們說__call__對(duì)應(yīng)底層的tp_call
    // 顯然__new__對(duì)應(yīng)底層的tp_new,這里是為實(shí)例對(duì)象分配空間
    if (type->tp_new == NULL) {
        // tp_new 是一個(gè)函數(shù)指針,指向具體的構(gòu)造函數(shù)
        // 如果 tp_new 為空,說明它沒有構(gòu)造函數(shù)
        // 因此會(huì)報(bào)錯(cuò),表示無法創(chuàng)建其實(shí)例
        PyErr_Format(PyExc_TypeError,
                     "cannot create '%.100s' instances",
                     type->tp_name);
        return NULL;
    }
  
    //通過tp_new分配空間
    //此時(shí)實(shí)例對(duì)象就已經(jīng)創(chuàng)建完畢了,這里會(huì)返回其指針
    obj = type->tp_new(type, args, kwds);
    //類型檢測(cè),暫時(shí)不用管
    obj = _Py_CheckFunctionResult((PyObject*)type, obj, NULL);
    if (obj == NULL)
        return NULL;

    //我們說這里的參數(shù)type是類型對(duì)象,但也可以是元類
    //元類也是由PyTypeObject結(jié)構(gòu)體實(shí)例化得到的
    //元類在調(diào)用的時(shí)候執(zhí)行的依舊是type_call
    //所以這里是檢測(cè)type指向的是不是PyType_Type
    //如果是的話,那么實(shí)例化得到的obj就不是實(shí)例對(duì)象了,而是類型對(duì)象
    //要單獨(dú)檢測(cè)一下
    if (type == &PyType_Type &&
        PyTuple_Check(args) && PyTuple_GET_SIZE(args) == 1 &&
        (kwds == NULL ||
         (PyDict_Check(kwds) && PyDict_GET_SIZE(kwds) == 0)))
        return obj;

    //tp_new應(yīng)該返回相應(yīng)類型對(duì)象的實(shí)例對(duì)象(的指針)
    //但如果不是,就直接將這里的obj返回
    //此處這么做可能有點(diǎn)難理解,我們一會(huì)細(xì)說
    if (!PyType_IsSubtype(Py_TYPE(obj), type))
        return obj;
  
    //拿到obj的類型
    type = Py_TYPE(obj);
    //執(zhí)行 tp_init
    //顯然這個(gè)tp_init就是__init__函數(shù)
    //這與Python中類的實(shí)例化過程是一致的。
    if (type->tp_init != NULL) {
        //將tp_new返回的對(duì)象作為self,執(zhí)行 tp_init
        int res = type->tp_init(obj, args, kwds);
        if (res < 0) {
            //執(zhí)行失敗,將引入計(jì)數(shù)減1,然后將obj設(shè)置為NULL
            assert(PyErr_Occurred());
            Py_DECREF(obj);
            obj = NULL;
        }
        else {
            assert(!PyErr_Occurred());
        }
    }
    //返回obj
    return obj;
}

因此從上面我們可以看到關(guān)鍵的部分有兩個(gè):

  • 調(diào)用類型對(duì)象的 tp_new 指向的函數(shù)為實(shí)例對(duì)象申請(qǐng)內(nèi)存
  • 調(diào)用 tp_init 指向的函數(shù)為實(shí)例對(duì)象進(jìn)行初始化,也就是設(shè)置屬性

所以這對(duì)應(yīng)Python中的__new__和__init__,我們說__new__是為實(shí)例對(duì)象開辟一份內(nèi)存,然后返回指向這片內(nèi)存(對(duì)象)的指針,并且該指針會(huì)自動(dòng)傳遞給__init__中的self。

class Girl:

    def __new__(cls, name, age):
        print("__new__方法執(zhí)行啦")
        # 寫法非常固定
        # 調(diào)用object.__new__(cls)就會(huì)創(chuàng)建Girl的實(shí)例對(duì)象
        # 因此這里的cls指的就是這里的Girl,注意:一定要返回
        # 因?yàn)開_new__會(huì)將自己的返回值交給__init__中的self
        return object.__new__(cls)

    def __init__(self, name, age):
        print("__init__方法執(zhí)行啦")
        self.name = name
        self.age = age


g = Girl("古明地覺", 16)
print(g.name, g.age)
"""
__new__方法執(zhí)行啦
__init__方法執(zhí)行啦
"""

__new__里面的參數(shù)要和__init__里面的參數(shù)保持一致,因?yàn)槲覀儠?huì)先執(zhí)行__new__,然后解釋器會(huì)將__new__的返回值和我們傳遞的參數(shù)組合起來一起傳遞給__init__。因此__new__里面的參數(shù)除了cls之外,一般都會(huì)寫

args和

*kwargs。

然后再回過頭來看一下type_call中的這幾行代碼:

static PyObject *
type_call(PyTypeObject *type, PyObject *args, PyObject *kwds)
{  
    //......
    //......
    if (!PyType_IsSubtype(Py_TYPE(obj), type))
        return obj;
  
    //......
    //......
}

我們說tp_new應(yīng)該返回該類型對(duì)象的實(shí)例對(duì)象,而且一般情況下我們是不寫__new__的,會(huì)默認(rèn)執(zhí)行。但是我們一旦重寫了,那么必須要手動(dòng)返回object.__new__(cls)??扇绻覀儾环祷?,或者返回其它的話,會(huì)怎么樣呢?

class Girl:

    def __new__(cls, *args, **kwargs):
        print("__new__方法執(zhí)行啦")
        instance = object.__new__(cls)
        # 打印看看instance到底是個(gè)什么東東
        print("instance:", instance)
        print("type(instance):", type(instance))
        
        # 正確做法是將instance返回
        # 但是我們不返回, 而是返回個(gè) 123
        return 123

    def __init__(self, name, age):
        print("__init__方法執(zhí)行啦")


g = Girl()
"""
__new__方法執(zhí)行啦
instance: <__main__.Girl object at 0x000002C0F16FA1F0>
type(instance): <class '__main__.Girl'>
"""

這里面有很多可以說的點(diǎn),首先就是 init 里面需要兩個(gè)參數(shù),但是我們沒有傳,卻還不報(bào)錯(cuò)。原因就在于這個(gè) init 壓根就沒有執(zhí)行,因?yàn)?new 返回的不是 Girl 的實(shí)例對(duì)象。

通過打印 instance,我們知道了object.__new__(cls) 返回的就是 cls 的實(shí)例對(duì)象,而這里的cls就是Girl這個(gè)類本身。我們必須要返回instance,才會(huì)執(zhí)行對(duì)應(yīng)的__init__,否則__new__直接就返回了。我們?cè)谕獠縼泶蛴∫幌聞?chuàng)建的實(shí)例對(duì)象吧,看看結(jié)果:

class Girl:

    def __new__(cls, *args, **kwargs):
        return 123

    def __init__(self, name, age):
        print("__init__方法執(zhí)行啦")


g = Girl()
print(g, type(g))  # 123 <class 'int'>

我們看到打印的是123,所以再次總結(jié)一些tp_new和tp_init之間的區(qū)別,當(dāng)然也對(duì)應(yīng)__new__和__init__的區(qū)別:

  • tp_new:為該類型對(duì)象的實(shí)例對(duì)象申請(qǐng)內(nèi)存,在Python的__new__方法中通過object.__new__(cls)的方式申請(qǐng),然后將其返回
  • tp_init:tp_new的返回值會(huì)自動(dòng)傳遞給self,然后為self綁定相應(yīng)的屬性,也就是進(jìn)行實(shí)例對(duì)象的初始化

但如果tp_new返回的不是對(duì)應(yīng)類型的實(shí)例對(duì)象的指針,比如type_call中第一個(gè)參數(shù)接收的&PyFloat_Type,但是tp_new中返回的卻是PyLongObject *,所以此時(shí)就不會(huì)執(zhí)行tp_init。

以上面的代碼為例,我們Girl中的__new__應(yīng)該返回Girl的實(shí)例對(duì)象才對(duì),但實(shí)際上返回了整型,因此類型不一致,所以不會(huì)執(zhí)行__init__。

下面我們可以做總結(jié)了,通過類型對(duì)象去創(chuàng)建實(shí)例對(duì)象的整體流程如下:

  • 第一步:獲取類型對(duì)象的類型對(duì)象,說白了就是元類,執(zhí)行元類的 tp_call 指向的函數(shù),即 type_call
  • 第二步:type_call 會(huì)調(diào)用該類型對(duì)象的 tp_new 指向的函數(shù),如果 tp_new 為 NULL,那么會(huì)到 tp_base 指定的父類里面去尋找 tp_new。在新式類當(dāng)中,所有的類都繼承自 object,因此最終會(huì)執(zhí)行 object 的 __new__。然后通過訪問對(duì)應(yīng)類型對(duì)象中的 tp_basicsize 信息,這個(gè)信息記錄著該對(duì)象的實(shí)例對(duì)象需要占用多大的內(nèi)存,繼而完成申請(qǐng)內(nèi)存的操作

調(diào)用type_new 創(chuàng)建完對(duì)象之后,就會(huì)進(jìn)行實(shí)例對(duì)象的初始化,會(huì)將指向這片空間的指針交給 tp_init,但前提是 tp_new 返回的實(shí)例對(duì)象的類型要一致。

所以都說 Python 在實(shí)例化的時(shí)候會(huì)先調(diào)用 new 方法,再調(diào)用 init 方法,相信你應(yīng)該知道原因了,因?yàn)樵谠创a中先調(diào)用 tp_new、再調(diào)用的 tp_init。

static PyObject *
type_call(PyTypeObject *type, PyObject *args, PyObject *kwds)
{  
    //調(diào)用__new__方法, 拿到其返回值
    obj = type->tp_new(type, args, kwds);

    if (type->tp_init != NULL) {
        //將__new__返回的實(shí)例obj,和args、kwds組合起來
        //一起傳給 __init__
        //其中 obj 會(huì)傳給 self,
        int res = type->tp_init(obj, args, kwds);
        //......
    return obj;
}

所以源碼層面表現(xiàn)出來的,和我們?cè)?Python 層面看到的是一樣的。

小結(jié)

到此,我們就從 Python 和解釋器兩個(gè)層面了解了對(duì)象是如何調(diào)用的,更準(zhǔn)確的說我們是從解釋器的角度對(duì) Python 層面的知識(shí)進(jìn)行了驗(yàn)證,通過 tp_new 和 tp_init 的關(guān)系,來了解 newinit 的關(guān)系。

另外,對(duì)象調(diào)用遠(yuǎn)不止我們目前說的這么簡(jiǎn)單,更多的細(xì)節(jié)隱藏在了幕后,只不過現(xiàn)在沒辦法將其一次性全部挖掘出來。后續(xù)我們會(huì)循序漸進(jìn),一點(diǎn)點(diǎn)揭開它什么面紗,并且在這個(gè)過程中還會(huì)不斷地學(xué)習(xí)到新的東西。比如說,實(shí)例對(duì)象在調(diào)用方法的時(shí)候會(huì)自動(dòng)將實(shí)例本身作為參數(shù)傳遞給 self,那么它為什么傳遞呢?解釋器在背后又做了什么工作呢?這些我們就以后慢慢說吧。

到此這篇關(guān)于淺談Python中對(duì)象是如何被調(diào)用的的文章就介紹到這了,更多相關(guān)Python對(duì)象調(diào)用內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • python把轉(zhuǎn)列表為集合的方法

    python把轉(zhuǎn)列表為集合的方法

    在本篇文章里小編給大家分享了關(guān)于python把轉(zhuǎn)列表為集合的方法以及相關(guān)實(shí)例內(nèi)容,有興趣的朋友們學(xué)習(xí)下。
    2019-06-06
  • Python?使用和高性能技巧操作大全

    Python?使用和高性能技巧操作大全

    這篇文章主要介紹了Python?使用和高性能技巧總結(jié),對(duì)一些python易混淆的操作進(jìn)行對(duì)比,不少 Python 的用戶是從以前 C/C++ 遷移過來的,這兩種語言在語法、代碼風(fēng)格等方面有些不同,本節(jié)簡(jiǎn)要進(jìn)行介紹,需要的朋友可以參考下
    2022-01-01
  • Python數(shù)據(jù)可視化之使用matplotlib繪制簡(jiǎn)單圖表

    Python數(shù)據(jù)可視化之使用matplotlib繪制簡(jiǎn)單圖表

    這篇文章主要為大家詳細(xì)介紹了使用matplotlib繪制簡(jiǎn)單圖表的方法,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助
    2022-03-03
  • Python中最快的循環(huán)姿勢(shì)實(shí)例詳解

    Python中最快的循環(huán)姿勢(shì)實(shí)例詳解

    python給我們提供了多個(gè)循環(huán)方法,比如while循環(huán)、for循環(huán)等,下面這篇文章主要給大家介紹了關(guān)于Python中最快的循環(huán)姿勢(shì),需要的朋友可以參考下
    2021-11-11
  • Python使用Matplotlib實(shí)現(xiàn)創(chuàng)建動(dòng)態(tài)圖形

    Python使用Matplotlib實(shí)現(xiàn)創(chuàng)建動(dòng)態(tài)圖形

    動(dòng)態(tài)圖形是使可視化更具吸引力和用戶吸引力的好方法,它幫助我們以有意義的方式展示數(shù)據(jù)可視化,本文將利用Matplotlib實(shí)現(xiàn)繪制一些常用動(dòng)態(tài)圖形,希望對(duì)大家有所幫助
    2024-02-02
  • python實(shí)現(xiàn)按行分割文件

    python實(shí)現(xiàn)按行分割文件

    這篇文章主要為大家詳細(xì)介紹了python如何實(shí)現(xiàn)按行分割文件,python按指定行數(shù)分割文件,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-07-07
  • 淺談Python2獲取中文文件名的編碼問題

    淺談Python2獲取中文文件名的編碼問題

    下面小編就為大家分享一篇淺談Python2獲取中文文件名的編碼問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2018-01-01
  • 如何基于python實(shí)現(xiàn)單目三維重建詳解

    如何基于python實(shí)現(xiàn)單目三維重建詳解

    單目三維重建是根據(jù)單個(gè)攝像頭的運(yùn)動(dòng)模擬雙目視覺獲得物體在空間中的三維視覺信息,下面這篇文章主要給大家介紹了關(guān)于如何基于python實(shí)現(xiàn)單目三維重建的相關(guān)資料,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2022-06-06
  • python使用pygame實(shí)現(xiàn)笑臉乒乓球彈珠球游戲

    python使用pygame實(shí)現(xiàn)笑臉乒乓球彈珠球游戲

    這篇文章主要為大家詳細(xì)介紹了python使用pygame實(shí)現(xiàn)笑臉乒乓球彈珠球游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-11-11
  • Python搭建HTTP服務(wù)過程圖解

    Python搭建HTTP服務(wù)過程圖解

    這篇文章主要介紹了Python搭建HTTP服務(wù)過程圖解,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-12-12

最新評(píng)論