Python:在try/except/else块中引发异常,处理顺序问题

0 投票
1 回答
1223 浏览
提问于 2025-04-16 21:11

我刚开始学习Python,正在写我的第一个模块,这个模块的功能是把数据备份到外部存储设备(通常是一个或多个USB硬盘)。

我希望这个模块能按以下步骤工作:

  1. 检查备份目标(备份硬盘)是否已经挂载。根据这个检查,destination_was_mounted会变成True或False。
  2. 如果destination_was_mounted是False,那就挂载这个目标。
  3. 如果挂载目标失败,就抛出异常并重新开始循环。
  4. 如果挂载成功,就检查目标上是否存在checkfile(和backup_dir)。
  5. 如果检查目标失败,就抛出异常并重新开始循环。
  6. 继续处理(这部分我还没写)。
  7. 在任何情况下,如果destination_was_mounted是False,就卸载这个目标。

问题是,如果check_destination部分抛出异常,即使我在finally部分有卸载的代码,它也没有卸载目标。就好像destination_was_mounted变成了True,尽管它应该是False。或者就像check_destination在mount_destination之前运行,尽管它实际上是在后面。

我的参考资料(除了查看Python文档和我的《学习Python》书籍):

Python:如何让for循环从一个函数继续?

如何在Python中异常后重试?

如何在处理异常后回到for循环?

#!/usr/bin/env python3.1

import sys
import os
import os.path
import subprocess
import configparser
CONFIGFILE = 'backup.ini'
# do i need this?
config = {}

config = configparser.ConfigParser()
config.read(CONFIGFILE)
backup_sources = sorted(config.sections()[1:])

class NoCheckFile(Exception):
    pass

def mountDestination(destination):
    return subprocess.check_call(['mount', destination])

def unMountDestination(destination):
    return subprocess.check_call(['umount', destination])

def checkDestination(destination, backup_dir, checkfile):
    return os.path.exists(destination + '/' + backup_dir + '/' + checkfile)

''' exception handlers '''
# perhaps add another arg like 0 or 1 for success/failure
def handleCalledProcessError(ex):
    print('Exception: ' + str(ex))

def handleNoCheckFile(ex):
    print('Exception: ' + str(ex))

# rename me once I work out logging
def logExecute(result):
    print('Info: ' + str(result))
# can I pass logging output here

def main():
    for section in backup_sources:
        item = dict(config.items(section))
        destination = item['destination']
        destination_was_mounted = os.path.ismount(destination)
        backup_dir = item['backup_dir']
        checkfile = item['checkfile']
        try:
            ''' check destination_was_mounted and mount destination if required '''
            mount_destination = None
            unmount_destination = None
            if not destination_was_mounted:
                mount_destination = mountDestination(destination)

            ''' check that checkfile exists in backup_dir '''
            check_destination = checkDestination(destination, backup_dir, checkfile)
            if not check_destination:
                raise NoCheckFile('no checkfile found')

            ''' lvm snapshot, mount and source path update '''

            ''' backup engine code here '''

            ''' check destination_was_mounted and um-mount destination if required '''
            if not destination_was_mounted:
                unmount_destination = unMountDestination(destination)
        except subprocess.CalledProcessError as ex:
            print(destination, 'mounted before loop start: ', destination_was_mounted)
            handleCalledProcessError(ex)
        except NoCheckFile as ex:
            handleNoCheckFile(ex)
        else:
            print(destination, 'mounted before loop start: ', destination_was_mounted)
            logExecute(mount_destination)
            logExecute(check_destination)
        finally:
            print('should always see me')
            logExecute(unmount_destination)
            # return to say True or False

    # this should be where email reports etc. go

if __name__ == '__main__':
    main()

backup.ini文件中相关的部分是:

[general]

[1]
DESTINATION = /mnt/backup2
BACKUP_DIR = BACKUP2
CHECKFILE = .checkfile

[2]
DESTINATION = /mnt/backup1
BACKUP_DIR = BACKUP1
CHECKFILE = .checkfile

输出看起来是这样的——我有两个备份硬盘,挂载在[1]和[2]指定的点上,并故意没有为[1]创建checkfile来进行测试。

> umount /mnt/backup1
umount: /mnt/backup1: not mounted
> umount /mnt/backup2 
umount: /mnt/backup2: not mounted
> mugsyback.py 
Exception: no checkfile found
should always see me
Info: None
/mnt/backup1 mounted before loop start:  False
Info: 0
Info: True
should always see me
Info: 0
> mount
...
/dev/sdc1 on /mnt/backup2 type ext3 (rw)

1 个回答

0

你在尝试的代码块里有卸载的代码。而在最后的部分,你只是记录了一些信息。

撰写回答