如何在Python中实现'EXIT_CODES'?

2 投票
5 回答
3283 浏览
提问于 2025-04-16 04:15

一开始我想做的事情是这样的:

#EXIT CODES
class ExitCode(object):
    (USERHOME_INVALID, \
    USERHOME_CANNOT_WRITE, \
    USERHOME_CANNOT_READ, \
    BASHRC_INVALID) = range(-1, -5, -1)

但后来我意识到,我必须确切知道总共有多少个退出代码(EXIT_CODES),这样才能把这个数字传给 range() 函数。假设我有 87 个(随便举个例子)退出代码……我不想一个一个数到 87(虽然这并不难),但我想找一个更优雅的解决办法。

有没有什么建议呢?

补充说明:退出代码是一个负整数,会传递给 sys.exit。与其写这个数字,我更希望使用一些常量(类似于 C 语言中的 #defines 或枚举,或者 Java 中的枚举)。

5 个回答

1

我得说明一下,负数状态对于 sys.exit() 来说并不一定有意义;至少在 Linux 系统上,它会被当作一个无符号的 8 位值来处理(范围是 0 到 255)。至于枚举类型,你可以做一些类似这样的事情:

class ExitStatus: pass
for code, name in enumerate("Success Failure CriticalFailure".split()):
    setattr(ExitStatus, name, code)

这样会得到类似这样的结果:

>>> ExitStatus.__dict__
{'CriticalFailure': 2, 'Failure': 1, '__module__': '__main__',
'__doc__': None, 'Success': 0}

在普通的 Unix 系统中,预定义的值是 EXIT_FAILURE=1 和 EXIT_SUCCESS=0。

补充说明:考虑到关于 IDE 识别标识符的担忧,你也可以做一些类似这样的事情:

class EnumItem: pass
def adjustEnum(enum):
    value=0
    enumdict=enum.__dict__
    for k,v in enumdict.items():
        if isinstance(v,int):
            if v>=value:
                value=v+1
    for k,v in enumdict.items():
        if v is EnumItem:
            enumdict[k]=value
            value+=1

class ExitStatus:
    Success=0
    Failure=EnumItem
    CriticalFailure=EnumItem
adjustEnum(ExitStatus)

第二次编辑:我忍不住又来了。这是一个变体,它按照你写的名称顺序来分配值。

class EnumItem:
    serial=0
    def __init__(self):
        self.serial=self.__class__.serial
        self.__class__.serial+=1

def adjustEnum(enum):
    enumdict=enum.__dict__
    value=0
    unknowns={}
    for k,v in enumdict.items():
        if isinstance(v,int):
            if v>=value:
                value=v+1
        elif isinstance(v,EnumItem):
            unknowns[v.serial]=k
    for i,k in sorted(unknowns.items()):
        enumdict[k]=value
        value+=1
    return enum

@adjustEnum
class ExitStatus:
    Success=0
    Failure=EnumItem()
    CriticalFailure=EnumItem()

显然,随着复杂性增加,这种方式看起来不太优雅,但确实是可行的。

2

也许我没有理解这个问题,但为什么不直接做一个退出代码的字典,然后在一个函数里实现你想要的行为呢?

EXIT_CODES = dict(SUCCESS=0,
                  USER_NAME_INVALID=-1,
                  OTHER_ERROR=-2)

def exit(code):
   try:
      return EXIT_CODES[code]  
   except KeyError:
      raise KeyError("exit code %s is not implemented" % code)

这样你就可以像这样使用它

# some computation goes here
return exit("SUCCESS")

如果你想要“自动”分配数字(我不推荐这样做),你可以简单地创建一个退出代码的列表,然后返回索引的负值:

EXIT_CODES = ['SUCCESS', 'ERROR_1', 'ERROR_2']
return -EXIT_CODES.index('ERROR_1')
# will return -1

(对于最后一种情况,你可以实现一个类似于基于字典的函数)

2

听起来你想要的是Python中类似于C#或其他类似语言的枚举类型。在Python中如何表示'Enum'?提供了几种解决方案,不过这些方案还是需要你知道有多少个项目。

补充一下:在Python中如何表示'Enum'?看起来好多了

或者你可以试试这样的做法(虽然可能不是最好的解决方案):

class _ExitCode:
    _exit_codes=["EXIT_CODE","EXIT_CODE_TWO"]
    def __getattr__(self, name):
        if name in _ExitCode._exit_codes:
            return -(_ExitCode._exit_codes.index(name)+1)
        raise AttributeError("Exit code %s not found" % name)

ExitCode=_ExitCode()
print ExitCode.EXIT_CODE #-1

撰写回答