目錄
#寫在前面
1、一切對象
模型-對象,值以及型別" >1.1 資料模型-對象,值以及型別
1.2 物件小結
" >變數
2.3 指针?引用?名字?
2.4 名字支持的操作
3、绑定的艺术
3.1 变量的声明
3.2 名字的定义
3.3 引用不可变对象
3.4 引用可变对象
3.4.1 示例1:改变可变对象的值
3.4.2 示例2:可变对象Python對象,名字以及綁定
3.4.3 示例3:Python對象,名字以及綁定可变对象
3.5 共享对象
3.5.1 共享不可变对象
3.5.2 Python對象,名字以及綁定
3.6 绑定何时发生
4、其他说明
参考
脚注
首頁 後端開發 Python教學 Python對象,名字以及綁定

Python對象,名字以及綁定

May 28, 2017 am 10:00 AM

Python進階- 物件,名字以及綁定

#寫在前面

如非特別說明,下文均基於Python3

1、一切對象

Python哲學:

Python中一切皆物件

1.1 資料模型-對象,值以及型別

物件是Python對資料的抽象。 Python程式中所有的資料都是物件或物件之間的關係表示的。 (在某種意義上,為順應馮·諾依曼「儲存式計算機」的模型,Python中的程式碼也是物件。)

Python中每一個物件都有一個身分標識,一個值以及一個類型。物件創建後,其身分標識絕對不會改變;可以把身分識別當作物件在記憶體中的位址。 is運算子比較兩個物件的身份識別;id()函數傳回表示物件身分識別的整數

CPython實作細節:CPython解釋器的實作中,id(x)函數傳回儲存x的記憶體位址

物件的型別決定了物件支援的運算(例如,物件有長度麼?),同時也決定了該型別物件可能的值。 type()函數傳回物件的型別(這個型別本身也是一個物件)。與其身分識別一樣,物件的型別也是不可改變的[1]

