"""
函数的概念:
S = πr²,当我们知道半径r的值时,就可以通过公式计算出面积,假设我们需要计算3个不同大小的圆的面积:
出现了几乎完全重复的代码,每次计算圆的面积的时候我们都是通过3.14*x*x(其中x是圆的半径)的方式计算出来的,这样写不仅非常麻烦,
而且,当我们需要提高圆周率的精度时,把3.14改成3.14159265359的时候,我们需要修改涉及到的三行代码。
我们可以使用函数,把重复的逻辑代码封装起来,这样子,我们就不需要每次计算的时候,都写3.14*x*x这样的代码了;
当我们使用函数的时候,我们只需要定义一次,就可以多次使用。
我们把封装重复逻辑代码的过程就做抽象,抽象是数学中非常常见的概念。
"""
r1 = 12.34
r2 = 9.08
r3 = 73.1
s1 = 3.14 * r1 * r1
s2 = 3.14 * r2 * r2
s3 = 3.14 * r3 * r3
print(s1, s2, s3)
# 用函数写
def area(r):
s = 3.14 * r * r
print(s)
area(12.34)
area(9.08)
area(73.1)
"""
部分内置函数:abs() int() str()
"""
print(abs(-100)) # 100,绝对值函数
# print(abs(-100, 2))
# print(abs('122'))
print(int('123'))
print(str(123))
"""
练习:
sum()函数接收一个list作为参数,并返回list所有元素之和。请计算 1*1 + 2*2 + 3*3 + ... + 100*100。
"""
L = []
x = 1
while x <= 100:
L.append(x * x)
x += 1
print(sum(L))
# 重写abs函数
def my_abs(x):
if x >= 0:
return x
else:
return -x
print(my_abs(-1.5))
# 定义一个list_sum函数
def list_sum(L):
result = 0
for i in L:
result += i
return result
res = list_sum([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
print(res) # 55
"""
在上述的案例中,使用return返回了计算的结果,在外部调用这个函数的时候,就可以接收到结果。
有时候函数是没有返回结果的,这个时候从函数获取到的是一个空值None。
我们对list_sum()这个函数进行简单的修改,在函数内把结果打印出来,不通过return返回结果。
"""
def list_sum(l):
result = 0
for i in l:
result += i
print('result is {}'.format(result))
return
l = [1, 3, 5, 7, 9, 11]
result = list_sum(l)
print(result) # None
"""
定义一个函数data_of_square,接收边长一个参数,同时返回正方形的周长和面积
"""
def data_of_square(side):
c = 4 * side
s = side * side
return c, s
c, s = data_of_square(3)
print('正方形的周长:{}'.format(c))
print('正方形的面积:%d' % s)
"""
正方形的周长:12
正方形的面积:9
"""
result = data_of_square(3) # (12, 9),结果值是tuple,可通过下标取值
c = result[0]
s = result[1]
print(c, s)
"""
定义一个函数sub_sum(),这个函数接收一个列表作为参数,函数返回列表所有奇数项的和以及所有偶数项的和
"""
def sub_sum(L):
odd_number = 0
even_number = 0
for i in L:
if i % 2 != 0:
odd_number += i
else:
even_number += i
return odd_number, even_number
L = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
result = sub_sum(L)
print('奇数项之和为:{}'.format(result[0])) # 30 25
print('偶数项之和为:{}'.format(result[1])) # 30 25
"""
函数内容调用其他函数:
在函数内部调用其他函数,是非常常见的,通过合理拆分逻辑,可以降低程序的复杂度。
根据上例:由于面积和周长是完全独立的逻辑,所以可定义为两个函数,然后在data_of_square函数中再调用这两个函数,得到结果并返回。
"""
def square_perimeter(side):
c = 4 * side
return c
def square_area(side):
s = side * side
return s
def data_of_square(side):
c = square_perimeter(side)
s = square_area(side)
return c, s
res = data_of_square(3)
print('正方形的周长:{}'.format(res[0]))
print('正方形的面积:%d' % res[1])
"""
递归函数:如果在一个函数内部调用其自身,这个函数就是递归函数。
使用递归函数需要注意防止栈溢出。在计算机中,函数调用是通过栈(stack)这种数据结构实现的,每当进入一个函数调用,栈就会加一层栈帧,
每当函数返回,栈就会减一层栈帧。由于栈的大小不是无限的,所以,递归调用的次数过多,会导致栈溢出。python的递归深度限制为1000
计算阶乘 n! = 1 * 2 * 3 * ... * n,用函数 fact(n)表示
fact(n) = n! = 1 * 2 * 3 * ... * (n-1) * n = (n-1)! * n = fact(n-1) * n
所以,fact(n)可以表示为 n * fact(n-1),只有n=1时需要特殊处理
fact(4)可拆分为:
= 4 * fact(3)
= 4 * 3 * fact(2)
= 4 * 3 * 2 * fact(1)
"""
def fact(n):
if n == 1:
return 1 # 满意n==1的条件,return之后,后面的代码就不执行了
return fact(n - 1) * n
print(fact(1))
print(fact(4))
# print(fact(1000)) # RecursionError: maximum recursion depth exceeded in comparison
"""
打印结果:
1
24
"""
"""
练习:
请分别使用循环和递归的形式定义函数,求出1~100的和
"""
# 循环
def my_sumA(n):
sum1 = 0
index = 1
while index <= n:
sum1 += index
index += 1
return sum1
print(my_sumA(100))
# 递归
# f(99) + 100
# f(98) + 99 + 100
def my_sumB(n):
if n == 1:
sum1 = n
else:
sum1 = my_sumB(n - 1) + n
return sum1
print(my_sumB(100))
"""
函数参数
"""
def print_param(param):
print(param)
print_param(123)
print_param(123.4567)
print_param('123')
print_param([1, 2, 3, 4])
"""
参数类型不匹配:
为保证函数正常运行,需对入参进行判断。isinstance()函数,可以判断参数类型,它接收两个参数,第一个是需要判断的参数,第二个是类型
"""
def my_abs(x):
if x >= 0:
return x
else:
return -x
# print(my_abs('123')) # TypeError: '>=' not supported between instances of 'str' and 'int'
print(isinstance(123, int))
print(isinstance('123', int))
print(isinstance('123', str))
print(isinstance([1, 2], list))
"""
打印结果:
True
False
True
True
"""
# 对上述函数进行修改
def my_abs_A(x):
if isinstance(x, int) or isinstance(x, float):
if x >= 0:
return x
else:
return -x
else:
print('param TypeError,传参有误')
return None
print(my_abs_A(0))
print(my_abs_A(-123))
print(my_abs_A(123.4567))
print(my_abs_A('123'))
print(my_abs_A([1, 2]))
"""
打印结果:
0
123
123.4567
param TypeError,传参有误
None
param TypeError,传参有误
None
"""
"""
函数默认参数:默认参数的意思是当这个参数没有传递的时候,参数就使用定义时的默认值
注意:1、由于函数的参数按从左到右的顺序匹配,所以默认参数只能定义在必需参数的后面,否则将会出现错误。
2、如果一个函数的参数中含有默认参数,则这个默认参数后的所有参数都必须是默认参数,否则会报错。
int():只传一个参数时,默认是转换为10进制的整数。当传两个参数时,就是指定转换的进制。
"""
print(int('123')) # 123
print(int('123', 8)) # 83,将123转换为8进制数
# 定义一个计算 x 的N次方的函数:x*x*x
def power(x, n):
s = 1
while n > 0:
n = n - 1
s = s * x
return s
print(power(2, 2)) # 4
# 假设最多计算平方的次数,我们就可以把 n 的默认值设定为 2:
def powerA(x, n=2):
s = 1
while n > 0:
s *= x
n -= 1
return s
print(powerA(3)) # 9,当计算平方时,就只用传一个参数
print(powerA(3, 3)) # 27
# 如果一个函数的参数中含有默认参数,则这个默认参数后的所有参数都必须是默认参数,否则会报错
# def powerA(x=2, n): # SyntaxError: non-default argument follows default argument
# s = 1
# while n > 0:
# s *= x
# n -= 1
# return s
#
# print(powerA(3))
"""
练习:
请定义一个 greet() 函数,它包含一个默认参数,如果没有传入参数,打印 Hello, world.,如果传入参数,打印Hello, 传入的参数内容.
"""
def greet(a='world'):
print('Hello, {}.'.format(a))
print('Hello, ' + a + '.')
greet()
greet('python')
"""
打印结果:
Hello, world.
Hello, world.
Hello, python.
Hello, python.
"""
"""
可变参数:*args
在使用上,Python会把可变参数定义为一个tuple,所以在函数内部,把可变参数当作tuple来使用就可以了,比如可以通过位置下标取出对应的元素等。
定义可变参数的目的也是为了简化调用
"""
def func(*args):
print('args length = {}, args = {}'.format(len(args), args))
func('a') # 可变函数返回值的类型为tuple
func('a', 'b')
func(12, 'b', [1, 2, 3])
# 计算任意个数的平均值,就可以定义一个可变参数
def average(*args):
sum_total = 0
for i in args:
sum_total += i
avg1 = sum_total / len(args)
return avg1
print(average(1, 2, 3, 4, 5, 6))
# print(average()) # ZeroDivisionError: division by zero, 可变参数的长度可能是0,当长度为0的时候,就会出现除0错误
# 处理可变参数为空的情况
def averageA(*args):
sum_total = 0
if len(args) == 0:
return sum_total
else:
for i in args:
sum_total += i
avg1 = sum_total / len(args)
return avg1
# averageA的基础上简化代码
def averageB(*args):
sum_total = 0
if len(args) == 0:
return sum_total # 满足该条件return结果后,后面的代码就不再执行
for i in args:
sum_total += i
avg1 = sum_total / len(args)
return avg1
print(averageA()) # 0
print(averageB()) # 0
"""
可变关键字参数:**kwargs
Python会把可变关键字参数当作dict去处理
"""
# 想要打印一个同学的信息
def info(**kwargs):
print('name: {}, gender: {}, age: {}' .format(kwargs.get('name'), kwargs.get('gender'), kwargs.get('age')))
info(name='zoey', gender='female', age=27)
# name: zoey, gender: female, age: 27
"""
对于一个拥有必需参数,默认参数,可变参数,可变关键字参数的函数,定义顺序是这样的:
当然,这么多类型的参数,很容易导致出错,在实际使用上,不建议定义这么多的参数
"""
def func(param1, param2, param3=None, *args, **kwargs):
print(param1)
print(param2)
print(param3)
print(args)
print(kwargs)
func(100, 200, 300, 400, 500, name='zoey', score=100)
"""
打印结果:
100
200
300
(400, 500)
{'name': 'zoey', 'score': 100}
"""
"""
练习:
编写一个函数,它接受关键字参数names,gender,age三个list,分别包含同学的名字、性别和年龄,
请分别把每个同学的名字、性别和年龄打印出来
"""
def c_info(**kwargs):
names = kwargs['names']
# print(names) # ['zoey', 'cibo', 'yancy']
genders = kwargs['gender']
ages = kwargs['ages']
index = 0
for name in names:
gender = genders[index]
age = ages[index]
index += 1
print('name:{}, gender:{}, age:{}' .format(name, gender, age))
c_info(names=['zoey','cibo', 'yancy'], gender=['female', 'male', 'male'], ages=[18, 19, 20])