Python函数

       函数,简单地讲就是一段可以重复使用的代码段,给这段代码起个名字就是“函数名”。在程序的任何地方都可以通过函数名来使用这段代码,这就是“函数调用”。

一、定义函数

       1.在Python中可定义一个自己想要功能的函数,以下是简单的规则:

       A、函数代码块以def关键字开头,后接函数名、圆括号()、圆括号中的参数冒号:,然后在缩进块中编写函数体,函数的返回值用return语句返回。

       B、任何传入参数和自变量必须放在圆括号中间,圆括号之间用于定义参数。

       C、(可选)函数第一行语句可以选择性使用文档字符串------用于存放函数说明

       D、return[表达式]结束函数(即函数内部return后面的语句将不再执行),选择性地返回一个值给调用方。不带表达式的return相当于返回None,函数可以返回一个或多个值,多个值以tuple的形式返回。

             返回值作用:后续程序需要根据被调用函数的返回值来执行不同的操作。

       2.语法

       Python中定义函数一般格式如下:

def 函数名(参数列表):
    函数体

       默认情况下,参数值和参数名称是按函数声明中定义的顺序匹配起来的。

       3.实例

# -*- coding:utf-8 -*-
#一元二次方程求根
import math

def quadratic(a,b,c):
    #参数检验,如果传入错误的参数类型,函数可以抛出一个错误
    if not isinstance(a,(int,float)):
        raise TypeError("a is not a number")
    if not isinstance(b,(int,float)):
        raise TypeError("a is not a number")
    if not isinstance(c,(int,float)):
        raise TypeError("a is not a number")

    if a == 0:
        if b == 0:
            if c == 0:
                return "方程根为全体实数"
            else:
                return "方程不成立!"
        else:
            x = -c / b
            return "方程根为x=%s" %x
    else:
        k = b * b - 4 * a * c
        if k >0:
            x1 = (-b + math.sqrt(k)) / (2 * a)
            x2 = (-b - math.sqrt(k)) / (2 * a)
            return "方程根为x1=%s ,x2=%s "%(x1,x2)
        elif k == 0:
            x1 = x2 = (-b + math.sqrt(k)) / (2 * a)
            return "方程根为x1=x2=%s" %x1
        else:
            return "方程无根"

a = float(input("请输入二次项系数a:"))
b = float(input("请输入一次项系数b:"))
c = float(input("请输入常数项c:"))
print(quadratic(a,b,c))

二、函数的参数

       Python函数除了正常定义位置参数外,还可以使用默认参数、可变参数、关键字参数和命名关键字参数,使得函数定义出来的接口不但能处理复杂参数,还可以简化调用者的代码。

       1.位置参数

#位置参数例子,计算x的n次方
def power(x,n):
    s = 1
    while n > 0:
        n -= 1
        s = s * x
    return s

print(power(5,2)) #25

        power(x,n)函数有两个参数:x和n,这两个参数都是位置参数,调用函数时,传入的两个值按照位置顺序依次赋给参数x和n。

       2.默认参数

#默认参数例子,计算x的n次方
def power(x,n=2):
    s = 1
    while n > 0:
        n -= 1
        s = s * x
    return s

print(power(5)) #25
print(power(3,3)) #27

       默认参数可以简化函数调用,设置默认参数时,有几点需要注意:

       ①必选参数在前,默认参数在后,否则Python解释器会报错。

       ②如何设置默认参数?当有多个参数时,把变化大的参数放前面,变化小的参数放后面。变化小的参数就可以作为默认参数。使用默认参数最大好处就是可以降低调用函数的难度。

       ③默认参数必须指向不变对象!

#默认参数示例
def info(id,name,grade=60,gender="M"):
    print("id= ",id)
    print("name= ",name)
    print("grade= ",grade)
    print("gender= ",gender)

info("001","zhangsan") #使用默认参数
info("002","liming",gender="F",grade=90) #不按顺序提供部分默认参数,需要把参数名写上
info(grade=80,id="003",gender="F",name="Tom") #参数顺序打乱,但不影响最终输出结果

       3.可变参数

       顾名思义,可变参数就是传入的参数个数是可变的,可以是0个、1个、2个甚至任意个。举个例子,给定一组数字a、b、c......,要求计算a^2+b^2+c^2+......。要定义这个函数,就需要确定输入的参数,可是参数个数不确定,怎么办?这个时候就用到了可变参数,把函数的参数改为可变参数。

#可变参数示例
def calc(*numbers):
    sum = 0
    for n in numbers:
        sum += n * n
    return sum

print(calc()) #0
print(calc(1,2,3)) #14

       观察上述代码可以发现,仅仅在参数前面加了一个 * 号 。在函数内部,参数numbers接收到的是一个元组,因此函数代码部分完全不用改动。如果已经有一个列表或者元组,要调用一个可变参数怎么做?可以这样:

L = [1,2,3]
calc(L[0],L[1],L[2])

       但是这样感觉太繁琐,有没有简单的写法?python允许在元组或者列表前面加一个 * 号,把列表或元组的元素变为可变参数传进去。 *L表示把L这个列表的所有元素作为可变参数传进去,这种写法很常用。

