python

关注公众号 jb51net

关闭
首页 > 脚本专栏 > python > python函数

python的函数最详解

作者:Zincy星辰

这篇文章主要介绍了详解python中各种的函数,是Python入门中的基础知识,需要的朋友可以参考下,希望能够给你带来帮助

一、函数入门

1.概念

2.定义函数的语法格式

def 函数名(形参列表):
    #可执行语句
    return 返回值

函数名

形参列表

返回值

3.函数的文档(注释→help)

4.举例

# 函数定义
def myfunc(arg1, arg2, arg3=None):
    ''' 
    This is a example for python documentation.
    这是一个为python函数提供文档的例子。
    arg1: 第一个参数的说明
    arg2: 第二个参数的说明
    arg3: 第三个参数的说明(这个参数有默认值)
    v1, v2, v3: 返回值的说明 
    '''
    v1 = arg1 + arg2
    v2 = arg1 * arg2
    if arg3 is None:
        v3 = arg1 + arg2
    else:
        v3 = arg1 + arg2 + arg3
    return v1, v2, v3
# 函数调用
v1, v2, v3 = myfunc(5, 3, arg3=4)
print(v1, v2, v3)    #8 15 12
# 使用arg3的默认值调用函数
v1, v2, v3 = myfunc(5, 3)
print(v1, v2, v3)    #8 15 8
# 忽略一个返回值
v1, v2, _ = myfunc(5, 3)
print(v1, v2, v3)    #8 15 8
# 看看返回值是元组tuple,在返回的过程中被自动解包
print(type(myfunc(5,3)))    #<class 'tuple'>

二、函数的参数

#举一个小栗子,计算纸箱子的体积
def cube_volume(length, width, height = 0.25):
    '''
    计算纸箱子的体积(单位:m)
    length: 长;    width: 宽
    height: 高(默认参数0.25)
    v: 返回值,纸箱的体积,单位m**3
    '''
    if length <= 0:
        print('length must larger than 0!')
        return 0
    if width <= 0:
        print('width must larger than 0!')
        return 0
    if height <= 0:
        print('height must larger than 0!')
        return 0
    v = length*width*height
    print('length = %.2f; width = %.2f; height = %.2f; cube volume = %.2f' % \
          (length, width, height, v))
    return v
# 使用位置参数调用
v = cube_volume(1, 2, 3)
# 使用关键字参数调用
v = cube_volume(width = 1, height = 2, length = 3)
# 位置参数和关键字参数混用
v = cube_volume(1, height = 2, width = 3)
# 关键字参数在位置参数之前会报错
# v = cube_volume(width = 1, 2, 3)

1.可变对象

# 对列表的乘方运算
def pow_list(x, p):
    '''
    power of a list
    x: list
    p: power
    not return value
    '''
    for i in range(len(x)):
        x[i] **= p
    #这样会输出乘方后的值,但不会改变x列表里的值
    #因为在计算时将x中的值传入了新的参数进行计算
    #for i in x:
    #    i **= p
    #    print(i)
    #print(x)
x = [1,2,3,5,7,9,10,12]
pow_list(x,2)
print(x)
# 可见函数内部对列表x中元素的更改,当函数退出之后依然有效

利用可变对象的特点,可以制作一种隐藏的参数记录器

# 隐藏的参数记录器
def growing_list(x, y=[]):
    y.append(x)
    print(y)
# 重复执行growing_list(‘a')会发生什么结果?
growing_list(2)         #[2]
growing_list('张三')    #[2, '张三']
growing_list(22333)     #[2, '张三', 22333]

2.参数收集(不定个数的参数)

# 不定个数的数字求和
def my_sum(*t):
    # 带星号的输入参数被当作元组处理
    print(t, type(t))
    sum = 0
    for s in t:
        sum += s
    return sum
# 事实上该函数接受了不定个数的输入参数
my_sum(1,2,3,4,2233)

如果带星参数后面还有别的参数,则它们必须要用关键字参数的方式传递,否则python不知道它们到底是啥,都会给收集到带星参数里。

# 不定个数的数字乘方后求和
def pow_sum(*t, p):
    # 带星号的输入参数被当作元组处理
    print(t, type(t))
    sum = 0
    for s in t:
        sum += s**p
    return sum
# 最后一个参数p,需要指定关键字传递
pow_sum(1,2,3,4,2233,p=2)
# 如果不指定关键字传递呢?会报错
# pow_sum(1,2,3,4,2233,2)

3.解决一个实际问题

# 不定个数的数字加权求和
# 权重随着数字的个数而发生变化
def weighted_sum(x1,x2,*y):
    sum = 0
    n = len(y)
    weight = 1/3/n
    for i in y:
        sum += weight*i
    return sum+1/3*x1+1/3*x2
weighted_sum(1,2,3)
weighted_sum(1,2,3,22,44,55)
weighted_sum(1,2,3,4,5,6)

4.参数收集(收集关键字参数)

