京公网安备 11010802034615号
经营许可证编号:京B2-20210330
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
数据分析咨询请扫描二维码
若不方便扫码,搜微信号:CDAshujufenxi
在用户从“接触产品”到“完成核心目标”的全链路中,流失是必然存在的——电商用户可能“浏览商品却未下单”,APP新用户可能“ ...
2026-01-14在产品增长的核心指标体系中,次日留存率是当之无愧的“入门级关键指标”——它直接反映用户对产品的首次体验反馈,是判断产品是 ...
2026-01-14在CDA(Certified Data Analyst)数据分析师的业务实操中,“分类预测”是高频核心需求——比如“预测用户是否会购买商品”“判 ...
2026-01-14在数字化时代,用户的每一次操作——无论是电商平台的“浏览-加购-下单”、APP的“登录-点击-留存”,还是金融产品的“注册-实名 ...
2026-01-13在数据驱动决策的时代,“数据质量决定分析价值”已成为行业共识。数据库、日志系统、第三方平台等渠道采集的原始数据,往往存在 ...
2026-01-13在CDA(Certified Data Analyst)数据分析师的核心能力体系中,“通过数据建立模型、实现预测与归因”是进阶关键——比如“预测 ...
2026-01-13在企业数字化转型过程中,业务模型与数据模型是两大核心支撑体系:业务模型承载“业务应该如何运转”的逻辑,数据模型解决“数据 ...
2026-01-12当前手游市场进入存量竞争时代,“拉新难、留存更难”成为行业普遍痛点。对于手游产品而言,用户留存率不仅直接决定产品的生命周 ...
2026-01-12在CDA(Certified Data Analyst)数据分析师的日常工作中,“挖掘变量间的关联关系”是高频核心需求——比如判断“用户停留时长 ...
2026-01-12在存量竞争时代,用户流失率直接影响企业的营收与市场竞争力。无论是电商、互联网服务还是金融行业,提前精准预测潜在流失用户, ...
2026-01-09在量化投资领域,多因子选股是主流的选股策略之一——其核心逻辑是通过挖掘影响股票未来收益的各类因子(如估值、成长、盈利、流 ...
2026-01-09在CDA(Certified Data Analyst)数据分析师的工作场景中,分类型变量的关联分析是高频需求——例如“用户性别与商品偏好是否相 ...
2026-01-09数据库中的历史数据,是企业运营过程中沉淀的核心资产——包含用户行为轨迹、业务交易记录、产品迭代日志、市场活动效果等多维度 ...
2026-01-08在电商行业竞争日趋激烈的当下,数据已成为驱动业务增长的核心引擎。电商公司的数据分析师,不仅是数据的“解读官”,更是业务的 ...
2026-01-08在数据驱动决策的链路中,统计制图是CDA(Certified Data Analyst)数据分析师将抽象数据转化为直观洞察的关键载体。不同于普通 ...
2026-01-08在主成分分析(PCA)的学习与实践中,“主成分载荷矩阵”和“成分矩阵”是两个高频出现但极易混淆的核心概念。两者均是主成分分 ...
2026-01-07在教学管理、学生成绩分析场景中,成绩分布图是直观呈现成绩分布规律的核心工具——通过图表能快速看出成绩集中区间、高分/低分 ...
2026-01-07在数据分析师的工作闭环中,数据探索与统计分析是连接原始数据与业务洞察的关键环节。CDA(Certified Data Analyst)作为具备专 ...
2026-01-07在数据处理与可视化场景中,将Python分析后的结果导出为Excel文件是高频需求。而通过设置单元格颜色,能让Excel中的数据更具层次 ...
2026-01-06在企业运营、业务监控、数据分析等场景中,指标波动是常态——无论是日营收的突然下滑、用户活跃度的骤升,还是产品故障率的异常 ...
2026-01-06