python默认参数只被解释一次_深入讲解Python函数中参数的使用及默认参数的陷阱...

C++里函数可以设置缺省参数,Java不可以,只能通过重载的方式来实现,python里也可以设置默认参数,最大的好处就是降低函数难度,函数的定义只有一个,并且python是动态语言,在同一名称空间里不能有想多名称的函数,如果出现了,那么后出现的会覆盖前面的函数。

def power(x, n=2):

s = 1

while n > 0:

n = n - 1

s = s * x

return s

看看结果:

>>> power(5)

25

>>> power(5,3)

125

注意: 必选参数在前,默认参数在后,否则Python的解释器会报错。

建议:*当函数有多个参数时,把变化大的参数放前面,变化小的参数放后面。变化小的参数就可以作为默认参数。

默认参数也有坑,看看下面的代码,先定义一个list,添加一个end再返回:

def add_end(L=[]):

L.append('END')

return L

看看调用结果:

>>> add_end([1, 2, 3])

[1, 2, 3, 'END']

>>> add_end(['x', 'y', 'z'])

['x', 'y', 'z', 'END']

>>> add_end()

['END']

>>> add_end()

['END', 'END']

>>> add_end()

['END', 'END', 'END']

这里需要解释一下,Python函数在定义的时候,默认参数L的值就被计算出来了,即[]。此时L指向[]。所以如果L中的内容改变了,下次调用引用的内容也就不再是[]了。所以要牢记一点定义默认参数必须指向不可变对象!。

可变参数第一种方法,传入的参数为一个list或者tuple。

def calc(numbers):

sum = 0

for n in numbers:

sum = sum + n * n

return sum

调用方式:

>>> calc([1, 2, 3])

14

>>> calc((1, 3, 5, 7))

84

第二种方式,直接传入多个参数,函数内部会自动用一个tuple接收。

def calc(*numbers):

sum = 0

for n in numbers:

sum = sum + n * n

return sum

调用方式:

>>> calc(1, 2)

5

>>> calc()

0

这个时候如果还想把一个list或者tuple里的数据传进去,可以这样:

>>> nums = [1, 2, 3]

>>> calc(*nums)

14

关键字参数关键字参数允许你传入0个或任意个含参数名的参数,这些关键字参数在函数内部自动组装为一个dict。

def person(name, age, **kw):

print 'name:', name, 'age:', age, 'other:', kw

调用示例:

>>> person('Michael', 30)

name: Michael age: 30 other: {}

>>> person('Bob', 35, city='Beijing')

name: Bob age: 35 other: {'city': 'Beijing'}

>>> person('Adam', 45, gender='M', job='Engineer')

name: Adam age: 45 other: {'gender': 'M', 'job': 'Engineer'}

参数组合在Python中定义函数,可以用必选参数、默认参数、可变参数和关键字参数,这4种参数都可以一起使用,或者只用其中某些,但是请注意,参数定义的顺序必须是:必选参数、默认参数、可变参数和关键字参数。

递归函数

基本的也没什么可讲的,和Java/C++里一样,就是调用本身的一种。这里重点介绍一下尾递归优化。事实上尾递归和循环效果是一样的,很显然的一个优点那就是可以防止递归调用栈溢出。

定义:在函数返回的时候调用自身,并且,return语句不能包含表达式。编译器或者解释器可以对其做优化,无论调用多少次,只占用一个栈帧,不会出现溢出的情况。

举个简单的例子,以阶乘函数为例:

def fact(n):

if n==1:

return 1

return n * fact(n - 1)

如果传入的n很大,就可能会溢出,这是由于return n * fact(n - 1)引入了乘法表达式,就不是尾递归了。把代码改一下:

def fact(n):

return fact_iter(n, 1)

def fact_iter(num, product):

if num == 1:

return product

return fact_iter(num - 1, num * product)

默认参数陷阱Python的函数定义提供了默认参数这个选择,使得函数的定义和使用更加的灵活,但是也会带来一些坑,例如之前的一个例子:

函数定义:

def add_end(L=[]):

L.append('END')

return L

调用函数的结果:

>>> add_end([1, 2, 3])

[1, 2, 3, 'END']

