2

最初我想做类似的事情:

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

但是我意识到我必须确切地知道 EXIT_CODES 的总数,以便我可以将它传递给 range() 函数。假设我将有 87 个(任意)EXIT_CODES...我不想数到 87(并不是说这很难),但我正在寻找一个更优雅的解决方案。

有什么建议么 ?

编辑: EXIT_CODE 是一个负整数,将传递给 sys.exit 。我更喜欢使用某种常量(例如 C 中的#defines 或 enums,或 Java 中的 enums),而不是写数字。

4

5 回答 5

2

听起来你想要的是 C# 或其他类似语言中枚举的 Python 等价物。如何在 Python 中表示“枚举”?提供了几种解决方案,尽管它们仍然需要您拥有的项目数量。编辑:如何在 Python 中表示“枚举”?看起来好多了

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

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
于 2010-09-16T23:17:17.877 回答
1

也许我不明白这个问题,但你为什么不简单地制作一个退出代码字典并在函数中实现所需的行为呢?

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

(对于最后一个,你可以实现一个类似于基于字典的功能)

于 2010-09-16T23:53:09.677 回答
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()

显然,不断增长的复杂性并不优雅,但它确实有效。

于 2010-09-17T00:05:21.400 回答
1

我想我之前看过这个问题并没有看到它,但要做的一件显而易见的事情是使用字典。

def make_exit_codes(*exit_codes):
    return dict((name, -value - 1) for name, value in enumerate(exit_codes)) 

EXIT_CODES = make_exit_codes('USERHOME_INVALID', 'USERHOME_CANNOT_WRITE',
                             'USERHOME_CANNOT_READ', 'BASHRC_INVALID')
于 2010-09-27T02:12:24.390 回答
0

您可以使用 Python 即时创建变量(或类属性)。例如

ExitCodes = '''USERHOME_INVALID, USERHOME_CANNOT_WRITE,
               USERHOME_CANNOT_READ, BASHRC_INVALID'''

for i, s in enumerate(ExitCodes.split(','), 1):
    exec('%s = %d' % (s.strip(), -i))

print USERHOME_INVALID
print USERHOME_CANNOT_WRITE
print USERHOME_CANNOT_READ
print BASHRC_INVALID

sys.exit(USERHOME_INVALID)

>>> -1
>>> -2
>>> -3
>>> -4
于 2010-09-17T00:09:11.937 回答