详解Python的函数与异常

目录
  • 1. 函数
    • 1.1 自定义函数
    • 1.2 函数与参数
    • 1.3 函数与返回值
  • 2. 异常处理
    • 2.1 raise 语句
    • 2.2 异常捕获
    • 2.3 finally 子句
  • 总结

1. 函数

抽象是程序能够被人理解的关键所在。程序应非常抽象,如获取用户输入构造列表,查找列表中最大的值,并进行打印:

list_a = get_input()
max_value = max(list_a)
print(max_value)

看到这些代码,可以很容易这个程序是做什么的,至于这些操作的具体细节,将在独立的函数中给出。

虽然我们并没有具体讲解过函数定义,但是我们已经使用过Python 的内置函数 print,input 等。函数可用于减少代码重复,并使程序更易于理解和维护。可以将函数理解为一个“子程序”:函数本质上是一个命名语句序列,可以通过引用函数名称,在程序中的任何位置执行这些指令。创建函数的代码称为“函数定义”,当函数在程序中使用时,称为函数被“调用”。

1.1 自定义函数

通过定义函数可以隐藏计算细节,函数定义需要一个函数名、一系列参数(也可以不使用参数)以及一个函数体,函数也可以显式地返回一个值,函数定义的一般形式如下所示:

def name_of_function(paramters):
    body_of_function

例如编写一个求圆面积的函数:

def area_of_circle(radius):
    area = 3.14 * radius ** 2
    return area

在这个函数定义中,def 是告诉 Python 要定义一个函数,函数名(这里为 area_of_circle )用于函数后续的调用,函数名后的括号里是函数的形式参数列表。在这个函数中,radius 是唯一的形式参数,函数体可以是任何一段 Python 代码,return 语句用于调用函数时返回一个值,只能用于函数体中,执行 return 语句会结束对函数的调用。如果要调用 area_of_circle 函数,需要为其提供一个实际参数值,函数调用是一个表达式,表达式的值就是调用函数返回的值:

>>> area_of_circle(10)
314.0
>>> area = area_of_circle(10)
>>> print(area)
314.0

函数被调用时,将执行以下过程:

1.调用程序在函数调用点暂停执行

2.函数形参获得实参提供的值

3.执行函数体中的代码,直至遇到 return 语句,return 后面的表达式的值作为函数调用的值;或者直到函数体中没有语句可以继续执行,这时函数返回的值为 None;

4.如果 return 后面没有表达式,返回的值也为 None返回到函数被调用的点执行之后的代码

我们已经知道,函数也可以不包含参数或返回值,例如以下简单的函数示例:

def hello_world():
    for i in range(3):
        print('Hello World!')

调用此函数,将打印三行 ‘Hello World!',且函数的返回值为 None:

>>> value = hello_world()
Hello World!
Hello World!
Hello World!
>>> print(value)
None

1.2 函数与参数

编写函数时,常常需要多个参数,那么不同参数是如何赋值的呢?在 Python 中,有两种方法可以将形参绑定到实参。最常用的方法是使用位置参数,即第一个形参绑定到第一个实参,第二个形参绑定到第二个实参,以此类推;第二种方法是关键字参数,即形参根据名称绑定到实参:

def inforname(name, sex, address):
    print("My name is {}, my gender is {}, and my home address is {}.".format(name, sex, address))

以下几种函数调用方式是等价的,其中第一种方式为位置参数,其他方法为关键字参数

inforname('panxiaohui', 'male', 'henan')
inforname('panxiaohui', address = 'henan', sex = 'male')
inforname('panxiaohui', 'male', address = 'henan')
inforname(address = 'henan', sex = 'male', name = 'panxiaohui')

关键字参数可以放在位置参数后,但位置参数不能放在关键字参数后:

>>> inforname('panxiaohui', sex = 'male', 'henan')
  File "<stdin>", line 1
    inforname('panxiaohui', sex = 'male', 'henan')
                                                 ^
SyntaxError: positional argument follows keyword argument

前面我们在介绍 print 函数时,提到过可以使用可选参数 end 来改变 print 函数默认换行的行为,可选参数是带有默认值的参数,通常和关键字参数结合使用,在函数调用时可以不为其赋值(此时将使用默认值),而不带有默认值的参数,在函数调用时则必须为其指定参数值。

首先编写以下函数:

def special_number(start, end, step=1):
    list_value = []
    for i in range(start, end, step):
        list_value.append(i)
    return list_value

执行函数调用:

>>> special_number(2,10)
[2, 3, 4, 5, 6, 7, 8, 9]
>>> special_number(2,10, step=2)
[2, 4, 6, 8]
>>> special_number(2)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: special_number() missing 1 required positional argument: 'end'

1.3 函数与返回值