# 测试一星参数和两星参数
def test_star(a, b, c, *onestar, **twostar):
    print('a = %d; b = %d; c = %d' % (a, b, c))
    print(onestar, type(onestar))
    print(twostar, type(twostar))
test_star(1, 2, 3, 4, 5, 6, s1 = 7, s2 = 8, s3 = 9)
# 换个顺序呢?
# test_star(1, 2, 3, 4, 5, 6, s1 = 7, s2 = 8, s3 = 9, a = 10, b = 11, c = 12)
# 报错了,二星参数后面不能再传递关键字参数了(当然位置参数也不行)

“参数收集”功能,会让带星参数尽量少的收集,把更多参数留给正常的位置参数和关键字参数

# 如果有默认参数,要注意可能引起的bug
def test_star(a, b, c, p = 5, *onestar, **twostar):
    print('a = %d; b = %d; c = %d; p = %d' % (a, b, c, p))    #a = 1; b = 2; c = 3; p = 4
    print(onestar, type(onestar))            #(5, 6) <class 'tuple'>
    print(twostar, type(twostar))            #{'s1': 7, 's2': 8, 's3': 9} <class 'dict'>
# 会传递一个p=4进去,而不是设想的,onestar=(4,5,6)
test_star(1, 2, 3, 4, 5, 6, s1 = 7, s2 = 8, s3 = 9)

5.逆向参数收集(炸开参数)

# 炸参数例子
def zha(a,b,c):
    print(a,b,c)
# 炸元组
z = (1,2,3)            #1 2 3
zha(*z)
# 炸列表
z = [4,5,6]            #4 5 6
zha(*z)
# 炸字典
z = {'a':7,'b':8,'c':9}    #7 8 9
zha(**z)
# 炸字典
z = {'c':7,'a':8,'b':9}    #8 9 7
zha(**z)
# 如果炸开后参数个数或Key不匹配,会报错
# z = {'c':7,'a':8}
# zha(**z)

6.参数的内存管理

# 传递数值类型参数
# 在函数内修改,在函数外面不受影响
def mod_para1(a,b):
    print('In mod_para1, before modification: a = %d; b = %d' % (a,b))    #a = 2; b = 8
    a *= 2
    b += 4
    print('In mod_para1, after modification: a = %d; b = %d' % (a,b))    #a = 4; b = 12
a = 2
b = 8
print('Out of mod_para1, before modification: a = %d; b = %d' % (a,b))    #a = 2; b = 8
mod_para1(a,b)
print('Out of mod_para1, after modification: a = %d; b = %d' % (a,b))    #a = 2; b = 8
# 列表通过函数传参时,被改动了数据
def mod_para2(x):
    print('In mod_para2, before modification: x = ' + str(x))
    for i in range(len(x)):
        x[i] *= 2
    print('In mod_para2, after modification: x = ' + str(x))
x = [i for i in range(10)]
print('Out of mod_para2, before modification: x = ' + str(x))
mod_para2(x)
print('Out of mod_para2, after modification: x = ' + str(x))
import copy
A = [1,2,3]; B = copy.copy(A)
mod_para2(B); print(A,B)

7.函数中变量的作用域

gv1 = 1
def test():
    # gv1=2
    print('在函数内部访问全局变量:gv1 = %d' % gv1)    #1
    # gv1=2
test()
print('在函数外部访问全局变量:gv1 = %d' % gv1)    #1
# 访问被遮蔽的全局变量
gv1 = 1
def test():
    # 用globals函数访问被遮蔽的全局变量
    print('在函数内部访问全局变量:gv1 = %d' % globals()['gv1'])
    gv1 = 2 
    print('在函数内部访问修改后的全局变量:gv1 = %d' % gv1)
test()
print('在函数外部访问全局变量:gv1 = %d' % gv1) # 函数内部修改的其实是同名局部变量,全局变量没有被修改。
# 测试全局变量
gv1 = 1
def test():
    global gv1 #全局变量我来撑控
    print('在函数内部访问全局变量:gv1 = %d' % gv1)    #1
    gv1+=1
test()
print('在函数外部访问全局变量:gv1 = %d' % gv1)    #2

8.获取指定范围内的变量

三、局部函数(函数的嵌套)

一个栗子(利用局部函数实现多种平均值的切换)

# 利用局部函数实现多种平均值的切换
def mymean(x, mtype = 'arithmetic'):
    '''计算列表x的平均值,用mtype定义计算哪种平均值,默认为算术平均值(arithmetic mean)    '''
    def arithmetic(x): 
        ''' 算术平均值(arithmetic mean)  '''
        m = sum(x)/len(x);    return m
    def geometric(x): 
        '''几何平均值(geometric mean) '''
        p = 1.;  n = len(x)
        for i in range(n):      p *= x[i]
        m = p ** (1/n);       return m
    def harmonic(x): 
        ''' 调和平均值(harmonic mean) '''
        s = 0.;      n = len(x)
        for i in range(n):        s += 1/x[i]
        m = 1/(s/n);        return m
    if mtype == 'arithmetic':    return arithmetic
    elif mtype == 'geometric':    return geometric
    elif mtype == 'harmonic':     return harmonic
    else:        return arithmetic
