Python中的函数用法。

一.函数的定义

在某些编程语言当中,函数声明和函数定义是区分开的(在这些编程语言当中函数声明和函数定义可以出现在不同的文件中,比如C语言),但是在Python中,函数声明和函数定义是视为一体的。
在Python中,函数定义的基本形式如下:

def function(params):blockreturn expression/value

在这里说明几点:
  (1)在Python中采用def关键字进行函数的定义,不用指定返回值的类型。
  (2)函数参数params可以是零个、一个或者多个,同样的,函数参数也不用指定参数类型,因为在Python中变量都是弱类型的,Python会自动根据值来维护其类型。 这点就很好,不用刻意去维护函数入参和出参
  (3)return语句是可选的,它可以在函数体内任何地方出现,表示函数调用执行到此结束;
   如果没有return语句,会自动返回NONE,如果有return语句,但是return后面没有接表达式或者值的话也是返回NONE。
   下面看两个例子:

def printHello():print 'hello'
def printNum():for i in range(0,10):print ireturn
def add(a,b):return a+b
print printHello()
print printNum()
print add(1,2)

二.函数的使用

在定义了函数之后,就可以使用该函数了,但是在Python中要注意一个问题,就是在Python中不允许前向引用,即在函数定义之前,不允许调用该函数。看个例子就明白了:

print add(1,2)
def add(a,b):return a+b

这段程序运行的结果是:
  从报的错可以知道,名字为"add"的函数未进行定义。所以在任何时候调用某个函数,必须确保其定义在调用之前。

三.实参和形参

在学习C语言函数的时候,遇到的问题主要有形参实参的区别、参数的传递和改变、变量的作用域。同样在Python中,关于对函数的理解和使用也存在这些问题。
一.函数形参和实参的区别
  相信有过编程语言经验的朋友对形参和实参这两个东西并不陌生。形参全称是形式参数,在用def关键字定义函数时函数名后面括号里的变量称作为形式参数。实参全称为实际参数,在调用函数时提供的值或者变量称作为实际参数。举个例子:

#这里的a和b就是形参
def add(a,b):return a+b
#这里的1和2是实参
add(1,2)
x=2
y=3
#这里的x和y是实参
add(x,y)

二.参数的传递和改变
  在大多数高级语言当中,对参数的传递方式这个问题的理解一直是个难点和重点,因为它理解起来并不是那么直观明了,但是不理解的话在编写程序的时候又极其容易出错。
  首先在讨论这个问题之前,我们需要明确一点就是在Python中一切皆对象,变量中存放的是对象的引用。这个确实有点难以理解,“一切皆对象”?对,在Python中确实是这样,包括我们之前经常用到的字符串常量,整型常量都是对象。不信的话可以验证一下:

def f1():print '&2', ;print id(2)x=2print '&x', ;print id(x)y='hello'print '&hello', ;print id("hello")print '&y', ;print id(y)

先解释一下函数id( )的作用。下面这段话是官方文档对id()函数的解释:

显而易见,id(object)函数是返回对象object在其生命周期内位于内存中的地址,id函数的参数类型是一个对象,因此对于这个语句

id(2)没有报错,就可以知道2在这里是一个对象。下面再看几个例子:

x=2
print id(2)
print id(x)
y='hello'
print id('hello')
print id(y)

从结果可以看出,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 '&2', ;print id(2)
print '&x', ;print id(x)
x=3
print '&3', ;print id(3)
print '&x', ;print id(x)
L=[1,2,3]
M=L
print '&L', ;print id(L)
print '&M', ;print id(M)
print '&L[2]', ;print id(L[2])
L[0]=2
print '&L', ;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]本身的存储地址)。

下面就来讨论一下函数的参数传递和改变这个问题。

在Python中参数传递采用的是值传递,这个和C语言有点类似。先看几个例子:

def modify1(m,K):m=2K=[4,5,6]return
def modify2(m,K):m=2K[0]=0return
def f3():n=100L=[1,2,3]modify1(n,L)print nprint Lmodify2(n,L)print nprint L


 从结果可以看出,执行modify1( )之后,n和L都没有发生任何改变;
 执行modify2( )后,n还是没有改变,L发生了改变。因为在Python中参数传递采用的是值传递方式,在执行函数modify1时,先获取n和L的id( )值,然后为形参m和K分配空间,让m和K分别指向对象100和对象[1,2,3]。m=2这句让m重新指向对象2,而K=[4,5,6]这句让K重新指向对象[4,5,6]。这种改变并不会影响到实参n和L,所以在执行modify1之后,n和L没有发生任何改变;
 在执行函数modify2时,同理,让m和K分别指向对象2和对象[1,2,3],然而K[0]=0让K[0]重新指向了对象0(注意这里K和L指向的是同一段内存),所以对K指向的内存数据进行的任何改变也会影响到L,因此在执行modify2后,L发生了改变。
 三.变量的作用域
  在Python中,也存在作用域这个问题。在Python中,会为每个层次生成一个符号表,里层能调用外层中的变量,而外层不能调用里层中的变量,并且当外层和里层有同名变量时,外层变量会被里层变量屏蔽掉。举个例子:

def function():x=2count=2while count>0:x=3print xcount=count-1
function()

在函数function中,while循环外面和while循环里面都有变量x,此时,while循环外面的变量x会被屏蔽掉。注意在函数内部定义的变量作用域都仅限于函数内部,在函数外部是不能够调用的,一般称这种变量为局部变量。
  还有一种变量叫做全局变量,它是在函数外部定义的,作用域是整个文件。全局变量可以直接在函数里面应用,但是如果要在函数内部改变全局变量,必须使用global关键字进行声明。

x=2
def fun1():print x
def fun2():global xx=3print x
fun1()
fun2()
print x

三 函数参数类型

在前面两篇文章中已经探讨了函数的一些相关用法,下面一起来了解一下函数参数类型的问题。在C语言中,调用函数时必须依照函数定义时的参数个数以及类型来传递参数,否则将会发生错误,这个是严格进行规定的。然而在Python中函数参数定义和传递的方式相比而言就灵活多了。
一.函数参数的类型
  之前我们接触到的那种函数参数定义和传递方式叫做位置参数,即参数是通过位置进行匹配的,从左到右,依次进行匹配,这个对参数的位置和个数都有严格的要求。*在Python中还有一种是通过参数名字来匹配的,这样一来,不需要严格按照参数定义时的位置来传递参数,这种参数叫做关键字参数。*下面举两个例子:

def display(a,b):print aprint b
display('hello','world')

这段程序是想输出’hello world’,可以正常运行。如果像下面这样写的话,结果可能就不是预期的样子了:

def display(a,b):print aprint b
#这样会报错
display('hello')
#这样会输出'world hello'
display('world','hello')

可以看出在Python中默认的是采用位置参数来传参。这样调用函数必须严格按照函数定义时的参数个数和位置来传参,否则将会出现预想不到的结果。下面这段代码采用的就是关键字参数:

def display(a,b):print aprint b
#下面2句达到的效果是相同的
display(a='world',b='hello')
display(b='hello',a='world')

可以看到通过指定参数名字传递参数的时候,参数位置对结果是没有影响的。
关键字参数最厉害的地方在于它能够给函数参数提供默认值。比如:

def display(a='hello',b='wolrd'):print a+b
display()
display(b='world')
display(a='hello')
display('world')

在上面的代码中,分别给a和b指定了默认参数,即如果不给a或者b传递参数时,它们就分别采用默认值。在给参数指定了默认值后,如果传参时不指定参数名,则会从左到右依次进行传参,比如display(‘world’)没有指定’world’是传递给a还是b,则默认从左向右匹配,即传递给a。
  使用默认参数固然方便,但是有一点要非常注意,在重复调用函数时默认形参会继承之前一次调用结束之后该形参的值。下面看一个例子:

def insert(a,L=[]):L.append(a)print L
insert('hello')
insert('world')

其运行结果为:
  

二.任意个数参数
  一般情况下我们在定义函数时,函数参数的个数是确定了的,然而某些情况下我们是不能确定参数的个数的,比如要存储某个人的名字和它的小名,某些人小名可能有2个或者更多个,此时无法确定参数的个数,就可以使用收集参数了,使用收集参数只需在参数前面加上’*‘或者’**’。

def storename(name,*nickName):print 'real name is %s' %namefor nickname in nickName:print nickname
storename('jack')
storename(u'詹姆斯',u'小皇帝')
storename(u'奥尼尔',u'大鲨鱼',u'三不沾')

'‘和’**‘表示能够接受0到任意多个参数,’‘表示将没有匹配的值都放在同一个元组中,’**'表示将没有匹配的值都放在一个dictionary中。

def printvalue(a,**d):print 'a=%d' %afor x in d:print x+'=%d' %d[x]printvalue(1,b=2,c=3)

最后需要补充一点:Python中函数是可以返回多个值的,如果返回多个值,会将多个值放在一个元组或者其他类型的集合中来返回。

def function():x=2y=[3,4]return x,y
print function()

重在积累,每天记录一点点