返回值是从函数发送信息到调用函数的程序部分的主要方式,函数还可以通过更改函数参数来与调用程序通信,这需要理解函数调用中使用的实参和形参之间的关系。

在函数中,尽管实参和形参的名称是一样的,但它们并不是同一个变量。每个函数都定义了一个命名空间,也称为作用域,每次函数调用都将创建一个新的作用域:

def exponentiation(number, power):
    power = power * 2
    result = number ** power
    number = result
def test_exponentiation():
    n = 2
    power = 5
    exponentiation(n, power)
    print(n, power)

调用函数,可以直观的看出作用域的含义:

>>> test_exponentiation()
2 5

在函数内使用的变量称为局部变量(与之相对的是全局变量)。test_exponentiation() 函数的前两行创建了名为 original  power 的两个局部变量,它们的值分别为 2 和 5。 然后调用了 exponentiation() 函数。形参 number 和 power 被赋值为来自实参 original 和 power 的值。需要牢记一点,即使实参和形参的名称都为 power,它们也是两个独立的变量,参数的赋值使 test_exponentiation() 函数中的变量 original 和 power 引用了实参的“值”:

执行 exponentiation() 首先为其局部变量 power 赋一个新值,并创建一个新变量 result。然后,exponentiation() 为 number 赋值,让它具有与 result 相同的值。虽然,现在 number  result 指向相同的值、并且修改了 exponentiation()函数中 power 变量,但这对 test_exponentiation() 函数中的变量 original 和 power 没有影响:

exponentiation() 执行完成后,控制返回到 test_exponentiation()exponentiation() 中的局部变量被回收,test_exponentiation() 函数中的 original 和 power 仍分别指初始值。

综上,Python 中函数的形参只接收实参的“值”,函数不能访问保存实参的变量。因此,为形参分配新值对实参变量没有影响,这是由于 Python “按值”传递所有参数。一些编程语言(如 C++ )允许变量本身作为参数传递给函数,这种机制称为“按引用”传递参数。当变量按引用传递时,向形参分配新值实际上会更改调用程序中的参数变量的值。

由于 Python 不允许按引用传递参数,因此需要使用 return 语句返回修改后的值:

def exponentiation(number, power):
    power = power * 2
    result = number ** power
    number = result
    return number, power
def test_exponentiation():
    original = 2
    power = 5
    original, power = exponentiation(original, power)
    print(original, power)

执行函数,查看输出:

>>> test_exponentiation()
1024 10

2. 异常处理

程序编写过程中,有两种常见的错误:第一种时语法错误,例如编写程序时缩进出现问题、第二种问题是算法的逻辑错误,例如访问不存在的变量、列表越界访问等。后者通常称为异常,为了处理这种情况,Python 提供了异常处理机制:

>>> x = []
>>> x[0]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
IndexError: list index out of range

在 Python 中,异常状态使用异常对象来表示,在遇到错误时引发异常。如果未处理异常对象,程序将会终止并显示错误消息 (Traceback)。每种异常也都是不同异常类的实例(上一示例中异常是类 IndexError 的实例),可以使用不同方式引发并捕获这些实例,而不至于导致整个程序运行失败。

2.1 raise 语句

可以使用 raise 语句来引发异常,并将类或实例作为参数。将类作为参数时,将自动创建一个实例,同时也可以添加错误消息提示:

>>> raise OSError
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
OSError
>>> raise OSError("can't open this file")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
OSError: can't open this file

2.2 异常捕获

当程序发生异常时,也称程序“抛出”异常。对异常进行处理,通常称为异常捕获。为此,可使用 try/except 语句。例如,进行除法运算时,如果用户输入了一个非零的除数,那么运算结果就会被打印出来。但是,如果用户输入了一个零作为除数,那么就会引发 ZeroDivisionError 异常:

>>> number_a = float(input('Please enter a number: '))
Please enter a number: 10.2
>>> number_b = float(input('Please enter another number: '))
Please enter another number: 0
>>> print(number_a / number_b)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ZeroDivisionError: float division by zero

使用 except 语句块则可以“捕捉”这个异常,并且打印提示消息,然后通过对除数加一个很小的值确保其不为零,这意味着程序并不会终止,而是继续执行后续语句:

>>> try:
...     print(number_a / number_b)
... except:
...     print('Divisor cannot be zero!')
...     print('Add a small number to the divisor.')
...     print(number_a / (number_b + 1e-8))
Divisor cannot be zero
Add a small number to the divisor
1019999999.9999999

如果需要捕获多个异常,可以使用多个 except 子句,或者在一个元组中指定这些异常:

# 使用多个 except 子句
try:
    number_a = input('Please enter a number:')
    number_b = input('Please enter another number:')
    print(float(number_a) / float(number_b))