L = [1,2,3]
calc(*L)

       4.关键字参数

       可变参数允许我们传入0个或任意个参数,这些可变参数在函数调用时自动组装为一个元组。而关键字参数允许我们传入0个或任意个含参数名的参数,这些关键字参数在函数内部自动组装为一个字典

#关键字参数示例
def info (id,name,**kw):
    print('id=',id,'name=',name,'other=',kw)

info("001","zhangsan") #只传入必选参数
#id= 001 name= zhangsan other= {}

info("002","lisi",age=34,gender="M",grade=98) #除必选参数外,传入任意个关键字参数。关键字参数跟默认参数类似有参数位置限制,关键字参数后面必须都是关键字参数
#id= 002 name= lisi other= {'age': 34, 'gender': 'M', 'grade': 98}

       观察上述代码发现info()除了必选参数id,name外,还多了一个关键字参数kw。关键字参数有何作用?它可以扩展函数功能。比如info()函数里,除了可以收到id和name参数外,还可以收到其他可选参数如gender、grade等。如果有一个字典,要调用关键字参数应该怎么做?可以这样:

D = {'age':24,'gender':'F','grade':90}
info("003","Jake",**D)
#id= 003 name= Jake other= {'age': 24, 'gender': 'F', 'grade': 90}

       **D可以把D这个字典的所有key-value用关键字参数传入到**kw参数,kw将获得一个字典。注意kw获得的是D的一份拷贝,对kw的改动不会影响到D本身。

       5.命名关键字参数

       如果要限制关键字参数的名字,就可以使用命名关键字参数。如下示例,除id,name以外只接收city作为关键字参数,代码如下:

#命名关键字参数示例
def info(id,name,*,city):
    print(id,name,city)

#info('001','Mark',gender='M',grade=98,city='xian') #报错,除id,name外只接收city
info('001','Mark',city='xian') #001 Mark xian

        观察上述示例可以发现,和关键字参数**kw不同,命名关键字参数需要一个特殊分隔符 *后面的参数被视为命名关键字参数。如果函数定义中已经有了一个可变参数,后面跟着的命名关键字参数就不再需要一个特殊分隔符 *了:

#已有可变参数示例
def info(id,name,*args,gender,city):
    print(id,name,args,gender,city)

#命名关键字参数必须传入参数名,如果没有传入参数名,调用将会报错
info('002','Jack','IT','student','M','shanghai')#报错

#命名关键字参数传入正确参数名
info('002','Jack','IT','student',gender='M',city='shanghai')#可变参数于位置参数后,否则会报错
#结果: 002 Jack ('IT', 'student') M shanghai

       命名关键字参数可以有默认值,从而简化调用: 

#命名关键字参数取默认值
def info(id,name,*args,gender,city='Shanghai'):
    print(id,name,args,gender,city)

info('002','Jack','IT','student',gender='M')
#002 Jack ('IT', 'student') M Shanghai

注意:① 命名关键字参数必须传入参数名,这和位置参数不同。如果没有传入参数名,调用将报错。

           ②使用命名关键字参数时,要特别注意,如果没有可变参数,就必须加一个*作为特殊分隔符。如果缺少*,Python解释器将无法识别位置参数和命名关键字参数。

       6.参数组合

       在Python中定义函数,可以用必选参数、默认参数、可变参数、关键字参数和命名关键字参数,这5种参数可以组合使用。参数定义的顺序必须是:必选参数、默认参数、可变参数、命名关键字参数和关键字参数。

#参数组合
def f1(a,b,c=0,*args,**kw):
    print('a=',a,'b=',b,'c=',c,'args=',args,'kw=',kw)

def f2(a,b,c=0,*,d,**kw):
    print('a=',a,'b=',b,'c=',c,'d=',d,'kw=',kw)

f1(1,2)#a= 1 b= 2 c= 0 args= () kw= {}
f1(1,2,c=3) #a= 1 b= 2 c= 3 args= () kw= {}
f1(1,2,3,'a','b') #a= 1 b= 2 c= 3 args= ('a', 'b') kw= {}
f1(1,2,3,'a','b',x=100) #a= 1 b= 2 c= 3 args= ('a', 'b') kw= {'x': 100}
f2(1,2,d=99,ext=None) #a= 1 b= 2 c= 0 d= 99 kw= {'ext': None}