>>> add_end(['x', 'y', 'z'])

['x', 'y', 'z', 'END']

>>> add_end()

['END']

>>> add_end()

['END', 'END']

>>> add_end()

['END', 'END', 'END']

很明显这个与函数的定义初衷不符,用一句话解释就是:

Default values are computed once, then re-used.

为了深入研究这个问题,我们来看看另一个例子:

# coding=utf-8

def a():

print "a executed"

return []

def b(x=a()):

print "id(x):", id(x)

x.append(5)

print "x:", x

for i in range(2):

print "不带参数调用,使用默认参数"

b()

print b.__defaults__

print "id(b.__defaults__[0]):", id(b.__defaults__[0])

for i in range(2):

print "带参数调用,传入一个list"

b(list())

print b.__defaults__

print "id(b.__defaults__[0]):", id(b.__defaults__[0])

NOTE:稍微解释一下,所有默认值都存储在函数对象的__defaults__属性中,这是一个列表,每一个元素均为一个默认参数值。

来看看输出结果:

a executed

不带参数调用,使用默认参数

id(x): 140038854650552

x: [5]

([5],)

id(b.__defaults__[0]): 140038854650552

不带参数调用,使用默认参数

id(x): 140038854650552

x: [5, 5]

([5, 5],)

id(b.__defaults__[0]): 140038854650552

带参数调用,传入一个list

id(x): 140038854732400

x: [5]

([5, 5],)

id(b.__defaults__[0]): 140038854650552

带参数调用,传入一个list

id(x): 140038854732472

x: [5]

([5, 5],)

id(b.__defaults__[0]): 140038854650552

简单分析一下输出结果:

第1行

在定义函数b(),即执行def语句,代码第7行def b(x=a()):的时候,这句话使用了默认参数,所以在定义的时候会计算默认参数x的值,这个时候会调用a(),所以打印出了a executed。

第2~6行

第一次执行循环,代码第14行调用b()没有传递参数,使用默认参数,此时x=[],所以调用一次之后

print b.__defaults__

输出结果为

([5],)

第7~11行

第二次循环,代码第14行调用b()没有传递参数,使用默认参数。

注意:默认参数只会计算一次,也就是说那个内存区域就固定了,但是这个地址所指向的是一个list,内容可以改变,此时由于上一次调用x: [5],所以

print b.__defaults__

输出结果为

([5, 5],)

第12~16行

第二个循环语句,第一次循环,代码第20行传入一个空的list,所以不使用默认参数,此时x=[],所以

print b.__defaults__

输出结果为

([5],)

第18~21行

第二个循环语句,第二次循环,代码第20行传入一个空的list,所以也不使用默认参数,此时仍然是x=[],所以

print b.__defaults__

输出结果依然为

([5],)

函数也是对象,因此定义的时候就被执行,默认参数是函数的属性,它的值可能会随着函数被调用而改变。其他对象不都是如此吗?

牢记: 默认参数必须指向不变对象!代码改一下如下:

# coding=utf-8

def a():

print "a executed"

return None

def b(x=a()):

print "id(x):", id(x)

if x is None:

x = []

x.append(5)

print "x:", x

for i in range(2):

print "不带参数调用,使用默认参数"

b()

print b.__defaults__

print "id(b.__defaults__[0]):", id(b.__defaults__[0])

for i in range(2):

print "带参数调用,传入一个list"

b(list())

print b.__defaults__

print "id(b.__defaults__[0]):", id(b.__defaults__[0])

此时的输出结果看看是什么:

a executed

不带参数调用,使用默认参数

id(x): 9568656

x: [5]

(None,)

id(b.__defaults__[0]): 9568656

不带参数调用,使用默认参数

id(x): 9568656

x: [5]

(None,)

id(b.__defaults__[0]): 9568656

带参数调用,传入一个list

id(x): 140725126699632

x: [5]

(None,)

id(b.__defaults__[0]): 9568656

带参数调用,传入一个list

id(x): 140725126699704

x: [5]

(None,)

id(b.__defaults__[0]): 9568656

希望与广大网友互动??

点此进行留言吧!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/265934.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

fancybox去除不受待见的水平滚动条

