python-2.文件&OS模块&异常

本文介绍了Python中的文件操作,包括文件打开模式和文件对象方法,还详细讲解了OS模块和异常处理,如try-except-finally语句、调用栈分析、logging模块记录错误、raise语句抛出错误,以及使用else和with语句进行错误处理。此外,文章还探讨了Python的调试方法,如assert断言和使用IDE进行调试。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

文件

文件的打开模式和文件对象方法
http://bbs.fishc.com/thread-45279-1-1.html
(出处: 鱼C论坛)

模块

import …
os模块
os.path模块
os、os.path 模块中关于文件、目录常用的函数使用方法
http://bbs.fishc.com/thread-45512-1-1.html
(出处: 鱼C论坛)

pickle模块(泡菜模块):将你的数据对象保存为二进制文件
先以‘wb’模式open文件:
存储数据
先以‘wb’模式open文件;
pickle.dump(date,file)
读取数据
先以‘rb’模式open文件;
pickle.load(date,file)

exception

Python 标准异常总结
http://bbs.fishc.com/thread-45814-1-1.html
(出处: 鱼C论坛)

try-except-finally语句
try:
    检测范围
except [Exception[as reason]]:
    出现exception后的处理代码
finally:
    无论如何都会执行的代码
try:
    sum=1+'1'
    f=open('我为什么是一个文件')
    print(f.read())
    f.close()

except OSError as reason:
    print('文件出错\n原因是:'+str(reason))
except TypeError as reason:
    print('类型错误\n错误原因是:'+str(reason))
except:
    print('出错了\n')
try:
    sum=1+'1'
    f=open('我为什么是一个文件')
    print(f.read())
    f.close()

except(OSError,TypeError):
    print('出错了\n')
try:

    f=open('d:\\a.txt','w')
    print(f.write('我存在了'))
    sum=1+'1'

except OSError as reason:
    print('文件出错\n原因是:'+str(reason))
except TypeError as reason:
    print('类型错误\n错误原因是:'+str(reason))
finally:
    f.close()#无论如何都会执行
调用栈

如果错误没有被捕获,它就会一直往上抛,最后被Python解释器捕获,打印一个错误信息,然后程序退出。出错的时候,一定要分析错误的调用栈信息,才能定位错误的位置。来看看err.py:

# err.py:
def foo(s):
    return 10 / int(s)

def bar(s):
    return foo(s) * 2

def main():
    bar('0')

main()

执行,结果如下:

$ python3 err.py
Traceback (most recent call last):#告诉我们这是错误的跟踪信息。
  File "err.py", line 11, in <module>#调用main()出错了,在代码文件err.py的第11行代码,但原因是第9行
    main()
  File "err.py", line 9, in main#调用bar('0')出错了,在代码文件err.py的第9行代码,但原因是第6行
    bar('0')
  File "err.py", line 6, in bar#原因是return foo(s) * 2这个语句出错了,但这还不是最终原因
    return foo(s) * 2
  File "err.py", line 3, in foo#原因是return 10 / int(s)这个语句出错了,这是错误产生的源头.
    return 10 / int(s)
ZeroDivisionError: division by zero#根据错误类型ZeroDivisionError,我们判断,int(s)本身并没有出错,但是int(s)返回0,在计算10 / 0时出错,至此,找到错误源头。

出错并不可怕,可怕的是不知道哪里出错了。解读错误信息是定位错误的关键。我们从上往下可以看到整个错误的调用函数链。
如果不捕获错误,自然可以让Python解释器来打印出错误堆栈,但程序也被结束了。既然我们能捕获错误,就可以把错误堆栈打印出来,然后分析错误原因,同时,让程序继续执行下去。
记录错误
如果不捕获错误,自然可以让Python解释器来打印出错误堆栈,但程序也被结束了。既然我们能捕获错误,就可以把错误堆栈打印出来,然后分析错误原因,同时,让程序继续执行下去。

记录错误:logging模块

Python内置的logging模块可以非常容易地记录错误信息:

# err_logging.py

import logging#

def foo(s):
    return 10 / int(s)

def bar(s):
    return foo(s) * 2

def main():
    try:
        bar('0')
    except Exception as e:
        logging.exception(e)#

main()
print('END')

同样是出错,但程序打印完错误信息后会继续执行,并正常退出:

$ python3 err_logging.py
ERROR:root:division by zero
Traceback (most recent call last):
  File "err_logging.py", line 13, in main
    bar('0')
  File "err_logging.py", line 9, in bar
    return foo(s) * 2
  File "err_logging.py", line 6, in foo
    return 10 / int(s)
ZeroDivisionError: division by zero
END

通过配置,logging还可以把错误记录到日志文件里,方便事后排查。

抛出错误:raise语句
>>> 1/0
Traceback (most recent call last):
  File "<pyshell#8>", line 1, in <module>
    1/0
ZeroDivisionError: division by zero
>>> raise ZeroDivisionError
Traceback (most recent call last):
  File "<pyshell#9>", line 1, in <module>
    raise ZeroDivisionError
ZeroDivisionError
>>> raise ZeroDivisionError('除数为0')
Traceback (most recent call last):
  File "<pyshell#10>", line 1, in <module>
    raise ZeroDivisionError('除数为0')
ZeroDivisionError: 除数为0

因为错误是class,捕获一个错误就是捕获到该class的一个实例。因此,错误并不是凭空产生的,而是有意创建并抛出的。Python的内置函数会抛出很多类型的错误,我们自己编写的函数也可以抛出错误。

如果要抛出错误,首先根据需要,可以定义一个错误的class,选择好继承关系(只有在必要的时候才定义我们自己的错误类型。如果可以选择Python已有的内置的错误类型(比如ValueError,TypeError),尽量使用Python内置的错误类型。),然后,用raise语句抛出一个错误的实例:

# err_raise.py
class FooError(ValueError):#定义一个错误的class
    pass

def foo(s):
    n = int(s)
    if n==0:
        raise FooError('invalid value: %s' % s)#抛出自定义的错误
    return 10 / n

foo('0')

执行,可以最后跟踪到我们自己定义的错误:

$ python3 err_raise.py 
Traceback (most recent call last):
  File "err_throw.py", line 11, in <module>
    foo('0')
  File "err_throw.py", line 8, in foo
    raise FooError('invalid value: %s' % s)
__main__.FooError: invalid value: 0

最后,我们来看另一种错误处理的方式:

# err_reraise.py

def foo(s):
    n = int(s)
    if n==0:
        raise ValueError('invalid value: %s' % s)
    return 10 / n

def bar():
    try:
        foo('0')
    except ValueError as e:
        print('ValueError!')
        raise

bar()

在bar()函数中,我们明明已经捕获了错误,但是,打印一个ValueError!后,又把错误通过raise语句抛出去了,这不有病么?

其实这种错误处理方式不但没病,而且相当常见。捕获错误目的只是记录一下,便于后续追踪。但是,由于当前函数不知道应该怎么处理该错误,所以,最恰当的方式是继续往上抛,让顶层调用者去处理。好比一个员工处理不了一个问题时,就把问题抛给他的老板,如果他的老板也处理不了,就一直往上抛,最终会抛给CEO去处理。

else语句

if-else
while-else;for-else
try-else

try:
    int('123')
except ValueError as reason:
    print('出错了\n'+str(reason))
else:
    print('没有异常')
with语句
try:
    f=open('data.txt','w')
    for each_line in f:
        print(each_line)
except OSError as reason:
    print('出错了\n'+str(reason))
finally:
    f.close()
try:
    with open('data.txt','w') as f:#自动调用f.close()
        for each_line in f:
            print(each_line)
except OSError as reason:
    print('出错了\n'+str(reason)) 
调试

1.第一种方法简单直接粗暴有效,就是用print()把可能有问题的变量打印出来看看。
2.凡是用print()来辅助查看的地方,都可以用断言(assert)来替代。
3.把print()替换为logging是第3种方式,和assert比,logging不会抛出错误,而且可以输出到文件.允许你指定记录信息的级别,有debug,info,warning,error等几个级别.
4.IDE:如果要比较爽地设置断点、单步执行,就需要一个支持调试功能的IDE。虽然用IDE调试起来比较方便,但是最后你会发现,logging才是终极武器。

assert断言

assert False程序自动崩溃并抛出AssertionError的异常

>>> assert 3>4
Traceback (most recent call last):
  File "<pyshell#26>", line 1, in <module>
    assert 3>4
AssertionError

程序中如果到处充斥着assert,和print()相比也好不到哪去。不过,启动Python解释器时可以用-O参数来关闭assert:

$ python -O err.py
Traceback (most recent call last):
  ...
ZeroDivisionError: division by zero

关闭后,你可以把所有的assert语句当成pass来看。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值