except TypeError:
    print("That wasn't a number!")
except ZeroDivisionError:
    print('Divisor cannot be zero!')
# 使用元组指定异常
try:
    number_a = input('Please enter a number:')
    number_b = input('Please enter another number:')
    print(float(number_a) / float(number_b))
except (ZeroDivisionError, TypeError):
    print("You entered the wrong number!")

try/except 语句还有一个可选的 else 子句,如果使用这个子句,那么必须放在所有的 except 子句之后,else 子句在 try 子句没有发生任何异常时执行,例如在 try 语句中执行除法运算,如果正确运算没有发生异常,则执行 else 部分,打印结果:

try:
    number_a = input('Please enter a number:')
    number_b = input('Please enter another number:')
    result = float(number_a) / float(number_b)
except (ZeroDivisionError, TypeError):
    print("You entered the wrong number!")
else:
    print(result)

不把所有语句都放在 try 子句,而使用 else 子句,可以避免一些意料之外,而 except 又无法捕获的异常。

2.3 finally 子句

finally 子句可以与 try 语句配套使用,可以在发生异常时执行清理工作,不管 try 子句中是否发生异常,都将执行 finally 子句:

result = None
try:
    number_a = input('Please enter a number:')
    number_b = input('Please enter another number:')
    result = float(number_a) / float(number_b)
except (ZeroDivisionError, TypeError):
    print("You entered the wrong number!")
else:
    print(result)
finally:
    del result

总结

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

(0)

