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

希望与广大网友互动??

点此进行留言吧!

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

  1. 定义python函数时如果没有return_定义 Python 函数时,如果函数中没有 return 语句,则默认返回空值 None 。_学小易找答案...

    [多选题]因发现核酶而共享诺贝尔化学奖的科学家是(). [简答题]如果是六角梅花,你还可以用什么方法完成? [填空题]如果函数中没有 return 语句或者 return 语句不带任何返回值,那么该函 ...

  2. python函数设置默认参数_深入讲解Python函数中参数的使用及默认参数的陷阱

    这篇文章主要介绍了Python函数中参数的使用及默认参数的陷阱,文中将函数的参数分为必选参数.默认参数.可变参数和关键字参数来讲,要的朋友可以参考下 C++里函数可以设置缺省参数,Java不可以,只能 ...

  3. 用python画一只可爱的皮卡丘_用python画一只可爱的皮卡丘实例

    效果图 #!/usr/bin/env python # -*- coding:utf-8 -*- from turtle import * ''' 绘制皮卡丘头部 ''' def face(x,y): ...

  4. 用python构建多只股票日收益率直方图_用Python分析多股票的投资组合

    俗话说不要将所有的鸡蛋放在同一个篮子里,在投资股票的时候我们也会多买几只以抵抗风险.本文将带领着你使用Python,来分析多只股票投资时的收益和风险,并找到最优的投资组合方案.这是上一篇文章<用 ...

  5. 用python输出12和8的最大公_重点汇总-python常见问题1

    1. 简述函数式编程 解释一: 在函数式编程中,函数是基本单位,变量只是一个名称,而不是一个存储单元.除了匿名函数外,Python还使fliter(),map(),reduce(),apply()函数 ...

  6. python 字典的值可以为集合吗_转:Python字典与集合操作总结

    1 一.创建字典2 方法①:3 >>> dict1 ={}4 >>> dict2 = {'name': 'earth', 'port': 80}5 >> ...

  7. python封装exe如何返回上一步_如何将python脚本封装成exe程序?

    我们在编写代码时候,,有没有想过怎么去运行这个代码,绝非是在编程软件里的预览哦.而是让用户去使用,绝对要成一个安装包,如果刚刚入门的小伙伴,肯定没有想过这些,因为大部分人,还处于在搭建代码的状态下,但 ...

  8. 学python应该掌握的英语单词怎么写_想学Python但是有好多英语单词不认识,Python的常见英语单词都在这儿...

    想学python但是有好多英文单词不认识怎么办? 以下是python代码编写和提示信息中的常用和常见的英文单词. 不需要背,看得多了用到的多了就熟悉了. 另外,我为大家准备了2020最新的学习资料,路 ...

  9. python闭包与装饰器有啥关系_深入理解Python中的闭包与装饰器

    函数的装饰器可以以某种方式增强函数的功能,如在 Flask 中可使用 @app.route('/') 为视图函数添加路由,是一种十分强大的功能.在表现形式上,函数装饰器为一种嵌套函数,这其中会涉及到闭 ...

最新文章

  1. js 中转换成list集合_java stream中Collectors的用法
  2. 工作随笔-日常工作-小说站 PC版
  3. web默认字体最佳实践
  4. 机器学习中的算法-支持向量机(SVM)基础
  5. mysql 用户授权_mysql添加、删除用户和授权用户
  6. 深度学习“炼丹”难?三分钟带你了解国产丹炉旷视天元
  7. 图层上下_「只要功夫深 不用关键帧」之图层序号的玩法
  8. go语言 slice
  9. python字典功能默写_新华字典APP每天只能免费查两字,完整版卖40元!网友嫌贵...
  10. CAML: FAST CONTEXT ADAPTATION VIA META-LEARNING
  11. java String字符串去除()里的内容
  12. hive:窗口函数/开窗函数 OVER()(笔记)
  13. CC2591和RFX2401C在zstack中的设置
  14. 图像特效---(Sketch Filter)素描滤镜
  15. 每天可以一看的哲理句子
  16. vue 页面使用两套el-form表单并且嵌套使用el-checkbox
  17. 【九度OJ】查找第K小数
  18. 2017华为实习生招聘机考模拟题——0交换排序
  19. 微软服务器操作系统软件价格,供应微软服务器操作系统软件
  20. 小程序页面设计模板都有哪些推荐

热门文章

  1. cobbler基础安装
  2. api-gateway实践(03)新服务网关 - 网关请求拦截检查
  3. orcale 之 集合操作
  4. nagios 监控配置介绍(二)
  5. 主板模式的两项通用性接口
  6. ubuntu下搭载LNMP环境,解决 fpm监听失败
  7. mysql配置文件注解
  8. hideprocess in bcb
  9. 嵌入式Linux系统基础知识
  10. apiexample.c例子教我们如何利用FFMPEG库中的API函数来编写自己的编解码程序