# -*- coding: utf-8 -*-
# @Time : 2019/11/8 8:55
# @Author : John
# @Email : 2398344557@qq.com
# @File : 函数.py
# @Software: PyCharm
- 函数的格式:
# def 函数名():
# 函数实现
# pass # pass空语句
- 定义一个函数
def say_hello():
print('hello, xuebi')
# 调用
say_hello()
# —— hello, xuebi
- 函数执行的顺序:调用时候才会执行
# # 栗子:
num = 100
print(num)
def say_hello():
print('hello1')
print('hello2')
print('hello3')
print('xuebi')
# 调用
say_hello()
print('1233')
# 运行顺序:num = 10
# print(num)
# print('xuebi')
# say_hello()
# print('hello1')
# print('hello2')
# print('hello3')
# print('1233')
—— 100
xuebi
hello1
hello2
hello3
1233
- 用函数的原因
# 为啥要用函数:
# 栗子:
str1 = 'abcdefg'
str1 = str1[:2] + 'z' + str1[3:]
print(str1)
# —— abzdefg
str2 = '1234567'
str2 = str2[:2] + '8' + str2[3:]
print(str2)
# —— 1284567
# 找规律改进,封装成函数:
def set_str(msg, index, char):
# 函数文档字符串
"""
将目标字符串的指定位置进行替换
:param msg: 目标字符串
:param index: 替换字符串的索引位置
:param char: 要替换的字符
:return: 返回替换完成的字符串
"""
# 对给定的char进行判断:isinstance(char, type),判断两个变量是否属于某种类型
if isinstance(char, int):
char = str(char)
return msg[:index] + char + msg[index+1:]
res1 = set_str('1234567', 2, 9)
res2 = set_str('abcdefg', 2, 'o')
print(res1)
print(res2)
# —— 1294567
# abodefg
- 函数的形参和实参
形参:形式参数
实参:实际调动的参数
区别:
- 形参是虚拟的,不占内存空间,形参变量只有在被调用的时候才分配内存空间
- 实参是一个变量,占用内存空间
注意:数据是单向传送的,实参传给形参
【实例1】求一个矩形的面积
def area(width, length):
return width*length
print(area(width=4, length=6)) # 实参,指定返回值,位置可变
print(area(length=6, width=4)) # 实参,指定返回值,位置可变
print(area(4, 6)) # 位置不能换,指顺序传给函数
—— 24
24
24
- 函数参数
# 1. 必须参数:以正确的顺序传入参数,调用时必须和声明的时候保持一致,不然会报错
# def f():
# pass
# f('xuebi')
# # —— TypeError: f() takes 0 positional arguments but 1 was given
# ------------
# def f(name, age):
# print('我叫%s'%(name), '我今年%d岁了'%(name, age))
# f('xuebi')
# # —— TypeError: f() missing 1 required positional argument: 'age'
# ------------
def f(name, age):
print('我叫%s,我今年%d岁了'%(name, age))
f('xuebi', 18)
# —— 我叫xuebi,我今年18岁了
# ------------
def f(name, age):
print('我叫%s,我今年%d岁了'%(name, age))
f(19, 'xuebi')
# —— TypeError: %d format: a number is required, not str
# 解决方法:===>
# 2. 关键字参数,允许函数调用时参数的顺序可以与声明不一致,因为python解释器能够用参数名匹配参数值
def f(name, age):
print('我叫%s,我今年%d岁了'%(name, age))
f(age=18, name='xuebi')
# —— 我叫xuebi,我今年18岁了
# 3. 默认参数(缺省参数)
# 在调用函数是,缺省的参数如果没有被传入,则会使用默认值
def f(name, age, sex='male'):
print('我叫%s,我今年%d岁了'%(name, age))
print('性别%s'%(sex))
f(age=18, name='xuebi') # 没有传入相应sex参数时,返回sex的默认值male
# —— 我叫xuebi,我今年18岁了
# 性别male
f(age=18, name='xuebi', sex='female') # 有相应的sex参数传入时会对默认值进行修改或覆盖,相同时忽略
# —— 我叫xuebi,我今年18岁了
# 性别female
# 4. 不定长参数
# 一个函数能处理比当初声明时更多的参数
# def funcname(*args, **kwargs):
# """文档字符串"""
# pass
# 或
# def funcname([formal_args,...]*args, **kwargs):
# """文档字符串"""
# pass
# 加了星号(*)的变量args(此命名不唯一),会存放所有未命名的变量参数,args为元组
# 加了星星号(**)的变量kwargs(此命名不唯一),会存放命名参数,即形如key=value的参数,kewargs为字典
def func(a, b, *args, **kwargs):
"""
可变参数演示范例
:param a: formal_args
:param b: formal_args
:param args: 未命名的变量参数args为元组
:param kwargs: 命名参数kwargs为字典
:return: 无
"""
print('a=', a)
print('b=', b)
print('args=', args)
print('kwargs=')
for k, v in kwargs.items():
print(k, '---->', v)
# 情况一:
func(1, 2, 3, 4, 5, m=6, n=7, p=8)
# —— a= 1
# b= 2
# args= (3, 4, 5)
# kwargs=
# m ----> 6
# n ----> 7
# p ----> 8
# 情况二:
c = (3, 4, 5)
d = {'m': 6, 'n': 7, 'p': 8}
func(1, 2, *c, **d)
# —— a= 1
# b= 2
# args= (3, 4, 5)
# kwargs=
# m ----> 6
# n ----> 7
# p ----> 8
# 情况三:
c = (3, 4, 5)
d = {'m': 6, 'n': 7, 'p': 8}
func(1, 2, c, d)
# —— a= 1
# b= 2
# args= ((3, 4, 5), {'m': 6, 'n': 7, 'p': 8})
# kwargs=
- 函数的返回值
如果想要获取函数的执行结果,我们一般要设置编写函数的返回值,使用return可以把结果返回
return 的作用:
- 停止这个函数的执行,返回指定的结果
- Python中的return可以返回多个结果(对象),解释器会将其组装成一个元组作为一个整体结果输出
- 如果未指定return,那么这个函数的返回值是None值
【实例2】给定一个列表,将列表中所有数字进行累加,并且返回他们的累加和以及平均数
def sum_and_average(list):
"""
:param list: 给定一个列表
:return: 返回他们的累加和以及平均数
"""
sum = 0
count = 0
average = 0
for x in list:
if isinstance(x, int) or isinstance(x, float):
# 进行累加
sum += x
# 计数
count += 1
average = sum/count
return sum, average
li = [20, 15, 2.8, 'a', 35, 5.9, -1.8]
print(sum_and_average(li)) # 输出的是一个元组
# —— (76.9, 12.816666666666668)
print('累计和:', sum_and_average(li)[0]) # 输出元组第一个元素
# —— 累计和: 76.9
print('平均数:', sum_and_average(li)[1]) # 输出元组第二个元素
# —— 平均数: 12.816666666666668
- 匿名函数(lambda表达式)
- 不需要显示指定名字的函数
- lambda 的参数可以是无限个,但返回的表达式只能有一个
- 主要目的:联合其他函数使用
格式:函数名 = lambda 参数1, 参数2, ... 参数n : 返回表达式
优点:
- 不用担心函数名冲突,
- 减少代码量,
- 优雅
【练习1】两数相乘
def mul(x, y):
return x*y
# 或用lambda:
mul2 = lambda x, y: x*y
print(mul2(3, 4))
# —— 12
【练习2】将x和y进行比较,如果x>y,返回x*y;否则返回x/y
def cheng_chu(x, y):
"""
两个数对比之后进行计算
:param x: 传入的第一个参数
:param y: 传入的第二个参数
:return: 当x>y时返回x*y;当x<y时返回x/y
"""
if x > y:
return x*y
else:
return x/y
print(cheng_chu(2, 5))
# —— 0.4
print(cheng_chu(5, 2))
# —— 10
# 或用lambda+三目运算符:
cheng_chu2 = lambda x, y: (x*y if x > y else x/y)
print(cheng_chu2(10, 25))
# —— 0.4
【插曲】回顾:三目运算符
store = ['']
if len(store) == 0:
store = '当当自营'
else:
store = store[0]
# 或用三目表达式:
print('当当自营' if len(store) == 0 else store[0])
函数作用域
x = 100
x = str(100) # 强制类型转换
print('hello' + x)
# —— hello100
str = 90 # built-in作用域(python自带的函数或已经定义好的)。改变类型为数据,不再是内置函数
y = str(100)
print('hello' + x)
# —— TypeError: 'int' object is not callable
# # 结论:定义的变量不要与保留字和函数重叠
g_counter = 33 # 全局作用域
def outer():
o_count = 0 # 嵌套作用域(函数范围内可用)
def inner():
i_counter = 10 # 局部作用域(离开局部作用域之后,数据销毁)
print(i_counter)
print(o_count)
print(g_counter)
inner()
# print(i_counter)
print(o_count)
print(g_counter)
outer()
# print(i_counter)
# print(o_count)
print(g_counter)
# # 结论:作用域遵循就近原则(LEGB)
# L:
# E:
# G:
# B:
10
0
33
0
33
33
x = 90
def f2():
global x
x += 88
print(x)
f2()
print(x) # 此时全局变量x已经发生变化
—— 90
78
a = 666
def outer():
out_count = 3
def inner():
# global out_count # 在全局作用域找
nonlocal out_count # 非本地非全局作用域(嵌套作用域)
out_count += 3
inner()
print(out_count)
outer()
—— 6
递归函数
【练习】阶乘
def jiecheng(n):
ret = n
for i in range(1, n):
ret *= i
return ret
result = jiecheng(5)
print(result)
—— 120
【练习】求n的阶乘
def jiecheng_new(n):
if n == 1: # 终止步骤
return 1
return n * jiecheng_new(n-1)
result = jiecheng_new(6)
print(result)
—— 720
【练习】斐波那数列
def fibo(n):
before = 0
after = 1
for i in range(n-1): # 循环次数等于输入的位置-1
ret = before + after # 指针往后挪一位
before = after # 指针往后挪一位
after = ret
print(before, end='\t')
return ret
print(fibo(9))
—— 1 1 2 3 5 8 13 21 34
【练习】斐波那契数列
def fibo(n):
if n <= 1: # 终止条件
return n
return fibo(n-1)+fibo(n-2)
print(fibo(7))
—— 13
# 缺点:效率不高且无法打印执行过程
【练习】斐波那数列(缓存,可提高运行速度)
cache = {}
def fibo(n):
if n <= 1: # 终止条件
return n
if (n-1) not in cache:
cache[n-1] = fibo(n-1)
if (n-2) not in cache:
cache[n-2] = fibo(n-2)
return cache[n-1] + cache[n-2]
print(fibo(100))
—— 354224848179261915075
【练习】水仙花
# 要求:153 = 1立方 + 5立方 + 3立方
n = int(input('请输入数字:'))
a = n % 10
b = (n % 100-a)//10
c = (n % 1000-(b*10)-a)//100
if (a**3 + b**3 + c**3) == n:
print('{}是个水仙花数'.format(n))
else:
print('{}不是水仙花数'.format(n))
—— 请输入数字:153
153是个水仙花数
请输入数字:100
100不是水仙花数
【自己版】
def flower():
flowers = []
for n in range(100, 10000):
a = n % 10
b = (n % 100 - a) // 10
c = (n % 1000 - (b * 10) - a) // 100
if (a ** 3 + b ** 3 + c ** 3) == n:
# print('{}是个水仙花数'.format(n))
flowers.append(n)
print(flowers)
flower()
—— [153, 370, 371, 407]
【老师版】
flowers = []
def flower():
for i in range(100, 1000):
gewei = i % 10
shiwei = (i // 10) % 10 # 取百位跟十位,然后再取余拿十位数
baiwei = i // 100
if gewei*gewei*gewei + shiwei*shiwei*shiwei + baiwei*baiwei*baiwei == i:
flowers.append(i)
flower()
print(flowers)
—— [153, 370, 371, 407]
【拓展版】
def narcissistic_number_1(num):
length = len(str(num))
count = length
num_sum = 0
while count:
num_sum += ((num//10**(count-1))%10)**length
count -= 1
else:
if num_sum == num:
print('%d is %d bit narcissistic_number' % (num, length))
else:
print('%d is not a narcissistic_number' % num)
narcissistic_number_1(153)
narcissistic_number_1(1634)
narcissistic_number_1(54748)
—— 153 is 3 bit narcissistic_number
1634 is 4 bit narcissistic_number
54748 is 5 bit narcissistic_number