>  기사  >  백엔드 개발  >  Python 객체, 이름 및 바인딩

Python 객체, 이름 및 바인딩

大家讲道理
大家讲道理원래의
2017-05-28 10:00:571500검색

Python고급 - 객체, 이름 및 바인딩

이 앞에 작성됩니다

별도의 언급이 없는 한 다음은 Python3Python3

1、一切皆对象

Python哲学:

Python中一切皆对象

1.1 数据模型-对象,值以及类型

对象是Python对数据的抽象。Python程序中所有的数据都是对象或对象之间的关系表示的。(在某种意义上,为顺应冯·诺依曼“存储式计算机”的模型,Python中的代码也是对象。)

Python中每一个对象都有一个身份标识,一个值以及一个类型。对象创建后,其身份标识绝对不会改变;可以把身份标识当做对象在内存中的地址。is操作符比较两个对象的身份标识;id()函数返回表示对象身份标识的整数

CPython实现细节:CPython解释器的实现中,id(x)函数返回存储x的内存地址

对象的类型决定了对象支持的操作(例如,对象有长度么?),同时也决定了该类型对象可能的值。type()函数返回对象的类型(这个类型本身也是一个对象)。与其身份标识一样,对象的类型也是不可改变的[1]

一些对象的值可以改变。可改变值的对象也称作可变的(mutable);一旦创建,值恒定的对象也叫做 不可变的(immutable)。(当不可变容器对象中包含对可变对象的引用时,可变对象值改变时,这个不可变容器对象值也被改变了;然而,不可变容器对象仍被认为是不可变的,因为对象包含的值集合确实是不可改变的。因此,不可变性不是严格等同于拥有不可变的值,它很微妙。) (译注:首先不可变容器对象的值是一个集合,集合中包含了对其他对象的引用;那么这些引用可以看做地址,即使地址指向的内容改变了,集合中的地址本身是没有改变的。所以不可变容器对象还是不可变对象。) 对象的可变性取决于其类型;例如,数字,字符串和元组是不可变的,但字典和列表是可变的。

对象从不显式销毁;当对象不可达时会被垃圾回收(译注:对象没有引用了)。一种解释器实现允许垃圾回收延时或者直接忽略——这取决于垃圾回收是如何实现的,只要没有可达对象被回收。

CPython实现细节: CPython解释器实现使用引用计数模式延时探测循环链接垃圾,这种方式可回收大多数不可达对象,但并不能保证Python 객체, 이름 및 바인딩的垃圾被回收。查看gc模块的文档了解控制循环垃圾回收的更多信息。其他解释器实现与CPython不同,CPython实现将来也许会改变。因此不能依赖垃圾回收器来回收不可达对象(因此应该总是显式关闭文件对象。)。

需要注意,使用工具的调试跟踪功能可能会导致应该被回收的对象一直存活,使用try...except语句捕获异常也可以保持对象的存活。

一些对象引用了如文件或者窗口的外部资源。不言而喻持有资源的对象被垃圾回收后,资源也会被释放,但因为没有机制保证垃圾回收一定会发生,这些资源持有对象也提供了显式释放外部资源的方式,通常使用close()方法。强烈推荐在程序中显式释放资源。try...<a href="http://www.php.cn/wiki/207.html" target="_blank">final</a>ly语句和with