Python中函数的用法相关推荐

  1. python教程实例-Python中函数的用法实例教程

    本文以数值计算为例讲述了Python中函数的用法,分享给大家供大家参考借鉴之用.具体如下: 我们都知道圆的面积计算公式为: S = πr2 当我们知道半径r的值时,就可以根据公式计算出面积.假设我们需 ...

  2. python中的super用法详解_Python中super函数用法实例分析

    本文实例讲述了python中super函数用法.分享给大家供大家参考,具体如下: 这是个高大上的函数,在python装13手册里面介绍过多使用可显得自己是高手 23333. 但其实他还是很重要的. 简 ...

  3. 五分钟理解yield在python中的简单用法,让你不再迷惑

    很多同学无论是在学习python还是使用python的过程中,都会遇到yield关键字,这个让人头大的问题,今天,就给大家分享一下我自学yield的心路历程 基本概念: (1)在 Python 中,使 ...

  4. 详解python中的用法_详解python中*号的用法

    1.表示乘号 2.表示倍数,例如: def T(msg,time=1): print((msg+' ')*time) T('hi',3) 打印结果(打印3次): hi hi hi 3.单个 * (1) ...

  5. python中的super用法详解_【Python】【类】super用法详解

    一.问题的发现与提出 在Python类的方法(method)中,要调用父类的某个方法,在Python 2.2以前,通常的写法如代码段1: 代码段1: class A: def __init__(sel ...

  6. Python中yield简单用法

    Python中yield简单用法 你或许知道带有yield的函数在Python中被称之为generator,那何为 generator? 我们暂时抛开generator,先从一个常见编程题目开始,循序 ...

  7. python中lambda()的用法_python中lambda()的用法

    在C++11和C#中都有匿名函数的存在.下面看看在python中匿名函数的使用. 1.lambda只是一个表达式,函数体比def简单很多. 2.lambda的主体是一个表达式,而不是一个代码块.仅仅能 ...

  8. python中path的用法,python中path的用法

    如何将python的路径加到path中 方法一:函数添加 1 import sys 2 查看sys.path 3 添加sys.path.append("c:\\") 方法二:修改环 ...

  9. map函数的用法python,详解Python map函数及Python map()函数的用法

    python map函数 map()函数 map()是 Python 内置的高阶函数,它接收一个函数 f 和一个 list,并通过把函数 f 依次作用在 list 的每个元素上,得到一个新的 list ...

  10. python两个乘号_详解python中*号的用法!(含实例:零基础也看能懂)

    前言: 今天为大家带来的内容是python中*号的用法,文中通过代码给大家介绍了双星号(**)的用法,非常不错,具有一定的参考借鉴价值,需要的朋友可以参考下. 1.表示乘号 2.表示倍数,例如: de ...

最新文章

  1. 解决Jsp与Java后台之间url传值中文乱码问题
  2. 1-STM32+W5500+GPRS物联网开发基础篇-工控板简介
  3. logo、展板、彩页、手提袋总结
  4. java流程控制both_java web面试题
  5. 数据结构 创建顺序栈
  6. 每天Leetcode 刷题 初级算法篇-设计问题-最小栈
  7. 计算机算法常用英语,计算机术语 算法相关术语
  8. 软件测试缺陷报告分析,测试报告中的缺陷分析和测试结论应该怎么写?
  9. STM32-GPRS模块连接系统主站
  10. 中望cad自定义快捷键命令_CAD如何设置新的命令快捷键
  11. 总有一些声音令人热血澎湃
  12. windows云服务器,如何使用windows云服务器
  13. Excel函数完整列表(Excel Function Full List)
  14. 摩拜创始人套现15亿:你的同龄人,正在抛弃你+韩寒回应
  15. zcurd上了开源中国头条
  16. Ubuntu设置apt源
  17. java中excel上传_java对excel表格的上传和下载处理
  18. Java中一年有几周、周的计算
  19. Linux(5):正则表达式 权限
  20. python图像计数_计算机视觉:利用OpenCV和Python进行车辆计数详细步骤

热门文章

  1. Android【报错】android.content.ActivityNotFoundException:activity in yourAndroidManifest.?
  2. 1002 写出这个数 (20 分)—PAT (Basic Level) Practice (中文)
  3. Android ListView + ArrayAdapter、SimpleAdapter、BaseAdapter实现列表
  4. MTK平台调试加密芯片ATSHA204A
  5. Linux的c编程getopt(分析命令行参数)
  6. C#通过正则表达式判断字符是否为数字
  7. jquer同时选择多个不同的id执行同意操作
  8. 涨姿势系列之——内核环境下花式获得CSRSS进程id
  9. 平均分配,移动欠费催收款数据的分配应用实例
  10. HCIE-Security Day16:防火墙双机热备实验(四)防火墙直路部署,上行连接路由器(OSPF),下行连接交换机