用fancybox在嵌套某个页面时,有时莫名其妙的会出现的消除不掉的幽灵般水平滚动条,如何去除: github上的解决方案:https://github.com/fancyapps/fancyBox/issues/24 转载于:https://www.cnblogs.com/kinpauln/p/3145796.html

Word Count作业

Word Count作业 一.个人Gitee地址&#xff1a;https://gitee.com/Changyu-Guo 二.项目简介 该项目主要是模拟Linux上面的wc命令&#xff0c;基本要求如下&#xff1a; 命令格式&#xff1a; wc.exe [para] <filename> [para] <filename> ... -o <filename> 功…

iDempiere = OSGi + ADempiere 一款ERPCRMSCM系统、助力中小企业发展

怀揣着为中小企业量身定做一整套开源软件解决方案的梦想开始了一个网站的搭建。http://osssme.org/ iDempiere OSGi ADempiere 一款ERP&CRM&SCM系统、助力中小企业发展 一句话概括iDempiere是一款基于Compiere/ADempiere的​开源企业级ERP&CRM&SCM系统​&…

字符串 hash 唯一数字_【数字课堂】酒妹带你了解“身份认证技术”

身份认证技术是在计算机网络中确认操作者身份的过程而产生的有效解决方法。计算机网络世界中一切信息包括用户的身份信息都是用一组特定的数据来表示的&#xff0c;计算机只能识别用户的数字身份&#xff0c;所有对用户的授权也是针对用户数字身份的授权。如何保证以数字身份进…

内核启动流程—走马观花

汇编阶段&#xff1a; ensure svc mode and irqs disabled 76确保cpu运行与svc模式&#xff0c;中断关闭 get processor id 78获取cpu id r5procinfo r9cpuid invalid processor (r50)? 79 和__proc_info lists 里比较&#xff0c;不能找到id就 r5 0 bl __vet_atags…

空气中超声衰减

空气中超声衰减是非常厉害的&#xff0c;这导致在空气耦合声换能器的制作或是声传感器的设计是极具挑战的&#xff0c;因此对超声衰减做一个细致的分析是很有必要的。 具体计算根据经验公式如下进行计算 结果如下&#xff1a; Figure 1 超声衰减系数与频率关系图 Figure 2 超声…

嵌入式linux系统和嵌入式android系统的区别和联系

目录区别与联系嵌入式系统在物联网行业中的应用物联网嵌入式系统的特征区别与联系 这个问题很多人问&#xff0c;尤其是初入嵌入式的菜鸟。其实大家都认为android是java&#xff0c;已经不是linux&#xff0c;殊不知android就是靠着linux 才发展起来的&#xff0c;现在来说说有…

java生产者消费者问题代码分析

作者要的是一个生产者生成&#xff0c;接着必须有一个消费者消费&#xff0c;那这不是需要单线程吗&#xff1f;或者使用1个大小的阻塞队列。所以只谈论问题本身&#xff0c;不谈论好不好。 具体代码&#xff1a; Java代码 import java.util.concurrent.locks.Condition; i…

vb冒泡排序法流程图_VB算法-冒泡排序教案

1冒泡排序教学设计班级&#xff1a;高一一班授课教师&#xff1a;袁海军一、教案背景模块&#xff1a;算法与程序设计班级&#xff1a;高一(1)班课时数&#xff1a;1课时所用教材&#xff1a;华师大版《算法与程序设计》教师&#xff1a;袁海军二、教学设计1.教学目标知识与技能…

linux板级初始化

最近拿到了明远智睿 的EK314开发板&#xff0c;以前主要用2440&#xff0c;眼界过于狭隘&#xff0c;借此机会练习下。 http://lornyin.top/?p106 原文地址 首先看看它的板级文件 /arch/arm/mach-mx6/board-myimx6ek314.c 在他的末尾指定了map_io、init_irq、init_machine…

可以ping通 但ssh: connect to host 192.168.0.2 port 22: Connection refused

目录问题描述原因解决问题描述 自己在树莓派端通过SCP指令给电脑上ubuntu传输文件发现提示&#xff1a;ssh: connect to host 192.168.0.2 port 22: Connection refused&#xff0c;并且发现树莓派端是可以ping通ubuntu的。 原因 通过网上查新找到原因&#xff1a; SSH分客…