#对于任意函数,都可以通过类似func(*args,**kw)形式调用,无论其参数是如何定义的
L = (1,2,3,4)
s = (1,2,3)
D = {'d':99,'x':'y'}
f1(*L,**D) #a= 1 b= 2 c= 3 args= (4,) kw= {'d': 99, 'x': 'y'}
f2(*s,**D) #a= 1 b= 2 c= 3 d= 99 kw= {'x': 'y'}

       参数总结:

       ①默认参数一定要用不可变对象,如果是可变对象,程序运行时会有逻辑错误

       ②注意可变参数和关键字参数的语法:*args是可变参数,args接收的是一个元组**kw是关键字参数,kw接收的是一个字典

       ③调用函数时如何传入可变参数和关键字参数语法:

               a、可变参数既可以直接传入:func(1,2,3),又可以先组装list或tuple,再通过*args传入:func(*(1,2,3));

               b、关键字参数既可以直接传入:func(a=1,b=1),又可以先组装dict,再通过**kw传入:func(**{'a':1,'b':2})。

       ④使用*args和**kw是Python的习惯用法,最好使用习惯用法。

       ⑤命名关键字参数是为了限制调用者可以传入的参数名,同时可以提供默认值。

       ⑥定义命名关键字参数在没有可变参数情况下不要忘了写分隔符*,否则定义的将是位置参数。

       ⑦必选参数、默认参数、可变参数、命名关键字参数和关键字参数可以组合使用,参数定义顺序为必选参数-->默认参数-->可变参数-->命名关键字参数-->关键字参数

三、递归函数

#递归求n阶乘
def fact(n):
    if n == 1: #跳出递归条件
        return 1
    return n * fact(n-1)

print(fact(1)) #1
print(fact(5)) #120
#汉诺塔
'''
move(n,a,b,c)各个参数含义:n表a,b,c三个柱子中第一个柱子a上面盘子数量,然后打印所有盘子从a借助b移动到c的方法.
思路:move(n,起点,缓冲区,终点),先把n-1个盘子搬到缓冲区move(n-1,a,c,b),然后把最底下那个大盘子搬到终点move(1,a,b,c),
最后缓冲区变为起点,起点变为缓冲区,其余的盘子搬到终点move(n-1,b,a,c)
'''
def move(n,a,b,c):
    if n == 1:
        print(a,'-->',c)
    else:
        move(n-1,a,c,b)
        move(1,a,b,c)
        move(n-1,b,a,c)

move(1,'A','B','C') #A --> C
move(2,'A','B','C') #A --> B,A --> C,B --> C
move(3,'A','B','C') #A --> C,A --> B,C --> B,A --> C,B --> A,B --> C,A --> C

       递归优点:定义简单,逻辑清晰。缺点:过深调用导致栈溢出,解决递归调用栈溢出方法是通过尾递归优化。

       递归特性:

                   A:必须有一个明确的结束条件

                   B:每次进入更深一层递归时,问题规模相比上次递归都应有所减少。

                   C:递归效率不高,递归层次过多会导致栈溢出。

四、匿名函数

       Python使用lambda来创建匿名函数。匿名,即不再使用def这样的标准形式定义函数。

       A、lambda只是一个表达式,函数体比def简单的多,不用写return,返回值就是该表达式的结果。

       B、lambda的主体是一个表达式,而不是一个代码块。仅仅能在lambda表达式中封装有限逻辑。

       C、lambda函数拥有自己的命名空间,且不能访问自己参数列表之外或全局命名空间里的参数。

       D、虽然lambda函数看起来只有一行,却不等同于C或C++的内联函数。

       语法

       lambda函数的语法只包含一个语句,格式如下,其中冒号前面[arg1 [,arg2,.....argn]]表示函数参数。

lambda [arg1 [,arg2,.....argn]]:expression
#匿名函数
sum = lambda x,y:x + y
print("两数相加和为:",sum(1,2)) #两数相加和为: 3

五、变量作用域

       变量作用域决定了在哪一部分程序可以访问哪个特定的变量名称。Python作用域一共有4种,分别是:

       L (Local) 局部作用域

       E (Enclosing) 闭包函数外的函数中

       G (Global) 全局作用域

       B (Built-in) 内置作用域(内置函数所在模块的范围)

       以 L –> E –> G –>B 的规则查找,即:在局部找不到,便会去局部外的局部找(例如闭包),再找不到就会去全局找,再者去内置中找。内置作用域是通过一个名为builtin的标准模块实现的,但是这个变量名自身没有放入内置作用域内,所以必须导入这个文件才能使用它import builtins.

g_count = 0 #全局作用域
def outer():
    o_count = 1 #闭包函数外的函数中
    def inner():
        i_count = 2 #局部作用域

       1.全局变量和局部变量

       定义在函数内部的变量拥有一个局部作用域,定义在函数外部的拥有全局作用域。局部变量只能在其被声明的函数内部访问,而全局变量可以在整个程序范围内访问。

#局部变量与全局变量
total = 0 #全局变量
def sum(x,y):
    total = x + y #total为局部变量
    print("这里是函数内部局部变量:",total)
    return total

sum(10,20) #这里是函数内部局部变量: 30
print("这里是函数外部全局变量:",total) #这里是函数外部全局变量: 0

        2.global和nonlocal关键字

       当内部作用域想修改外部作用域时,就要用到globalnonlocal关键字了。

#修改全局变量--global
num = 1
def fun1():
    global num #global关键字声明,否则打印num会报错
    print(num)
    num = 10
    print(num)

fun1() #1,10
print(num) #10
#修改嵌套作用域(enclosing作用域,外层非全局作用域)中的变量--nonlocal
def outer():
    num  = 1
    def inner():
        nonlocal num #nonlocal关键字
        print(num) #1
        num = 10
        print(num) #10
    inner()
    print(num) #10

outer()

 

 

 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值