相关推荐

  • Python常遇到的错误和异常

    目录 1.语法错误 2.异常 3.异常处理 4.try/except...else 5.try-finally 语句 6.抛出异常 7.用户自定义异常 在日常的学习Python过程中,由于本身的编程水平受限,时不时的给我抛出一个异常让我真的很难受:在学习的过程中发现Python中的错误分为语法错误和异常两种. 1.语法错误 Python中的语法错误通常是最为明显的错误了,由于不按照要求书写代码,往往就容易出现语法错误 示例代码: >>> print("hello world)

  • 深入了解python高阶函数编写与使用

    目录 1.变量可以指向函数 2.函数名也可以是变量. 3.传入函数 总结 何为高阶函数,以实际代码为例子一步步深入概念. 1.变量可以指向函数 以abs()为例: >>>abs(-10) 10 但是只写abs呢? >>>abs <built-in function abs> abs(-10)是调用函数而abs是函数本身 . 把函数本身赋给变量呢? >>>f=abs >>>f <built-in function ab

  • Python中异常处理用法

    目录 1.if进行处理,在错误发生之前进行预防 2.用try..except:在错误发生之后进行处理 为了保证程序的健壮性与容错性,即在遇到错误时候程序不会崩溃,我们需要对异常进行处理, 1.if进行处理,在错误发生之前进行预防 如果错误发生的条件是可预知的,我们需要用if进行处理,在错误发生之前进行预防 AGE=10 while True: age=input('>>: ').strip() if age.isdigit(): #只有在age为字符串形式的整数时,下列代码才不会出错,该条件是

  • Python中关于元组 集合 字符串 函数 异常处理的全面详解

    目录 元组 集合 字符串 1.字符串的驻留机制 2.常用操作 函数 1.函数的优点: 2.函数的创建:def 函数名([输入参数]) 3.函数的参数传递: 4.函数的返回值: 5.函数的参数定义: 6.变量的作用区域 7.递归函数:函数体内套用该函数本身 8.将函数存储在模块中 9.函数编写指南: Bug 1.Bug常见类型 2.常见异常类型 3.python异常处理机制 pycharm开发环境的调试 编程思想 (1)两种编程思想 (2)类和对象的创建 元组 元组是不可变序列 多任务环境下,同时

  • Python函数中4种参数的使用教程

    1.必需的参数: 必须参数须以正确的顺序传入函数,调用的数量必须和声明时的一样 def f(name,age): print('I am %s,I am %d'%(name,age)) f('alex',18) f('alvin',16) 输出: I am alex,I am 18 I am alvin,I am 16 2关键字参数: 关键字参数和函数调用关系紧密,函数调用使用关键字参数来确定传入的参数值.使用关键字参数允许函数调用时参数的顺序与声明时不一致,因为 Python 解释器能够用参数

  • 详解Python的函数与异常

    目录 1. 函数 1.1 自定义函数 1.2 函数与参数 1.3 函数与返回值 2. 异常处理 2.1 raise 语句 2.2 异常捕获 2.3 finally 子句 总结 1. 函数 抽象是程序能够被人理解的关键所在.程序应非常抽象,如获取用户输入构造列表,查找列表中最大的值,并进行打印: list_a = get_input() max_value = max(list_a) print(max_value) 看到这些代码,可以很容易这个程序是做什么的,至于这些操作的具体细节,将在独立的函

  • 详解Python map函数及Python map()函数的用法

    python map函数 map()函数 map()是 Python 内置的高阶函数,它接收一个函数 f 和一个 list,并通过把函数 f 依次作用在 list 的每个元素上,得到一个新的 list 并返回. 例如,对于list [1, 2, 3, 4, 5, 6, 7, 8, 9] 如果希望把list的每个元素都作平方,就可以用map()函数: 因此,我们只需要传入函数f(x)=x*x,就可以利用map()函数完成这个计算: def f(x): return x*x print map(f,

  • 详解Python匿名函数(lambda函数)

    匿名函数lambda Python使用lambda关键字创造匿名函数.所谓匿名,意即不再使用def语句这样标准的形式定义一个函数.这种语句的目的是由于性能的原因,在调用时绕过函数的栈分配.其语法是: lambda [arg1[, arg2, ... argN]]: expression 其中,参数是可选的,如果使用参数的话,参数通常也会在表达式之中出现. 下面举例来说明lambda语句的使用方法(无参数). # 使用def定义函数的方法 def true(): return True #等价的l

  • 详解python while 函数及while和for的区别

    1.while循环(只有在条件表达式成立的时候才会进入while循环) while 条件表达式: pass while 条件表达式: pass else: pass 不知道循环次数,但确定循环条件的时候用while # 如果说年利率是6%,存入1000到第几年本钱翻倍 money = 10000 year = 0 while money < 20000: money = money*(1+0.06) year += 1 print('第 {0} 年本钱翻倍了,总共有 {1} 元'.format(

  • 详解python eval函数的妙用

    python eval函数功能:将字符串str当成有效的表达式来求值并返回计算结果. 函数定义: eval(expression, globals=None, locals=None) 将字符串str当成有效的表达式来求值并返回计算结果.globals和locals参数是可选的,如果提供了globals参数,那么它必须是dictionary类型:如果提供了locals参数,那么它可以是任意的map对象. python的全局名字空间存储在一个叫globals()的dict对象中:局部名字空间存储在

  • 详解python中自定义超时异常的几种方法

    最近在项目中调用第三方接口时候,经常会出现请求超时的情况,或者参数的问题导致调用异代码异常.针对超时异常,查询了python 相关文档,没有并发现完善的包来根据用户自定义的时间来抛出超时异常的模块.所以自己干脆自己来实现一个自定义的超时异常.目前找到了两种方式来实现超时异常的功能(signal.alarm().threading实现超时异常) 方法1 thread + time 原理:将要调用的功能函数放入子线程,通过设定子线程的阻塞时间,超时则主线程并不会等待子线程的执行.主线程退出,子线程就

  • 代码详解Python的函数基础(1)

    目录 1.函数调用 2.函数定义 总结 1.函数调用 # 1.调用函数,需要知道函数的名称和参数 # 2.调用函数传入的参数需要和函数定义的参数数量和类型一致 # 如调用abs函数 print("-2的绝对值为:",abs(-2)) print("100的绝对值为:",abs(100)) # 3.函数名是指向一个函数对象的引用,可以把函数名赋给一个变量,相当于给这个函数起别名 abs1 = abs # 变量abs1指向abs函数 print("-1的绝对值

  • 代码详解Python的函数基础(2)

    目录 1.函数参数 2.递归函数 总结 1.函数参数 # 1.位置参数:调用函数时,传入的值需要按照位置顺序传入 # 实例:求x的n次方 def xPowN(x,n): # 传入的值按照x,n的位置顺序传入 s = 1 while n > 0: n = n - 1 s = s * x return s print("2的5次方的值为:",xPowN(2,5)) print("5的2次方的值为:",xPowN(5,2)) # 结果输出: # 2的5次方的值为:

  • 详解Python函数可变参数定义及其参数传递方式

    Python函数可变参数定义及其参数传递方式详解 python中 函数不定参数的定义形式如下 1. func(*args)  传入的参数为以元组形式存在args中,如: def func(*args): print args >>> func(1,2,3) (1, 2, 3) >>> func(*[1,2,3]) #这个方式可以直接将一个列表的所有元素当作不定参数 传入(1, 2, 3) 2.func( **kwargs) 传入的参数为以字典形式存在args中,如: d

  • 详解python中的异常和文件读写

    Python异常 1.python异常的完整语法 try: # 提示用户输入一个整数 num = int(input("输入一个整数:")) # 使用 8 除以用户输入的整数并且输出 result = 8 / num print(result) except ValueError: print("请输入正确的整数!") except Exception as result: print("未知错误:%s" % result) else: prin

随机推荐