文档章节

探索 Python 之 变量、类型和引用

charlesdong1989
 charlesdong1989
发布于 2012/03/29 17:35
字数 1684
阅读 766
收藏 0

在探索到 Python 函数的参数传递的时候,我不禁赞叹 Python 灵活的参数设计,但慢慢的,开始迷惑与传递参数的修改和返回。

众所周知,在 C++ 中传递参数分为传值和传引用两种,但 Python 没有,那到底传进去的东西,修改一下,能不能传出来呢?这是一个很奇怪和让人费解的问题,不是么?在查阅了一些资料后,对 Python 关于变量、类型和引用的一些基本方式有了一些了解,进而基于这种理解并结合实验,了解了参数传递的奥妙。

Python 的变量是没有类型的,这与以往看到的大部分语言都不一样。但 Python 却是区分类型的,那类型在哪里呢?事实是,类型是跟着内存中的对象走的。Python 的所有变量其实都是指向内存中的对象的一个指针,所有的变量都是!此外,对象还分两类:一类是可修改的,一类是不可修改的。

现在,我插入在此先说说函数参数的问题,我们有下面一个实验:

1
2
3
4
5
6
7
8
def func1(a): a += 1 def func2(a): a[0] = 0 t1 = 0 func1(t1) print t1
t2 = [1, 2, 3] func2(t2) print t2

结果是:

1
2
0
[0, 2, 3]

看看结果会不会很惊异?第一个看起来像传值,第二个看起来却像传引用?看到这里你是不是觉得 Python 是一种莫名其妙的语言?其实当时我也有这种想法……但 Python 果然没哟让我失望,它如同 UNIX 一样,一开始设计得就如此优美。继续往下看~

不可修改的对象是我们最常用和最熟悉,几乎在任何一个语言中都能看到的——整数、实数、字符串和元组。有人说,怎么不可变啊?我随便给他们赋值!是 的,在 Python 里几乎一切都是可以改变的,甚至有人说“如果你愿意,None 的值也是可以变的”(当然我不知道怎么变……)。但是如果注意观察,会发现所谓的改变其实是——扔了旧的建个新的!验证这个的实验很简单:

1
2
3
4
a = 1 print id(a) a += 1 print id(a)

类似的实验想怎么做怎么做,只要那两个是不可变对象,你就一定会发现 id 变了!为什么?因为对象不可变。那什么可变?变量的引用是可变的!

好,那么自然剩下的就是可变的对象了,上面的实验亦可以很容易的证实字典、列表、集合和类实例等对象是可变的。那么,这意味着什么呢?

下面,我们回到函数传值的问题。我们知道了可变对象和不可变对象的区别,不是吗?对于可变对象,对于对象的操作不会重建对象,而对于不可变对象,每一次操作就重建新的对象。那么函数参数到底是个什么东西呢?其实说白了也简单,就是把参数里传入的东西对相应对象的引用依次赋给对应的内部变量(有 点晕吗?)。看看第一个实验,有没有明白些什么?其实都是将一个指向对象的引用传个一个名为“参数”的本地变量,所以 func1 中给 a 的是一个值为 0 的整数对象的引用,但我们知道,整数对象是不可变的,所以当 func1 对 a 进行修改的时候,实际上是修改本地变量 a 的引用到一个新的值为 1 的整数对象的引用。那么很显然,func2 修改的是一个可变的对象,也就是说即使 func2 修改了 a,本地变量 a 和全局变量 t2 指向的还是同一个对象,虽然他们不是同一个变量!这样一切情况都明了了,不是么?不明了的话再看看下面这个实验:

1
2
3
4
a = [[1, 2, 3], [4, 5, 6]] b = a[0] b[0] = 0 print a

输出一定是:

1
[[0, 2, 3], [4, 5, 6]]

其实原理和参数的传递是一致的。

我们下面来看看全局变量和本地变量的问题。如果一个函数里面使用了一个变量,那么 Python 会先看看有没有对应的本地变量,如果没有找到,但找到一个全局变量,那么 Python 会把那个全局变量的引用赋给一个新的本地变量。 所以,现在在函数里的那个变量和全局变量其实不是同一个变量,他们只不过暂时有了相同的引用。这样其实可以看作 Python 为你做了隐式的参数传递。因此我们发现,他和参数一样,传值传引用表面上看过去漂移不定。那么如何修改一个指向不可变全局变量的值呢?靠返回值显然不那么 优美。好在 Python 像 PHP 那样提供了一个叫 global 的语法,被 global 的变量使得本地变量成为相应全局变量的一个别名,也就是说这个语句使他们成为同一个变量,这一点很重要!

现在看到了 Python 优美的设计。那下面的问题是,如果我们一定要复制一个可变对象的副本怎么办?简单的等号赋值显然被证明无效了。Python 也提供了方法——copy 模块。copy 模块是每一个 Python 都有的,专门用于生成可变对象的副本。copy 模块中有两个函数:copy.copy 和 copy.deepcopy。其中 copy 叫做潜复制,它仅仅复制了第一你给它的东西,下面的不管了。而 deepcopy 叫做深复制,它将所有能复制的都复制了。这样说比较抽象,我们来看下面实验:

1
2
3
4
5
6
7
8
9
10
a = [[1, 2, 3], [4, 5, 6]] b = a
c = copy.copy(a) d = copy.deepcopy(a) a.append(15) a[1][2] = 10 print aprint bprint cprint d

输出结果:

1
2
3
4
[[1, 2, 3], [4, 5, 10], 15]
[[1, 2, 3], [4, 5, 10], 15]
[[1, 2, 3], [4, 5, 10]]
[[1, 2, 3], [4, 5, 6]]

我想,效果不言而喻了。

此外,我还看到一个叫做弱引用 (weakref) 的模块,暂时不知道是干嘛的……下次研究了再说……

参考:

© 著作权归作者所有

上一篇: python re
下一篇: python
charlesdong1989
粉丝 22
博文 155
码字总数 84903
作品 0
海淀
私信 提问
加载中

评论(2)

charlesdong1989
charlesdong1989 博主

引用来自“王王先生”的评论

在idle shell里不能使用c = copy.copy(a),说是未定义,请问这是为什么?

ide的shell没用过, import copy
王王先生
王王先生
在idle shell里不能使用c = copy.copy(a),说是未定义,请问这是为什么?
好程序员Python教程分享python之变量

好程序员Python教程分享python之变量,变量(variable)是必经之路,它是学习python初始时,就会接触到的一个新的知识点,也是一个需要熟知的概念。python是一种动态类型语言,在赋值的执行中可...

好程序员IT
07/01
11
0
对比 C++ 和 Python,谈谈指针与引用

花下猫语:本文是学习群内 樱雨楼 小姐姐的投稿。之前已发布过她的一篇作品《当谈论迭代器时,我谈些什么?》,大受好评。本文依然是对比 C++ 与 Python,来探讨编程语言中极其重要的概念。祝...

豌豆花下猫
07/12
3.8K
9
000-Python常量与变量

python常量与变量 昨天的文章虽然有插图,但是一个都没有显示出来,估计是天气太热,不愿意露面的缘故吧。这些都不是事,暂且不表,今天再次发布与昨天相同的文章,主要为了弥补3个插图。为了...

bigstone2012
2018/06/29
0
0
投稿007期|令人震惊到发指的PyObject对象代码设计之美

前言 最近在重温经典漫画《SlamDunk》的全国大赛篇,其中的一个情形可以很好的诠释虎躯一震这个状态——当樱木看到流川枫一次高难度投篮时内心的感受:“经过两万次射球练习后,樱木首次明白...

元宵大师
2018/08/20
0
0
[Python] 动态类型的实现

大多数编译型语言,变量在使用前必须先声明,其中的 C 语言更加苛刻:变量声明必须位于代码块最开始,且在任何其他语句之前。其它语言,像C++和Java,允许“随时随地”声明变量,比如,变量声...

长平狐
2013/06/03
107
0

没有更多内容

加载失败,请刷新页面

加载更多

为什么要在网站中应用CDN加速?

1. 网页加载速度更快 在网站中使用CDN技术最直接的一个好处就是它可以加快网页的加载速度。首先,CDN加速的内容分发是基于服务器缓存的,由于CDN中缓存了不少数据,它能够给用户提供更快的页...

云漫网络Ruan
36分钟前
7
0
亚玛芬体育(Amer Sports)和信必优正式启动合作开发Movesense创新

亚玛芬体育和信必优正式启动合作开发Movesense创新,作为亚玛芬体育的完美技术搭档,信必优利用Movesense传感器技术为第三方开发移动应用和服务。 Movesense基于传感器技术和开放的API,测量...

symbiochina88
47分钟前
4
0
创龙TI AM437x ARM Cortex-A9 + Xilinx Spartan-6 FPGA核心板规格书

SOM-TL437xF是一款广州创龙基于TI AM437x ARM Cortex-A9 + Xilinx Spartan-6 FPGA芯片设计的核心板,采用沉金无铅工艺的10层板设计,适用于高速数据采集和处理系统、汽车导航、工业自动化等领...

Tronlong创龙
48分钟前
4
0
好程序员Java学习路线分享MyBatis之线程优化

  好程序员Java学习路线分享MyBatis之线程优化,我们的项目存在大量用户同时访问的情况,那么就会出现大量线程并发访问数据库,这样会带来线程同步问题,本章我们将讨论MyBatis的线程同步问...

好程序员官方
54分钟前
6
0
IDEA 自定义方法注解模板

IDEA 自定义方法注解模板 1、使用效果 /*** 计算交易费用* @Author wangjiafang* @Date 2019/9/11* @param feeComputeVo* @return*/@PostMapping("/v1/fee_compute")public ApiResp......

小白的成长
54分钟前
6
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部