1을 기반으로 합니다. 객체 🎜🎜Python 철학: 🎜🎜🎜Python의 모든 것은 객체입니다🎜
1.1 데이터 모델🎜-객체, 값 및 유형
🎜객체는 Python의 데이터 추상화입니다. Python 프로그램의 모든 데이터는 개체 또는 개체 간의 관계로 표현됩니다. (어떤 의미에서는 von Neumann의 "저장 컴퓨터" 모델을 따르기 위해 Python의 코드도 객체입니다.)🎜🎜Python 객체의 모든 것에는 ID, 값 및 유형. 객체가 생성된 후에는 그 ID가 결코 변경되지 않습니다. ID는 메모리에 있는 객체의 주소로 생각할 수 있습니다. isOperator 🎜는 두 객체의 ID를 비교합니다. id () Function🎜반환 정수 🎜. 🎜🎜CPython 구현 세부 정보: CPython 인터프리터 구현에서 id(x) 함수는 저장된 x를 반환합니다. code> 객체의 메모리 주소는 객체가 지원하는 작업(예: 객체에 길이가 있습니까?)을 결정하고 이 유형의 객체에 가능한 값도 결정합니다. <code>type() 함수는 객체의 유형을 반환합니다(이 유형 자체도 객체입니다). ID와 마찬가지로 객체 유형도 변경할 수 없습니다[1]. 🎜🎜일부 개체의 값은 변경될 수 있습니다. 값이 변경될 수 있는 개체는 변경 가능이라고도 하며, 생성된 후 값이 일정한 개체는 불변(immutable)이라고도 합니다. em>. (불변 컨테이너 객체가 가변 객체에 대한 참조를 포함하는 경우, 가변 객체의 값이 변경되면 불변 컨테이너 객체 값도 변경됩니다. 그러나 불변 컨테이너 객체는 포함된 값 모음 때문에 여전히 불변으로 간주됩니다. 따라서 불변성은 불변성과 엄격하게 동일하지 않습니다. 값은 매우 미묘합니다. ) (주석: 우선 불변 컨테이너 객체의 값은 다른 객체에 대한 참조를 포함합니다. 그러면 이러한 참조는 주소로 간주될 수 있습니다. 주소가 가리키는 내용이 변경되더라도 주소 자체는 변경되지 않습니다. 예를 들어 개체의 변경 가능성은 다음과 같습니다. 숫자, 문자열과 튜플은 변경할 수 없지만 사전과 목록은 변경할 수 있습니다. 🎜🎜객체는 명시적으로 삭제되지 않습니다. 객체에 접근할 수 없으면 가비지 수집됩니다(주석: 객체에 참조가 없습니다). 하나의 인터프리터 구현을 사용하면 가비지 수집을 지연하거나 완전히 무시할 수 있습니다. 이는 도달 가능한 객체가 수집되지 않는 한 가비지 수집 구현 방법에 따라 다릅니다. 🎜🎜CPython 구현 세부 정보: CPython 인터프리터는 참조 계산 모드 순환 🎜 링크 쓰레기, 이 방법은 도달할 수 없는 대부분의 객체를 재활용할 수 있지만 순환 참조의 쓰레기가 재활용된다는 보장은 없습니다. 순환 가비지 수집 제어에 대한 자세한 내용은 gc 모듈 설명서를 참조하세요. 다른 인터프리터 구현은 CPython과 다르며 CPython 구현은 향후 변경될 수 있습니다. 따라서 가비지 수집기는 연결할 수 없는 개체를 회수하는 데 의존할 수 없습니다(따라서 파일 개체는 항상 명시적으로 닫혀야 합니다). 🎜🎜도구의 디버깅🎜추적 기능을 사용하면 재활용해야 할 개체가 남을 수 있다는 점에 유의하세요. 예외를 포착하기 위해 try...out 문을 사용하면 객체를 활성 상태로 유지할 수도 있습니다. 🎜🎜일부 개체는 파일이나 창과 같은 외부 리소스를 참조합니다. 리소스를 보유하고 있는 개체가 가비지 수집된 후에 리소스도 해제된다는 것은 말할 필요도 없습니다. 그러나 가비지 수집이 반드시 발생한다는 것을 보장하는 메커니즘이 없기 때문에 이러한 리소스 보유 개체는 외부에서 명시적으로 해제하는 방법도 제공합니다. 일반적으로 close() 메서드를 사용합니다. 프로그램에서 리소스를 명시적으로 해제하는 것이 좋습니다. 시도...<a href="http://www.php.cn/wiki/207.html" target="_blank">최종🎜 ly</a> 문과 with 문은 리소스 해제에 대한 편의를 제공합니다. 🎜

일부 개체에는 다른 개체에 대한 참조가 포함되어 있으며 이러한 개체를 컨테이너라고 합니다. 튜플, 리스트, 딕셔너리는 모두 컨테이너입니다. 참조된 컨테이너 값의 일부입니다. 대부분의 경우 컨테이너의 값에 대해 이야기할 때는 객체의 ID 집합이 아닌 컨테이너에 포함된 객체 값 집합을 언급합니다. 우리는 그것이 포함하는 객체의 정체성을 암시하고 있습니다. 따라서 불변 객체(예: 튜플)에 가변 객체에 대한 참조가 포함되어 있는 경우 가변 객체가 변경되면 해당 값도 변경됩니다.

유형은 개체의 대부분의 동작에 영향을 미칩니다. 어떤 경우에는 객체 ID의 중요성조차 영향을 받습니다. 불변 유형의 경우 새 값을 계산하는 작업은 실제로 동일한 값과 유형을 가진 기존 객체에 대한 참조를 반환할 수 있지만, 가변 객체의 경우 이는 불가능합니다. 예를 들어 a = 1; b = 1 문이 실행된 후 ab는 다음과 같은 개체를 참조할 수도 있고 참조하지 않을 수도 있습니다. 동일한 값입니다. 이는 인터프리터 구현에 따라 다릅니다. 그러나 c = []; d = [] 문이 실행된 후에는 cd가 서로 다른 위치를 가리킬 것이 보장됩니다. 새로 생성된 고유한 빈 목록입니다. (c = d = []는 동일한 객체를 cd에 할당합니다.)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 객체, 이름 및 바인딩 위의 내용은 다음에서 번역되었습니다. "Python" Lang

uage References#Data 모델🎜# 객체🎜 s, 값, 유형》버전 3.6.1. 🎜
1.2 개체 요약
🎜공식 문서에는 Python 개체에 대한 자세한 설명이 나와 있습니다. 🎜🎜🎜객체의 세 가지 특성: 🎜🎜
🎜🎜Variable and immutable🎜: 일반적으로 불변 값을 가진 객체는 불변 객체, 변수 값을 가진 객체는 가변 객체라고 생각하지만, 변경할 수 없는 컬렉션 개체에는 변경 가능한 개체 참조 멤버가 포함되어 있습니다. 🎜🎜🎜Python의 개체: 🎜🎜


🎜

>>> a = 9>>> id(a)1470514960>>> a = a + 1>>> id(a)1470514976
🎜
🎜🎜이 Python 코드에는 다음이 있습니다. 모듈 개체 hello, 생성된 Person 클래스 개체 및 test, main와 같은 여러 함수를 포함한 많은 개체 > >함수 객체, 숫자, 문자열, 심지어 코드 자체도 객체입니다. 🎜

2. 이름은 "Variable🎜"

🎜 거의 모든 언어로 사용 가능합니다. "변수"라고 하면 엄밀히 말하면 Python의 변수는 변수라고 부르면 안 됩니다. 🎜🎜다음 번역은 Code Like a Pythonista에서 가져온 것입니다: Idiomatic Python # Python has "names"🎜
2.1 다른 언어에는 변수가 있습니다
🎜다른 언어에서 변수에 값을 할당하는 것은 값을 넣는 것과 같습니다 ​​"상자"에.
int a = 1;🎜🎜1을 상자에 넣으세요🎜🎜a 상자에는 이제 정수 1이 있습니다. 🎜🎜같은 변수에 값을 할당하고 상자의 내용을 바꿉니다:
a =2;🎜🎜Put 2 in the same box🎜🎜이제 정수 2가 상자 a 🎜🎜한 변수를 다른 변수에 할당하고 변수 값을 복사한 다음 새 상자에 넣으세요.<br><code>int b = a;🎜🎜b상자에 2개가 있습니다🎜🎜a box also contain 2🎜🎜b는 두 번째 상자입니다. 복사본이 있습니다. 정수 2의 상자 a에는 별도의 사본이 있습니다. 🎜
2.2 Python에는 이름이 있습니다
🎜Python에서 이름이나 식별자는 개체에 레이블을 바인딩하는 것과 같습니다.
a = 1🎜🎜🎜🎜

这里,整数对象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('dir', 'r') 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으로 문의하세요.
이전 기사:Django 모델 작업다음 기사:Django 모델 작업