# 局部函数内的变量与函数内的局部变量相冲突,这个程序会报错
def test1():
    fv = 1
    def test2():
        # print('局部函数内打印上层函数中的局部变量:%d' % fv) # 会在这里报错
        fv = 2
        print('局部函数内打印上层函数中的局部变量(更改后):%d' % fv)    #2        
    test2()
    print('上层函数内打印局部变量(更改后):%d' % fv)    #1        
    return fv
print('上层函数外打印局部变量(更改后):%d' % test1())    #1

用nolocal声明的方式可以使用/更改全局变量

# 局部函数内的变量与函数内的局部变量相冲突,应该改成这样就不报错了
def test1():
    fv = 1
    def test2():
        nonlocal fv # 用nonlocal声明,把fv声明为上一层函数的变量
        print('局部函数内打印上层函数中的局部变量:%d' % fv)    #1
        fv = 2
        print('局部函数内打印上层函数中的局部变量(更改后):%d' % fv)    #2    
    test2()
    print('上层函数内打印局部变量(更改后):%d' % fv)    #2
    return fv
print('上层函数外打印局部变量(更改后):%d' % test1())    #2

四、函数的高级内容

# 以第三章栗子中mymean函数为例
# 将函数赋值给变量f
f = mymean2('arithmetic')
# 打印出来看看
print(f)
# 测试一下
x = list(range(1,10))
m = f(x)
print(m)
# 也可以像上面的例子一样,连起来写
print(mymean2('geometric')(x))

1.函数作为函数的形参

2.使用函数作为返回值

# 以第三章栗子中mymean函数为例
# 编写另一个程序,对列表中的数字进行变换,变成均值为1的另一个列表
# 均值,可以是算术平均值、几何平均值、调和平均值
def mynormalize(x, mtype):
    f = mymean(mtype)
    m = f(x)
    return [i/m for i in x]
x = list(range(1,10))
mtype = 'geometric'
print(mymean(mtype)(x))
print(mynormalize(x, mtype))

3.递归

# 斐波那契数列(Fibonacci sequence)
# 在现代物理、准晶体结构、化学等领域,斐波纳契数列都有直接的应用
def Fibonacci(n):
    '''    Fibonacci sequence
    f(0)=1, f(1) = 1, f(n) = f(n-1)+f(n-2)    '''
    if n == 0 or n == 1:        return 1
    else:      return Fibonacci(n-1) + Fibonacci(n-2)
# 测试一下,注意n不要设的太大,python的递归效率是比较低的,太大会死机
print(Fibonacci(5))
# 斐波那契数列,前20位
print('Fibonacci sequence:')
for i in range(20):
    print('%d: %d' % (i,Fibonacci(i)))

五、局部函数与lambda

# 一行中的hello world
greeting = lambda: print('Hello lambda!')
greeting()
# lambda表达式可以放在数组里面,批量运行
L = [lambda x: x**2, lambda x: x**3, lambda x: x**4]
for p in L:
    print(p(3))

1.用lambda表达式代替局部函数

# 用lambda表达式代替局部函数
def mymean2(mtype = 'arithmetic'):
    '''    返回计算平均值所用的函数,用mtype定义计算哪种平均值,默认为算术平均值(arithmetic mean)    '''
    # 由于lambda表达式只能写一行,这里用numpy和scipy的现成的函数来实现
    import numpy as np
    import scipy.stats as st
    a = np.array(x)
    if mtype == 'arithmetic': # 算术平均值(arithmetic mean)
        return lambda a: np.mean(a)
    elif mtype == 'geometric':# 几何平均值(geometric mean)
        return lambda a: st.gmean(a)
    elif mtype == 'harmonic': # 调和平均值(harmonic mean)
        return lambda a: st.hmean(a)
    else:        # 默认:算术平均值(arithmetic mean)
        return lambda a: np.mean(a)
x = list(range(1,10))
print(x)
print(mymean2('arithmetic')(x))
print(mymean2('geometric')(x))
print(mymean2('harmonic')(x))

2.常见数学方法的内部函数

# 判断所有元素是否为True,相当于多重的and
help(all)
print(all([3>2,6<9]))
# 任意一个元素是否为True,相当于多重的or
help(any)
print(any([3>2,6<9]))
# 最大值和最小值
help(max)
help(min)
print(max([1,2,5,3]))
print(min([1,2,5,3]))
# 四舍五入(到小数点后第n位)
help(round)
print(round(3.1415926,3))
# 所有元素相加 
help(sum)
print(sum([1,2,3]))
print(sum([1,2,3],5))
# 乘幂
help(pow)
print(pow(6,2))
print(pow(6,2,5))
# 带余除法
help(divmod)
print(divmod(6,2))
# 绝对值
help(abs)
print(abs(-2.56))

总结

本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注脚本之家的更多内容!

您可能感兴趣的文章:
阅读全文