python学习笔记11(函数二): 参数的传递、变量的作用域
一、函数形参和实参的区别
形参全称是形式参数,在用def关键字定义函数时函数名后面括号里的变量称作为形式参数。
实参全称为实际参数,在调用函数时提供的值或者变量称作为实际参数。
>>> def add(a,b): #这里的a和b是形参
return a+b >>> add(1,2) # 这里的1和2是实参
3
>>> x=2 # 这里的x和y是实参
>>> y=3
>>> add(x,y)
5
二、参数的传递和改变
在Python中一切皆对象,变量中存放的是对象的引用。
例子:
print id(5) # id(object)函数是返回对象object在其生命周期内位于内存中的地址,id函数的参数类型是一个对象
print id('python')
x = 2
print id(x)
print id(2)
y = 'Hello'
print id(y)
print id('Hello')
代码的运行结果:
从运行结果中可以看到,id(x)和id(2)的值是一样的,id(y)和id('Hello')的值也是一样的。
在Python中一切皆对象,像2,'hello'这样的值都是对象,只不过5是一个整型对象,而'hello'是一个字符串对象。
上面的x=2,在Python中实际的处理过程是这样的:先申请一段内存分配给一个整型对象来存储整型值2,然后让变量x去指向这个对象,实际上就是指向这段内存(这里有点和C语言中的指针类似)。
而id(2)和id(x)的结果一样,说明id函数在作用于变量时,其返回的是变量指向的对象的地址。因为变量也是对象,所以在这里可以将x看成是对象2的一个引用。
再看一个例子:
x=2
print id(x)
y=2
print id(y)
s='hello'
print id(s)
t=s
print id(t)
代码运行结果:
从运行结果可以看到id(x)和id(y)的结果是相同的,id(s)和id(t)的结果也是相同的。这说明x和y指向的是同一对象,而t和s也是指向的同一对象。
x=2这句让变量x指向了int类型的对象2,而y=2这句执行时,并不重新为2分配空间,而是让y直接指向了已经存在的int类型的对象2。
这个很好理解,因为本身只是想给y赋一个值2,而在内存中已经存在了这样一个int类型对象2,所以就直接让y指向了已经存在的对象。
这样一来不仅能达到目的,还能节约内存空间。t=s这句变量互相赋值,也相当于是让t指向了已经存在的字符串类型的对象'hello'(这个原理和C语言中指针的互相赋值有点类似)。
下面再看个例子:
x=2
print id(2)
print id(x)
x=3
print id(3)
print id(x)
L=[1,2,3]
M=L
print id(L)
print id(M)
print id(L[2])
L[0]=2
print id(L)
print M
代码运行结果:
两次的id(x)的值不同,这个可能让人有点难以理解。注意,在Python中,单一元素的对象是不允许更改的,比如整型数据、字符串、浮点数等。
x=3这句的执行过程并不是先获取x原来指向的对象的地址,再把内存中的值更改为3,而是新申请一段内存来存储对象3,再让x去指向对象3,所以两次id(x)的值不同。
然而为何改变了L中的某个子元素的值后,id(L)的值没有发生改变?在Python中,复杂元素的对象是允许更改的,比如列表、字典、元组等。
Python中变量存储的是对象的引用,对于列表,其id()值返回的是列表第一个子元素L[0]的存储地址。
就像上面的例子,L=[1,2,3],这里的L有三个子元素L[0],L[1],L[2],L[0]、L[1]、L[2]分别指向对象1、2、3,id(L)值和对象3的存储地址相同。
因为L和M指向的是同一对象,所以在更改了L中子元素的值后,M也相应改变了,但是id(L)值并没有改变,因为这句L[0]=2只是让L[0]重新指向了对象2,而L[0]本身的存储地址并没有发生改变,所以id(L)的值没有改变( id(L)的值实际等于L[0]本身的存储地址)。
结合例子看看函数的参数传递和改变这个问题
>>> a = 1
>>> def change_integer(a):
a = a + 1
return a >>> print change_integer(a)
2
>>> print a
1
>>> b = [1,2,3]
>>> def change_list(b):
b[0] = b[0] + 1
return b >>> print change_list(b)
[2, 2, 3]
>>> print b
[2, 2, 3]
第一个例子,我们将一个整数变量传递给函数,函数对它进行操作,但原整数变量a不发生变化。
第二个例子,我们将一个表传递给函数,函数进行操作,原来的表b发生变化。
对于基本数据类型的变量,变量传递给函数后,函数会在内存中复制一个新的变量,从而不影响原来的变量。(我们称此为值传递)
但是对于表来说,表传递给函数的是一个指针,指针指向序列在内存中的位置,在函数中对表的操作将在原有内存中进行,从而影响原有变量。 (我们称此为指针传递)
三、变量的作用域
局部变量 当你在函数定义内声明变量的时候,它们与函数外具有相同名称的其他变量没有任何关系,即变量名称对于函数来说是 局部 的。这称为变量的 作用域 。所有变量的作用域是它们被定义的块,从它们的名称被定义的那点开始。
def func(x):
print 'x is', x
x = 2 # x=2只在func函数内其作用
print 'Changed local x to', x x = 50
func(x) # func函数并没有返回数据过来
print 'x is still', x
输出:
原理:在函数中,我们第一次使用x
的 值 的时候,Python使用函数声明的形参的值。
接下来,我们把值2
赋给x
。x
是函数的局部变量。所以,当我们在函数内改变x
的值的时候,在主块中定义的x
不受影响。
在最后一个print
语句中,我们证明了主块中的x
的值确实没有受到影响。
全部变量 它是在函数外部定义的,作用域是整个文件,全局变量可以直接在函数里面应用,但是如果要在函数内部改变全局变量,必须使用 global 关键字进行声明。
全局变量一个特征就是:除非被删除,否则他们存活到脚本运行结束,且对于所有的函数都可访问。
def func():
global x print 'x is', x
x = 2
print 'Changed local x to', x x = 50
func()
print 'Value of x is', x
输出:
原理:global
语句被用来声明x
是全局的——因此,当我们在函数内把值赋给x
的时候,这个变化也反映在我们在主块中使用x
的值的时候。
详细例子:
bar = 10 #声明一个全局变量bar
def foo():
global bar #指定bar是全局变量,谁都不能替换!但是能修改原值!
bar2 = 0.1 #声明一个局部变量bar2
bar = 0.0001 #是对全局变量bar的修改,而不是在又声明一个局部变量将全局变量覆盖。
return bar+bar2 bar = 10000 #又对全局变量bar进行修改,但是为时已晚了,因为在foo函数里已经 return bar+bar2了
print foo() #综上,输出:0.1001
python学习笔记11(函数二): 参数的传递、变量的作用域的更多相关文章
- python学习笔记(3)--函数、参数、变量、递归
1.函数基本语法和特性 背景摘要 现在老板让你写一个监控程序,监控服务器的系统状况,当cpu\memory\disk等指标的使用量超过阀值时即发邮件报警,你掏出了所有的知识量吗,写出了以下代码 whi ...
- Python学习笔记11—函数
建立第一个函数 /usr/bin/env Python #coding:utf-8 def add_function(a,b): c = a+b print c if __name__==" ...
- python学习笔记之函数的参数
函数的参数有位置参数和关键字参数,位置参数一定要在关键字参数的前面,位置参数的优先级是高于关键字参数的,否则会报错 def my_abs(a,b): print(a) print(b) my_abs( ...
- Python学习笔记——以函数为参数的内置函数
1.用法 一个参数 def ds(x): return 2 * x + 1 print(ds(5)) 11 g = lambda x : 2 * x + 1 print(g(5)) 11 两个参数 d ...
- Python学习笔记之函数
这篇文章介绍有关 Python 函数中一些常被大家忽略的知识点,帮助大家更全面的掌握 Python 中函数的使用技巧 1.函数文档 给函数添加注释,可以在 def 语句后面添加独立字符串,这样的注释被 ...
- python学习笔记(4)--函数
1.函数 函数是指将一组语句的集合通过一个名字封装起来.要想执行这个函数,只需调用其函数名即可. 函数的特性: 1.减少重复代码 2.使程序变的课扩展 3.使程序变得易维护 语法定义: def pri ...
- Python学习笔记 for windows 二
函数 abs(-20) //结果为:20,绝对值函数 def 函数名称([参数1,参数2,参数3]): 执行语句 retu ...
- Python学习笔记_week3_函数
一.介绍 1.面向对象(华山派)--->类(独门秘籍)--->class(定义的关键字) 2.面向过程(少林派)--->过程--->def 3.函数式编程(逍遥派)---> ...
- Python学习笔记7-把函数当参数传递、指定可变参数
把函数当参数传递 # 函数参数传递 # 面向对象编程就是把对象传来传去 # 面向函数编程就是把函数传来传去 def mytest(num): return num * 2 # # 不光可以传递变量,还 ...
随机推荐
- hdu 3622 二分+2-SAT判定
思路:如题 #include<iostream> #include<algorithm> #include<cstring> #include<cstdio& ...
- HttpClient(4.3.5) - 简单示例
HttpClient 是一个客户端的 HTTP 传输库,而不是浏览器.HttpClient 的目的是传输和接收 HTTP 报文.HttpClient 不会尝试去处理报文内容,执行嵌入 HTML 内的 ...
- Linux 命令 - chown: 更改文件的所有者和所属群组
chown 命令用来更改文件或者目录的所有者和所属群组.使用这个命令需要超级用户的权限. 命令格式 chown [OPTION]... [OWNER][:[GROUP]] FILE... chown ...
- Django学习--9 Admin
1.vim settings.py 打开 'django.contrib.admin' vim urls.py 打开 from django.contrib import admin (注意 ...
- Android对象类系列化public class User implements Parcelable
package com.gaojinhua.android.activitymsg; import android.os.Parcel; import android.os.Parcelable; / ...
- JavaScript之模拟评星打分
<head> <meta http-equiv="Content-Type" content="text/html; charset=gb2312&qu ...
- android64位机子兼容32位.so库文件
http://blog.csdn.net/vhawk/article/details/49964475 猴子在调用高德地图的时候,遇到一个操作系统兼容问题,异常堆栈说是找不到so库文件,猴子就不懂了, ...
- Hibernate+DWR无刷新三级联动
DWR(Direct Web Remoting)是一个用于改善web页面与Java类交互的远程服务器端Ajax开源框架,可以帮助开发人员开发包含AJAX技术的网站.它可以允许在浏览器里的代码使用运行在 ...
- 编译android5.0源码的
java环境 Android 5.1 用到的jdk不再是Oracle 的 jdk ,而是开源的 openjdk,在ubuntu安装好后,使用如下命令安装jdk: $sudo apt-get insta ...
- IO&Seralize
IO <appSettings> <!--日志路径--> <add key="LogPath" value="E:\学习\C#进阶\fsoc ...