一些物件的值可以改變。可改變值的物件也稱為可變的(mutable);一旦創建,值恆定的物件也叫做不可變的(immutable)。 (當不可變容器物件中包含對可變物件的引用時,可變物件值改變時,這個不可變容器物件值也被改變了;然而,不可變容器物件仍被認為是不可變的,因為物件所包含的值集合確實是不可改變的。中包含了對其他物件的引用;那麼這些引用可以看做地址,即使地址指向的內容改變了,集合中的地址本身是沒有改變的。 所以不可變容器對象還是不可變對象。取決於其類型;例如,數字,字串和元組是不可變的,但字典和列表是可變的。

物件從不明確銷毀;當物件不可達時會被垃圾回收(譯註:物件沒有引用了)。解釋器實作允許垃圾回收延時或直接忽略——這取決於垃圾回收是如何實現的,只要沒有可達物件被回收。

CPython實作細節: CPython解釋器實作使用引用計數模式延時探測循環連結垃圾,這種方式可回收大多數不可達對象,但並不能保證循環引用的垃圾會被回收。查看gc模組的文件以了解控制循環垃圾回收的更多資訊。其他解釋器實作與CPython不同,CPython實作將來也許會改變。因此不能依賴垃圾回收器來回收不可達物件(因此應該總是明確關閉檔案物件。)。

需要注意,使用工具的調試追蹤功能可能會導致應該被回收的物件一直存活,使用try...#except語句捕獲異常也可以保持物件的存活。

有些物件引用瞭如檔案或視窗的外部資源。不言而喻持有資源的物件被垃圾回收後,資源也會被釋放,但因為沒有機制保證垃圾回收一定會發生,這些資源持有對像也提供了顯式釋放外部資源的方式,通常使用close()方法。強烈建議在程序中明確釋放資源。 try...<a href="http://www.php.cn/wiki/207.html" target="_blank">final</a>ly語句和with語句為釋放資源提供了便利。

有些物件包含對其他物件的引用,這些物件被稱為 容器。元組,列表和字典都是容器。引用的容器值的一部分。大多數情況下,當談論容器的值時,我們暗指容器包含的物件值集合,而不是物件的身份識別集合;然而,當談論容器的可變性時,我們暗指容器包含的物件的身份識別。因此,如果不可變物件(如元組)包含可變物件的引用,則可變物件改變時,其值也改變了。

類型影響物件的絕大多數行為。在某些情況下甚至對象的身份標識的重要性也受到影響:對於不可變類型,計算新值的操作實際上可能會返回已存在的,值和類型一樣的對象的引用,然而對於可變對象來說這是不可能的。例如,語句a = 1; b = 1執行之後,ab可能會也可能不會引用具有相同值得同一個對象,這取決於解釋器實作。但是語句c = []; d = []執行之後,可以保證cd會指向不同的,唯一的新建立的空列表。 (注意c = d = []分配相同的物件給cd)

Note: 以上翻譯自《The Python Language References#Data model#Objects, values, types》 3.6.1版本。

1.2 物件小結

官方文件已經對Python 物件做了詳細的描述,這裡總結一下。

物件的三個特性:

  • 身份識別
    唯一識別物件;不可變;CPython#解釋器實作為物件的記憶體位址。
    操作:id(),內建函數id()函數傳回標識物件的一個整數;is比較兩個物件的身份識別。
    範例:

    >>> id(1)
    1470514832
    >>> 1 is 1
    True
    登入後複製
  • 類型
    決定物件支援的操作,可能的值;不可變。
    操作:type(),內建函數傳回物件的類型
    範例:

    >>> type('a')
    <class></class>
    登入後複製

  • 數據,可變/不可變
    操作:==運算子用於比較兩個物件的值是否相等,其他比較運算子比較物件間大小情況。
    範例:

    >>> 'python'
    'python'
    >>> 1 == 2
    False
    登入後複製

可變與不可變:一般認為,值不可變的物件是不可變對象,值可變的物件是可變對象,但是要注意不可變集合對象包含可變對象引用成員的情況。

Python中的物件:


#
# -*- coding: utf-8 -*-# filename: hello.py&#39;a test module&#39;author = &#39;Richard Cheng&#39;import sysclass Person(object):    &#39;&#39;&#39; Person class&#39;&#39;&#39;

    def init(self, name, age):        self.name = name        self.age = agedef tset():    print(sys.path)
    p = Person(&#39;Richard&#39;, 20)    print(p.name, &#39;:&#39;, p.age)def main():
    tset()if name == &#39;main&#39;:
    main()
登入後複製


##這段

Python程式碼中有很多對象,包括hello這個模組對象,創建的Person類別對象,幾個函數如test, main函數對象,數字,字串,甚至程式碼本身也是對象。

2、名字即「

變數

幾乎所有語言中都有「變數」的說法,嚴格說來,

Python#中的變數不應該叫變量,稱為名字更貼切。

以下翻譯自Code Like a Pythonista: Idiomatic Python # Python has "names"

2.1 其他語言有變數
其他語言中,為變數分配值就像將值放到「盒子」裡。


int a = 1;

Python對象,名字以及綁定

a現在有了一個整數1

為同一個變數分配值替換掉盒子的內容:


a =2;

Python對象,名字以及綁定

現在盒子

a中放了整數2

將一個變數分配給另一個變量,拷貝變數的值,並把它放到新的盒子裡:


int b = a;

Python對象,名字以及綁定

Python對象,名字以及綁定

#b是第二個盒子,裝有整數2的拷貝。盒子a有一份單獨的拷貝。

2.2 Python有名字

Python中,名字或識別碼就像將一個標籤捆綁到物件上一樣。
a = 1

Python對象,名字以及綁定#

这里,整数对象1有一个叫做a的标签。

如果重新给a分配值,只是简单的将标签移动到另一个对象:
a = 2

Python對象,名字以及綁定
Python對象,名字以及綁定

现在名字a贴到了整数对象2上面。原来的整数对象1不再拥有标签a,或许它还存在,但是不能通过标签a访问它了(当对象没有任何引用时,会被回收。)

如果将一个名字分配给另一名字,只是将另一个名字标签捆绑到存在的对象上:
b = a

Python對象,名字以及綁定

名字b只是绑定到与a引用的相同对象上的第二个标签而已。

虽然在Python中普遍使用“变量”(因为“变量”是普遍术语),真正的意思是名字或者标识符。Python中的变量是值得标签,不是装值得盒子。

2.3 指针?引用?名字?

C/C++中有指针,Java中有引用,Python中的名字在一定程度上等同于指针和引用。

2.1节中其他语言的例子,也只是针对于它们的基本类型而言的,若是指针或者引用,表现也跟Python的名字一样。这也在一定程度上说明了Python面向对象贯彻得更加彻底。

2.4 名字支持的操作

可以对一个变量做什么?声明变量,使用变量,修改变量的值。名字作为Python中的一个重要概念,可以对它做的操作有:

  • 定义;名字需要先定义才能使用,与变量需要先声明一样。

  • 绑定:名字的单独存在没有意义,必须将它绑定到一个对象上。

  • Python對象,名字以及綁定:名字可以重新引用另一个对象,这个操作就是Python對象,名字以及綁定。

  • 引用:为什么要定义名字,目的是使用它。

3、绑定的艺术

名字以及对象,它们之间必然会发生些什么。

3.1 变量的声明

其他如C/C++Java的高级语言,变量在使用前需要声明,或者说定义。以下在Java中声明变量:


public static void main(String[] args) {        int i = 0; // 先声明,后使用
        System.out.println(i); // 使用变量i}
登入後複製


这样,在可以访问到变量i所在作用域的地方,既可以使用i了。还有其他声明变量的方法么?好像没有了。

3.2 名字的定义

Python中有多种定义名字的途径,如函数定义,函数名就是引用函数对象的名字;类定义,类名就是指向类对象的名字,模块定义,模块名就是引用模块对象的名字;当然,最直观的还是赋值语句。

赋值语句

官方对赋值语句做了这样的说明(地址):

Assignment statements are used to (re)bind names to values and to modify attributes or items of mutable objects.

即:

赋值语句被用来将名字绑定或者Python對象,名字以及綁定给值,也用来修改可变对象的属性或项

那么,我们关心的,就是赋值语句将名字和值(对象)绑定起来了。

看一个简单的赋值语句:


a = 9
登入後複製


Python在处理这条语句时:

  1. 首先在内存中创建一个对象,表示整数9:

Python對象,名字以及綁定

  1. 然后创建名字a,并把它指向上述对象:

Python對象,名字以及綁定

上述过程就是通过赋值语句的名字对象绑定了。名字首次和对象绑定后,这个名字就定义在当前命名空间了,以后,在能访问到这个命名空间的作用域中可以引用该名字了。

3.3 引用不可变对象

定义完名字之后,就可以使用名字了,名字的使用称为“引用名字”。当名字指向可变对象和不可变对象时,使用名字会有不同的表现。


a = 9       #1a = a + 1   #2
登入後複製


语句1执行完后,名字a指向表示整数9的对象:

Python對象,名字以及綁定

由于整数是不可变对象,所以在语句2处引用名字a,试图将表示整数9的对象 + 1,但该对象的值是无法改变的。因此就将该对象表示的整数值91,以整数10新建一个整数对象:

Python對象,名字以及綁定

接下来,将名字a Python對象,名字以及綁定 到新建对象上,并移除名字对原对象的引用:

Python對象,名字以及綁定

使用id()函数,可以看到名字a指向的对象地址确实发生了改变:


>>> a = 9>>> id(a)1470514960>>> a = a + 1>>> id(a)1470514976
登入後複製


3.4 引用可变对象
3.4.1 示例1:改变可变对象的值

可变对象可以改变其值,并且不会造成地址的改变:


>>> list1 = [1]>>> id(list1)42695136>>> list1.append(2)>>> id(list1)42695136>>> list1
[1, 2]>>>
登入後複製


执行语句list1 = [1],创建一个list对象,并且其值集中添加1,将名字list1指向该对象:

Python對象,名字以及綁定

执行语句list1.append(2),由于list是可变对象,可以直接在其值集中添加2

Python對象,名字以及綁定

值得改变并没有造成list1引用的对象地址的改变。

3.4.2 示例2:可变对象Python對象,名字以及綁定

再来看一个比较“奇怪”的例子:


values = [1, 2, 3]
values[1] = valuesprint(values)
登入後複製


一眼望去,期待的结果应该是


[1, [1, 2, 3], 3]
登入後複製


但实际上结果是:


[1, [...], 3]
登入後複製


我们知道list中的元素可以是各种类型的,list类型是可以的:

Python對象,名字以及綁定

3.4.3 示例3:Python對象,名字以及綁定可变对象

观察以下代码段:


>>> list1 = [1]>>> id(list1)42695136>>> list1 = [1, 2]>>> id(list1)42717432
登入後複製


两次输出的名字list1引用对象的地址不一样,这是因为第二次语句list 1 = [1, 2] 对名字做了Python對象,名字以及綁定:

Python對象,名字以及綁定

3.5 共享对象

当两个或两个以上的名字引用同一个对象时,我们称这些名字共享对象。共享的对象可变性不同时,表现会出现差异。

3.5.1 共享不可变对象

函数attempt_change_immutable将参数i的值修改为2


def attempt_change_immutable(i):
    i = 2i = 1print(i)
attempt_change_immutable(i)print(i)
登入後複製


Output:


11
登入後複製


如果你对输出不感到意外,说明不是新手了 ^_^。

  1. 首先,函数的参数i与全局名字i不是在同一命名空间中,所以它们之间不相互影响。

  2. 调用函数时,将两个名字i都指向了同一个整数对象。

  3. 函数中修改i的值为2, 因为整数对象不可变,所以新建值为2的整数对象,并把函数中的名字i绑定到对象上。

  4. 全局名字i的绑定关系并没有被改变。

Python對象,名字以及綁定

Python對象,名字以及綁定

值得注意的是,这部分内容与命名空间和作用域有关系,另外有文章介绍它们,可以参考。

3.5.2 Python對象,名字以及綁定

函数attempt_change_mutable为列表增加字符串。


def attempt_change_mutable(list_param):
    list_param.append(&#39;test&#39;)

list1 = [1]print(list1)
attempt_change_mutable(list1)print(list1)
登入後複製


output:


[1]
[1, &#39;test&#39;]
登入後複製


可以看到函数成功改变了列表list1的值。传递参数时,名字list_param引用了与名字list1相同的对象,这个对象是可变的,在函数中成功修改了对象的值。

首先,名字list_param与名字list1指向对象:

Python對象,名字以及綁定

然后,通过名字list_param修改了对象的值:

Python對象,名字以及綁定

最后,这个修改对名字list1可见。

3.6 绑定何时发生

总的来说,触发名字对象绑定的行为有以下一些:

  • 赋值操作;a = 1

  • 函数定义;

    def test():
        pass
    登入後複製

    将名字test绑定到函数对象

  • 类定义:

    class Test(object):
        pass
    登入後複製

    将名字Test绑定到类对象

  • 函数传参;

    def test(i):
        pass
    test(1)
    登入後複製

    将名字i绑定到整数对象1

  • import语句:

    import sys
    登入後複製

    将名字sys绑定到指定模块对象。

  • <a href="http://www.php.cn/wiki/125.html" target="_blank">for</a>循环

    for i in range(10):
        pass
    登入後複製

    每次循环都会绑定/Python對象,名字以及綁定名字i

  • as操作符

    with open(&#39;dir&#39;, &#39;r&#39;) as f:
        pass
    
    try:
        pass
    except NameError as ne:
        pass
    登入後複製

    with open语句,异常捕获语句中的as都会发生名字的绑定

    4、其他说明

    待续。。。

    参考

    1. The Python Language References#Data model# Objects, values, types

    2. Python的名字绑定

    3. Python一切皆对象

    4. Code Like a Pythonista: Idiomatic Python

    5. python基础(5):深入理解 python 中的赋值、引用、拷贝、作用域

    脚注

    [1] 在特定的控制条件下,改变对象的类型是可能的。但不是一种明智的做法,如果处理不当的话,会发生一些奇怪的行为。

    以上是Python對象,名字以及綁定的詳細內容。更多資訊請關注PHP中文網其他相關文章!

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

使用PHP的json_encode()函數將陣列或物件轉換為JSON字串 使用PHP的json_encode()函數將陣列或物件轉換為JSON字串 Nov 03, 2023 pm 03:30 PM

JSON(JavaScriptObjectNotation)是一種輕量級的資料交換格式,已成為Web應用程式之間資料交換的常用格式。 PHP的json_encode()函數可以將陣列或物件轉換為JSON字串。本文將介紹如何使用PHP的json_encode()函數,包括語法、參數、傳回值以及具體的範例。語法json_encode()函數的語法如下:st

使用Python的__contains__()函數定義物件的包含操作 使用Python的__contains__()函數定義物件的包含操作 Aug 22, 2023 pm 04:23 PM

使用Python的__contains__()函數定義物件的包含操作Python是一種簡潔而強大的程式語言,提供了許多強大的功能來處理各種類型的資料。其中之一是透過定義__contains__()函數來實現物件的包含操作。本文將介紹如何使用__contains__()函數來定義物件的包含操作,並且給予一些範例程式碼。 __contains__()函數是Pytho

如何將 MySQL 查詢結果陣列轉換為物件? 如何將 MySQL 查詢結果陣列轉換為物件? Apr 29, 2024 pm 01:09 PM

將MySQL查詢結果陣列轉換為物件的方法如下:建立一個空物件陣列。循環結果數組並為每一行建立一個新的物件。使用foreach迴圈將每一行的鍵值對賦給新物件的對應屬性。將新物件加入到物件數組中。關閉資料庫連線。

原始碼探針:Python 中物件是如何被呼叫的? 原始碼探針:Python 中物件是如何被呼叫的? May 11, 2023 am 11:46 AM

楔子我們知道物件被創建,主要有兩種方式,一種是透過Python/CAPI,另一種是透過呼叫類型物件。對於內建類型的實例物件而言,這兩種方式都是支援的,例如列表,我們即可以透過[]創建,也可以透過list(),前者是Python/CAPI,後者是呼叫類型物件。但對於自訂類別的實例物件而言,我們只能透過呼叫類型物件的方式來創建。而一個物件如果可以被調用,那麼這個物件就是callable,否則就不是callable。而決定一個物件是不是callable,就取決於其對應的型別物件中是否定義了某個方法。如

PHP 函數如何傳回物件? PHP 函數如何傳回物件? Apr 10, 2024 pm 03:18 PM

PHP函數可以透過使用return語句後接物件實例來傳回對象,從而將資料封裝到自訂結構中。語法:functionget_object():object{}。這允許創建具有自訂屬性和方法的對象,並以對象的形式處理資料。

使用Python的__le__()函數定義兩個物件的小於等於比較 使用Python的__le__()函數定義兩個物件的小於等於比較 Aug 21, 2023 pm 09:29 PM

標題:使用Python的__le__()函數定義兩個物件的小於等於比較在Python中,我們可以透過使用特殊方法來定義物件之間的比較操作。其中之一就是__le__()函數,它用來定義小於等於比較。 __le__()函數是Python中的一個魔法方法,並且是一種用於實現「小於等於」操作的特殊函數。當我們使用小於等於運算子(&lt;=)比較兩個物件時,Python

C++ 函式回傳物件時有什麼需要注意的? C++ 函式回傳物件時有什麼需要注意的? Apr 19, 2024 pm 12:15 PM

在C++中,函數傳回物件需要注意三點:物件的生命週期由呼叫者負責管理,以防止記憶體洩漏。避免懸垂指針,透過動態分配記憶體或返回物件本身來確保物件在函數返回後仍然有效。編譯器可能會最佳化傳回物件的副本生成,以提高效能,但如果物件是值語義傳遞的,則無需副本生成。

數組和物件在 PHP 中的差異是什麼? 數組和物件在 PHP 中的差異是什麼? Apr 29, 2024 pm 02:39 PM

PHP中,數組是有序序列,以索引存取元素;物件是具有屬性和方法的實體,透過new關鍵字建立。數組存取透過索引,物件存取通過屬性/方法。數組值傳遞,物件參考傳遞。

See all articles