如何在python中使用多个Try-Excepts后跟着一个Else子句

45 阅读3分钟

在python中,如果有多个连续的Try-Except子句,并且只有当所有这些子句都成功时才触发一个Else子句,该如何实现?例如,以下代码中,只有当所有Voltmeter都成功初始化时,才希望打印“仪表已初始化”。但是,目前代码只取决于加热器温度计。

try:
    private.anodization_voltage_meter = Voltmeter(voltage_meter_address.value) #assign voltmeter location
except(visa.VisaIOError): #channel time out
    private.logger.warning('Volt Meter is not on or not on this channel')
try:
    private.anodization_current_meter = Voltmeter(current_meter_address.value) #assign voltmeter as current meter location
except(visa.VisaIOError): #channel time out
    private.logger.warning('Ammeter is not on or not on this channel')
try:
    private.sample_thermometer = Voltmeter(sample_thermometer_address.value)#assign voltmeter as thermomter location for sample.
except(visa.VisaIOError): #channel time out
    private.logger.warning('Sample Thermometer is not on or not on this channel')
try:
    private.heater_thermometer = Voltmeter(heater_thermometer_address.value)#assign voltmeter as thermomter location for heater.
except(visa.VisaIOError): #channel time out
    private.logger.warning('Heater Thermometer is not on or not on this channel')
else:
    private.logger.info('Meters initialized')

2、解决方案

以下是一些可能的解决方案:

解决方案1:使用函数和all()

一种方式是将try/except结构分解成一个函数,如果调用成功则返回True,如果调用失败则返回False,然后使用all()来查看它们是否都成功了。例如:

def initfunc(structure, attrname, address, desc):
  try:
    var = Voltmeter(address.value)
    setattr(structure, attrname, var)
    return True
  except(visa.VisaIOError):
    structure.logger.warning('%s is not on or not on this channel' % (desc,))

if all([initfunc(*x) for x in [(private, 'anodization_voltage_meter', voltage_meter_address, 'Volt Meter'), ...]]):
  private.logger.info('Meters initialized')

解决方案2:使用trip变量

另一种方式是使用一个trip变量,如init_ok,将其设置为True,并在所有except子句中将其设置为False,最后再进行测试。例如:

init_ok = True
for meter, address, message in (
        ('anodization_voltage_meter',voltage_meter_address,'Volt Meter is not on or not on this channel'),
        ('anodization_current_meter',current_meter_address,'Ammeter is not on or not on this channel'),
        ('sample_thermometer',sample_thermometer_address,'Sample Thermometer is not on or not on this channel'),
        ('heater_thermometer',heater_thermometer_address,'Heater Thermometer is not on or not on this channel')):
   try:
       setattr(private,meter, Voltmeter(address.value):
   except (visa.VisaIOError,):
       init_ok = False
       private.logger.warning(message)

if init_ok: # everything is ok
    private.logger.info('Meters initialized')

解决方案3:使用布尔变量

还可以使用一个布尔变量,在开头初始化为True:everythingOK=True。然后在所有的except块中将其设置为False,只有在true的情况下才记录最后一行。例如:

success = True
for meter, address, message in (
        ('anodization_voltage_meter',voltage_meter_address,'Volt Meter is not on or not on this channel'),
        ('anodization_current_meter',current_meter_address,'Ammeter is not on or not on this channel'),
        ('sample_thermometer',sample_thermometer_address,'Sample Thermometer is not on or not on this channel'),
        ('heater_thermometer',heater_thermometer_address,'Heater Thermometer is not on or not on this channel')):
   try:
       setattr(private,meter, Voltmeter(address.value):
   except (visa.VisaIOError,):
       success = False
       private.logger.warning(message)

if success: # everything is ok
    private.logger.info('Meters initialized')

解决方案4:使用数据驱动的解决方案

如果有多个相似性对象,可以使用数据驱动的解决方案。例如,可以创建一个包含所有对象的类,并使用这个类来初始化所有的对象。这样可以简化代码并提高可读性。

class MeterConfiguration(object):
    def __init__(self, name, address):
        self.name = name
        self.address = address

    def english_name(self):
        """A readable form of the name for this meter."""
        return ' '.join(x.title() for x in self.name.split('_')) + ' Meter'

ALL_METERS = [
    MeterConfiguration('anodization_voltage', 'PORT0001'),
    MeterConfiguration('anodization_current', 'PORT0002'),
    MeterConfiguration('sample_thermometer', 'PORT0003'),
    MeterConfiguration('heater_thermometer', 'PORT0004')
]

private.meters = {}
any_errors = False
for meter in ALL_METERS:
    try:
        private.meters[meter.name] = Voltmeter(meter.address)
    except VisaError:
        logging.error('%s not found at %s', meter.english_name(), meter.address)
        any_errors = True
if not any_errors:
    logging.info('All meters initialized.')