文档章节

Is Python call-by-value or call-by-reference? Neit

Ericleey
 Ericleey
发布于 2016/04/22 21:51
字数 1049
阅读 26
收藏 0

Is Python call-by-value or call-by-reference? Neither.

One aspect of Python programming that trips up those coming from languages like C or Java is how arguments are passed to functions in Python. At a more fundamental level, the confusion arises from a misunderstanding about Python object-centric data model and its treatment of assignment. When asked whether Python function calling model is "call-by-value" or "call-by-reference", the correct answer is: neither. Indeed, to try to shoe-horn those terms into a conversation about Python's model is misguided. "call-by-object," or "call-by-object-reference" is a more accurate way of describing it. But what does "call-by-object" even mean?

In Python, (almost) everything is an object. What we commonly refer to as "variables" in Python are more properly called names. Likewise, "assignment" is really the binding of a name to an object. Each binding has a scope that defines its visibility, usually the block in which the name originates.

That's a lot of terminology all at once, but those basic terms form the cornerstone of Python's execution model. Compared to, say, C++, the differences are subtle yet important. A concrete example will highlight these differences. Think about what happens when the following C++ code is executed:

string some_guy = "Fred";// ...some_guy = "George";

In the above, the variable some_guy refers to a location in memory, and the value 'Fred' is inserted in that location (indeed, we can take the address of some_guy to determine the portion of memory to which it refers). Later, the contents of the memory location referred to by some_guy are changed to 'George'. The previous value no longer exists; it was overwritten. This likely matches your intuitive understanding (even if you don't program in C++).

Let's now look at a similar block of Python code:

some_guy = 'Fred'# ...some_guy = 'George'

Binding Names to Objects

On line 1, we create a binding between a namesome_guy, and a string object containing 'Fred'. In the context of program execution, the environment is altered; a binding of the name some_guy' to a string object is created in the scope of the block where the statement occurred. When we later say some_guy = 'George', the string object containing 'Fred' is unaffected. We've just changed the binding of the name some_guyWe haven't, however, changed either the 'Fred' or 'George' string objects. As far as we're concerned, they may live on indefinitely.

With only a single name binding, this may seem overly pedantic, but it becomes more important when bindings are shared and function calls are involved. Let's say we have the following bit of Python code:

some_guy = 'Fred'first_names = []first_names.append(some_guy)another_list_of_names = first_namesanother_list_of_names.append('George')some_guy = 'Bill'print (some_guy, first_names, another_list_of_names)

So what get's printed in the final line? Well, to start, the binding of some_guy to the string object containing 'Fred' is added to the block's namespace. The name first_names is bound to an empty list object. On line 4, a method is called on the list object first_names is bound to, appending the object some_guy is bound to. At this point, there are still only two objects that exist: the string object and the list object. some_guy andfirst_names[0] both refer to the same object (Indeed, print(some_guy is first_names[0]) shows this).

Let's continue to break things down. On line 6, a new name is bound: another_list_of_names. Assignment between names does not create a new object. Rather, both names are simply bound to the same object. As a result, the string object and list object are still the only objects that have been created by the interpreter. On line 7, a member function is called on the object another_list_of_names is bound to and it is mutated to contain a reference to a new object: 'George'. So to answer our original question, the output of the code is

Bill ['Fred', 'George'] ['Fred', 'George']

This brings us to an important point: there are actually two kinds of objects in Python. A mutable object exhibits time-varying behavior. Changes to a mutable object are visible through all names bound to it. Python's lists are an example of mutable objects. An immutable object does not exhibit time-varying behavior. The value of immutable objects can not be modified after they are created. They can be used to compute the values of new objects, which is how a function like string.join works. When you think about it, this dichotomy is necessary because, again, everything is an object in Python. If integers were not immutable I could change the meaning of the number '2' throughout my program.

It would be incorrect to say that "mutable objects can change and immutable ones can't", however. Consider the following:

first_names = ['Fred', 'George', 'Bill']last_names = ['Smith', 'Jones', 'Williams']name_tuple = (first_names, last_names)first_names.append('Igor')

Tuples in Python are immutable. We can't change the tuple object name_tuple is bound to. But immutable containers may contain references to mutable objects like lists. Therefore, even though name_tuple is immutable, it "changes" when 'Igor' is appended to first_names on the last line. It's a subtlety that can sometimes (though very infrequently) prove useful.

By now, you should almost be able to intuit how function calls work in Python. If I call foo(bar), I'm merely creating a binding within the scope of foo to the object the argument bar is bound to when the function is called. If bar refers to a mutable object and foo changes its value, then these changes will be visible outside of the scope of the function.

def foo(bar):
    bar.append(42)
    print(bar)
    # >> [42]answer_list = []foo(answer_list)print(answer_list)# >> [42]

On the other hand, if bar refers to an immutable object, the most that foo can do is create a name bar in its local namespace and bind it to some other object.

def foo(bar):
    bar = 'new value'
    print (bar)
    # >> 'new value'answer_list = 'old value'foo(answer_list)print(answer_list)# >> 'old value'

Hopefully by now it is clear why Python is neither "call-by-reference" nor "call-by-value". In Python a variable is not an alias for a location in memory. Rather, it is simply a binding to a Python object. While the notion of "everything is an object" is undoubtedly a cause of confusion for those new to the language, it allows for powerful and flexible language constructs, which I'll discuss in my next post.


本文转载自:

上一篇: Python多进程编程
下一篇: Python多进程编程
Ericleey
粉丝 0
博文 3
码字总数 0
作品 0
青岛
私信 提问
dataframe中将一列数据切分成多列

原sheet中数据 目的 将【备注】列切分成【key】列和【value】列 Python 结果 参考 pandas.Series.str.extract

亚林瓜子
01/26
31
0
python对于图片的风格的处理--引用github上开源项目的

关于python做过的比较好玩的事 这段时间学了python,对于python这种优雅简洁的语言深深吸引,在网上看到一个github上的开源项目,觉得比较有意思,就自己研究一番,现将结果记录下来,以志自...

yxc_kyzg
2017/11/04
61
0
剑指offer 40. 数组中只出现一次的数字

原题 一个整型数组里除了两个数字之外,其他的数字都出现了偶数次。请写程序找出这两个只出现一次的数字。 Reference Answer 思路分析 直接利用python中的dict进行次数统计就好了,用空间换时...

dby_freedom
2018/11/20
0
0
[转]一个python‘非多态’的问题

Properties are just one application of Python ubiquitous proxying. The properties are created as wrappers over get/set methods: class C(object): all is fine, value calls C.getva......

Orion
2012/02/22
77
0
python 利用 descriptor 实现自己的 property

1.概念简介 1.1 property 在 python 代码中,property 是非常常见的一个内置函数。property 可以为一个 python 类的 attribute 设置 getter/setter,可以类比之 C# 的 properties。 见下面的...

御坂网络路由器
02/21
9
0

没有更多内容

加载失败,请刷新页面

加载更多

好程序员大数据学习路线分享函数+map映射+元祖

好程序员大数据学习路线分享函数+map映射+元祖,大数据各个平台上的语言实现 hadoop 由java实现,2003年至今,三大块:数据处理,数据存储,数据计算 存储: hbase --> 数据成表 处理: hive --> 数...

好程序员官方
今天
6
0
tabel 中含有复选框的列 数据理解

1、el-ui中实现某一列为复选框 实现多选非常简单: 手动添加一个el-table-column,设type属性为selction即可; 2、@selection-change事件:选项发生勾选状态变化时触发该事件 <el-table @sel...

everthing
今天
6
0
【技术分享】TestFlight测试的流程文档

上架基本需求资料 1、苹果开发者账号(如还没账号先申请-苹果开发者账号申请教程) 2、开发好的APP 通过本篇教程,可以学习到ios证书申请和打包ipa上传到appstoreconnect.apple.com进行TestF...

qtb999
今天
10
0
再见 Spring Boot 1.X,Spring Boot 2.X 走向舞台中心

2019年8月6日,Spring 官方在其博客宣布,Spring Boot 1.x 停止维护,Spring Boot 1.x 生命周期正式结束。 其实早在2018年7月30号,Spring 官方就已经在博客进行过预告,Spring Boot 1.X 将维...

Java技术剑
今天
17
0
浅谈java过滤器Filter

一、简介 Servlet中的过滤器Filter是实现了javax.servlet.Filter接口的服务器端程序,主要的用途是过滤字符编码、做一些业务逻辑判断如是否有权限访问页面等。其工作原理是,只要你在web.xml...

青衣霓裳
今天
9
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部