特に明記されていない限り、以下は
Python3
Python3
Python
哲学:
Python中一切皆对象
对象是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
Python
哲学: 🎜🎜🎜Python のすべてのものはオブジェクトです🎜Python
によるデータの抽象化です。 Python
プログラム内のすべてのデータは、オブジェクトまたはオブジェクト間の関係によって表されます。 (ある意味、フォン・ノイマンの「ストレージ コンピューター」モデルに準拠するために、Python
のコードもオブジェクトです。)🎜🎜Python
オブジェクト内のすべてのものには、 ID、値、タイプ。オブジェクトが作成された後、その ID は決して変更されません。ID はメモリ内のオブジェクトのアドレスと考えることができます。 is
演算子 🎜 は 2 つのオブジェクトの ID を比較します。id ()
関数🎜戻り値 整数 🎜。 🎜🎜CPython 実装の詳細: CPython
インタープリターの実装では、id(x)
関数は保存されている x を返します。 code> オブジェクトのメモリ アドレスは、オブジェクトによってサポートされる操作 (たとえば、オブジェクトには長さがあるかどうか) を決定し、このタイプのオブジェクトの可能な値も決定します。 <code>type()
関数は、オブジェクトのタイプを返します (このタイプ自体もオブジェクトです)。 ID と同様、オブジェクトのタイプも不変です[1]。 🎜🎜一部のオブジェクトの値は変更できます。値を変更できるオブジェクトは可変とも呼ばれ、作成後の値が一定であるオブジェクトは不変 (不変) とも呼ばれます。 /em>。 (不変コンテナ オブジェクトに変更可能オブジェクトへの参照が含まれている場合、変更可能オブジェクトの値が変更されると、不変更コンテナ オブジェクトの値も変更されます。ただし、不変更コンテナ オブジェクトは依然として不変とみなされます。これは、値のコレクションが含まれているためです。したがって、不変性は、値が不変であることと厳密には同じではありません。注釈: まず第一に、不変コンテナ オブジェクトの値は、他のオブジェクトへの参照を含むコレクションです。この場合、これらの参照はアドレスと見なすことができ、アドレスが指す内容が変化しても、アドレス自体は変化しません。したがって、オブジェクトの可変性は、たとえば次のようになります。数値、文字列とタプルは不変ですが、辞書とリストは変更可能です。 🎜🎜オブジェクトが明示的に破棄されることはありません。オブジェクトが到達不能な場合は、ガベージ コレクションが行われます (注釈: オブジェクトには参照がありません)。 1 つのインタープリター実装では、到達可能なオブジェクトが収集されない限り、ガベージ コレクションの実装方法に応じて、ガベージ コレクションを遅延または完全に無視できます。 🎜🎜CPython 実装の詳細: CPython
インタプリタは参照カウント モードを使用して遅延検出を実装します 循環 🎜 リンク ガベージ。このメソッドは、ほとんどの到達不能オブジェクトをリサイクルできますが、循環参照のガベージがリサイクルされることは保証されません。循環ガベージ コレクションの制御の詳細については、gc
モジュールのドキュメントを参照してください。他のインタープリターの実装は CPython
とは異なり、CPython
の実装は将来変更される可能性があります。したがって、ガベージ コレクターを利用して到達不能なオブジェクトを再利用することはできません (したがって、ファイル オブジェクトは常に明示的に閉じる必要があります)。 🎜🎜ツールのデバッグ🎜追跡機能を使用すると、リサイクルされるべきオブジェクトが残る可能性があることに注意してください。 try
...
excel
ステートメントを使用して例外をキャッチすると、オブジェクトを存続させることもできます。 🎜🎜一部のオブジェクトは、ファイルやウィンドウなどの外部リソースを参照します。リソースを保持するオブジェクトがガベージ コレクションされた後、リソースも解放されることは言うまでもありませんが、ガベージ コレクションが確実に行われることを保証する仕組みはないため、これらのリソース保持オブジェクトは明示的に外部に解放する方法も提供します。リソース。通常は close() メソッドを使用します。プログラム内で明示的にリソースを解放することを強くお勧めします。 試してください
...
<a href="http://www.php.cn/wiki/207.html" target="_blank">最終🎜 ly</a>
ステートメントと with
ステートメントは、リソースを解放するのに便利です。 🎜一部のオブジェクトには他のオブジェクトへの参照が含まれており、これらのオブジェクトは コンテナ と呼ばれます。タプル、リスト、辞書はすべてコンテナです。参照されるコンテナ値の一部。ほとんどの場合、コンテナの値について話すときは、オブジェクトの ID のセットではなく、コンテナに含まれるオブジェクトの値のセットを指します。ただし、コンテナの可変性について話すときは、これは、そこに含まれるオブジェクトのアイデンティティを暗示していることになります。したがって、不変オブジェクト (タプルなど) に変更可能オブジェクトへの参照が含まれている場合、変更可能オブジェクトが変更されると、その値も変更されます。
型は、オブジェクトのほとんどの 動作に影響を与えます。場合によっては、オブジェクトの ID の重要性さえも影響を受けます。不変型の場合、新しい値を計算する操作により、同じ値と型を持つ既存のオブジェクトへの参照が実際に返される可能性がありますが、可変オブジェクトの場合、これは不可能です。たとえば、ステートメント a = 1; b = 1
が実行された後、a
と b
は同じオブジェクトを参照する場合もあれば、参照しない場合もあります。同じ値です。これはインタプリタの実装によって異なります。ただし、ステートメント c = []; d = []
が実行された後は、c
と d
が異なるものを指すことが保証されます。新しく作成された一意の空のリスト。 (c = d = []
は同じオブジェクトを c
と d
に割り当てることに注意してください)a = 1; b = 1
执行之后,a
和b
可能会也可能不会引用具有相同值得同一个对象,这取决于解释器实现。但是语句c = []; d = []
执行之后,可以保证c
和d
会指向不同的,唯一的新创建的空列表。(注意 c = d = []
分配相同的对象给c
和d
)
Note: 以上翻译自 《The Python Language References#Data model# Objects, values, types》 3.6.1版本。
官方文档已经对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'a test module'author = 'Richard Cheng'import sysclass Person(object): ''' Person class''' def init(self, name, age): self.name = name self.age = agedef tset(): print(sys.path) p = Person('Richard', 20) print(p.name, ':', p.age)def main(): tset()if name == 'main': main()
这段Python
代码中有很多对象,包括hello
这个模块对象,创建的Person
类对象,几个函数如test
, main
函数对象,数字,字符串,甚至代码本身也是对象。
几乎所有语言中都有“变量”的说法,严格说来,Python
中的变量不应该叫变量,称为名字更加贴切。
以下翻译自 Code Like a Pythonista: Idiomatic Python # Python has "names"
其他语言中,为变量分配值就像将值放到“盒子”里。int a = 1;
盒子a
现在有了一个整数1
。
为同一个变量分配值替换掉盒子的内容:a =2;
现在盒子a
中放了整数2
将一个变量分配给另一个变量,拷贝变量的值,并把它放到新的盒子里:int b = a;
b
是第二个盒子,装有整数2的拷贝。盒子a
有一份单独的拷贝。
Python
中,名字或者标识符就像将一个标签捆绑到对象上一样。a = 1
注: 上記は以下から翻訳されたものです「Python」Lang
uage References#Data モデル🎜# オブジェクト🎜、値、型》バージョン 3.6.1。 🎜Python
オブジェクトの詳細な説明が記載されています。概要は次のとおりです。 🎜🎜🎜 オブジェクトの 3 つの特性: 🎜🎜id()
、組み込み関数 id()
関数は、is
が比較するオブジェクトを識別する整数を返します。アイデンティティの 2 つのオブジェクト。 public static void main(String[] args) { int i = 0; // 先声明,后使用 System.out.println(i); // 使用变量i}
type()
、組み込み関数はオブジェクトのタイプを返しますa = 9
==
演算子は、2 つのオブジェクトの値が等しいかどうかを比較するために使用されます。その他比較演算子 🎜オブジェクトのサイズを比較します。 a = 9 #1a = a + 1 #2
Python
のオブジェクト: 🎜🎜
🎜
>>> a = 9>>> id(a)1470514960>>> a = a + 1>>> id(a)1470514976🎜
Python
コードには、次のものがあります。モジュール オブジェクト hello
、作成された person
クラス オブジェクト、および test
、main
などのいくつかの関数を含む多数のオブジェクト> >関数オブジェクト、数値、文字列、さらにはコード自体もオブジェクトです。 🎜
Python
の変数は変数と呼ぶべきではなく、名前と呼ぶのが適切です。 🎜🎜以下の翻訳は Code Like a Pythonista からのものです: Idiomatic Python # Python has "names"🎜int a = 1;
🎜🎜🎜🎜ボックス a
には整数 1
が入ります。 🎜🎜同じ変数に値を代入し、ボックスの内容を置き換えます:a =2;
🎜🎜🎜🎜これで、整数 2
がボックス a 🎜🎜ある変数を別の変数に割り当て、変数の値をコピーして、新しいボックスに入れます:<br><code>int b = a;
🎜🎜🎜🎜🎜🎜b
は 2 番目のボックスで、次のボックスが含まれています。整数 2 の値。ボックス a
には別のコピーがあります。 🎜Python
では、名前または識別子はラベルをオブジェクトにバインドするようなものです。 a = 1
🎜🎜🎜🎜这里,整数对象1
有一个叫做a
的标签。
如果重新给a
分配值,只是简单的将标签移动到另一个对象:a = 2
现在名字a
贴到了整数对象2
上面。原来的整数对象1不再拥有标签a
,或许它还存在,但是不能通过标签a
访问它了(当对象没有任何引用时,会被回收。)
如果将一个名字分配给另一名字,只是将另一个名字标签捆绑到存在的对象上:b = a
名字b
只是绑定到与a
引用的相同对象上的第二个标签而已。
虽然在Python
中普遍使用“变量”(因为“变量”是普遍术语),真正的意思是名字或者标识符。Python
中的变量是值得标签,不是装值得盒子。
C/C++
中有指针,Java
中有引用,Python
中的名字在一定程度上等同于指针和引用。
2.1节中其他语言的例子,也只是针对于它们的基本类型而言的,若是指针或者引用,表现也跟Python
的名字一样。这也在一定程度上说明了Python
将面向对象贯彻得更加彻底。
可以对一个变量做什么?声明变量,使用变量,修改变量的值。名字作为Python
中的一个重要概念,可以对它做的操作有:
定义;名字需要先定义才能使用,与变量需要先声明一样。
绑定:名字的单独存在没有意义,必须将它绑定到一个对象上。
Python のオブジェクト、名前、バインディング:名字可以重新引用另一个对象,这个操作就是Python のオブジェクト、名前、バインディング。
引用:为什么要定义名字,目的是使用它。
名字以及对象,它们之间必然会发生些什么。
其他如C/C++
和Java
的高级语言,变量在使用前需要声明,或者说定义。以下在Java
中声明变量:
public static void main(String[] args) { int i = 0; // 先声明,后使用 System.out.println(i); // 使用变量i}
这样,在可以访问到变量i
所在作用域的地方,既可以使用i
了。还有其他声明变量的方法么?好像没有了。
Python
中有多种定义名字的途径,如函数定义,函数名就是引用函数对象的名字;类定义,类名就是指向类对象的名字,模块定义,模块名就是引用模块对象的名字;当然,最直观的还是赋值语句。
赋值语句
官方对赋值语句做了这样的说明(地址):
Assignment statements are used to (re)bind names to values and to modify attributes or items of mutable objects.
即:
赋值语句被用来将名字绑定或者Python のオブジェクト、名前、バインディング给值,也用来修改可变对象的属性或项
那么,我们关心的,就是赋值语句将名字和值(对象)绑定起来了。
看一个简单的赋值语句:
a = 9
Python
在处理这条语句时:
首先在内存中创建一个对象,表示整数9
:
然后创建名字a
,并把它指向上述对象:
上述过程就是通过赋值语句的名字对象绑定了。名字首次和对象绑定后,这个名字就定义在当前命名空间了,以后,在能访问到这个命名空间的作用域中可以引用该名字了。
定义完名字之后,就可以使用名字了,名字的使用称为“引用名字”。当名字指向可变对象和不可变对象时,使用名字会有不同的表现。
a = 9 #1a = a + 1 #2
语句1执行完后,名字a
指向表示整数9
的对象:
由于整数是不可变对象,所以在语句2处引用名字a
,试图将表示整数9
的对象 + 1
,但该对象的值是无法改变的。因此就将该对象表示的整数值9
加1
,以整数10
新建一个整数对象:
接下来,将名字a
Python のオブジェクト、名前、バインディング
到新建对象上,并移除名字对原对象的引用:
使用id()
函数,可以看到名字a
指向的对象地址确实发生了改变:
>>> a = 9>>> id(a)1470514960>>> a = a + 1>>> id(a)1470514976
可变对象可以改变其值,并且不会造成地址的改变:
>>> list1 = [1]>>> id(list1)42695136>>> list1.append(2)>>> id(list1)42695136>>> list1 [1, 2]>>>
执行语句list1 = [1]
,创建一个list
对象,并且其值集中添加1
,将名字list1
指向该对象:
执行语句list1.append(2)
,由于list
是可变对象,可以直接在其值集中添加2
:
值得改变并没有造成list1
引用的对象地址的改变。
再来看一个比较“奇怪”的例子:
values = [1, 2, 3] values[1] = valuesprint(values)
一眼望去,期待的结果应该是
[1, [1, 2, 3], 3]
但实际上结果是:
[1, [...], 3]
我们知道list
中的元素可以是各种类型的,list
类型是可以的:
观察以下代码段:
>>> list1 = [1]>>> id(list1)42695136>>> list1 = [1, 2]>>> id(list1)42717432
两次输出的名字list1
引用对象的地址不一样,这是因为第二次语句list 1 = [1, 2]
对名字做了Python のオブジェクト、名前、バインディング:
当两个或两个以上的名字引用同一个对象时,我们称这些名字共享对象。共享的对象可变性不同时,表现会出现差异。
函数attempt_change_immutable
将参数i
的值修改为2
def attempt_change_immutable(i): i = 2i = 1print(i) attempt_change_immutable(i)print(i)
Output:
11
如果你对输出不感到意外,说明不是新手了 ^_^。
首先,函数的参数i
与全局名字i
不是在同一命名空间中,所以它们之间不相互影响。
调用函数时,将两个名字i
都指向了同一个整数对象。
函数中修改i
的值为2
, 因为整数对象不可变,所以新建值为2
的整数对象,并把函数中的名字i
绑定到对象上。
全局名字i
的绑定关系并没有被改变。
值得注意的是,这部分内容与命名空间和作用域有关系,另外有文章介绍它们,可以参考。
函数attempt_change_mutable
为列表增加字符串。
def attempt_change_mutable(list_param): list_param.append('test') list1 = [1]print(list1) attempt_change_mutable(list1)print(list1)
output:
[1] [1, 'test']
可以看到函数成功改变了列表list1
的值。传递参数时,名字list_param
引用了与名字list1
相同的对象,这个对象是可变的,在函数中成功修改了对象的值。
首先,名字list_param
与名字list1
指向对象:
然后,通过名字list_param
修改了对象的值:
最后,这个修改对名字list1
可见。
总的来说,触发名字对象绑定的行为有以下一些:
赋值操作;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
都会发生名字的绑定
待续。。。
The Python Language References#Data model# Objects, values, types
Python的名字绑定
Python一切皆对象
Code Like a Pythonista: Idiomatic Python
python基础(5):深入理解 python 中的赋值、引用、拷贝、作用域
[1] 在特定的控制条件下,改变对象的类型是可能的。但不是一种明智的做法,如果处理不当的话,会发生一些奇怪的行为。
以上がPython のオブジェクト、名前、バインディングの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。