动态规划初步--数字三角形

数字三角形是一个由非负数组成的三角形&#xff0c;第n行有n个数&#xff0c;形如&#xff1a; 1 2 3 4 5 6 除最下行之外&#xff0c;每一行的左下和右下各有一个数&#xff0c;从第一行开始&#xff0c;向下&#xff0c;左或者右走一格&#xff0c;直到走到最后一行&#…

光影精灵5完全拆解全程图解_惠普光影精灵5值得买吗?惠普光影精灵5绿刃版游戏本深度拆解评测...

三星8GB DDR4 2666MHz内存还有一个小配件&#xff0c;虽然小&#xff0c;但绝对是最常用的&#xff0c;这就是无线模块。这款笔记本搭载的是Intel 9560NGW无线网卡&#xff0c;支持2.4GHz / 5GHz双频&#xff0c;最大传输速度可达1.73Gbps&#xff0c;并且集成蓝牙5.0版本&…

linux嵌入式贪吃蛇

目标&#xff1a;用游戏手柄控制贪吃蛇 硬件平台&#xff1a;imax6q 版本信息&#xff1a; arm-none-linux-gnueabi-gcc-4.8.3、 qt5.7.1、linux3.0.1 一、交叉编译tslib1.4 由于 imax6q是 armv7-a 构架&#xff0c;所以以后的编译我们都应编译出 armv7 平台的文件 编译参…

2.联邦模式配置---扩容,负载均衡

原理图 两个集群---目的&#xff1a;扩容 HA联邦模式解决了单纯HA模式的性能瓶颈&#xff08;主要指Namenode、ResourceManager&#xff09;&#xff0c;将整个HA集群划分为两个以上的集群&#xff0c;不同的集群之间通过Federation进行连接&#xff0c;使得HA集群拥有了横向扩…

树莓派交叉编译(PS交叉编译链下载安装、配置永久环境变量、带WiringPi库交叉编译、软链接)

目录一、本章概述二、交叉编译工具链的下载安装下载安装交叉编译链临时有效交叉编译链永久有效三、交叉编译的使用对比gcc与armgccPC端交叉编译发送到树莓派运行四、带WiringPi库的交叉编译如何处理复制树莓派上的WiringPi库到主机软硬链接交叉编译一、本章概述 下面将详细介绍…

海量数据处理分析(部分)

2019独角兽企业重金招聘Python工程师标准>>> 1. 海量数据处理分析 原文地址&#xff1a; http://blog.csdn.net/DaiZiLiang/archive/2006/12/06/1432193.aspx 笔者在实际工作中&#xff0c;有幸接触到海量的数据处理问题&#xff0c;对其进行处理是一项艰巨而复…

android p wifi一直在扫描_在Android上的每次WiFi扫描之间我应该使用什么时间间隔?...

我需要定期执行Wifi扫描.当时间间隔设置为1-2秒时,我遇到了问题.好像我没有得到任何ScanResult.是否有最短的时间设置,以便WifiManager能够执行成功的WiFi扫描&#xff1f;这是代码.我正在使用服务进行Wifi扫描&#xff1a;public class WifiScanning extends Service{private …

uboot2015–启动流程分析 imx6q

最近项目原因&#xff0c;要在uboot中增加内核验校和内核损坏修复功能&#xff0c;所以需要回头看看uboot。这次选择了uboot2015来进行分析 uboot是明远睿智提供的。 下载地址 链接&#xff1a;https://pan.baidu.com/s/13SuRii3WTqvFTNIsSS9GAg 密码&#xff1a;65zz 环境&…

树莓派内核开发准备(内核源码获取、启动过程、源码目录树)

目录1.交叉编译工具的安装2.内核源码获取3.嵌入式设备带操作系统的启动过程扫盲4.Linux内核源码树扫盲1.内核源码简介2.Linux内核源代码目录树结构tree指令查看内核源码目录树1.交叉编译工具的安装 参照我之前的笔记 2.内核源码获取 下载哪个版本取决于树莓派的版本&#xf…