2012-06-24 2 views
1

Python: Exception in the separated module works wrong에서 다양한 용도의 GnuLibError 클래스를 사용하여 다양한 오류를 '대기'합니다. 각 하위 오류는 고유 한 ID 번호와 오류 형식 문자열을가집니다. - 오류 번호를 호출하는 경우팩토리 클래스, 서브 클래스 생성자에 전달되는 인수의 수가 잘못되었습니다.

class GNULibError(Exception): 
    sub_exceptions = 0 # patched with dict of subclasses once subclasses are created 
    err_num = 0 
    err_format = None 

    def __new__(cls, *args): 
     print("new {}".format(cls)) # DEBUG 
     if len(args) and args[0] in GNULibError.sub_exceptions: 
      print(" factory -> {} {}".format(GNULibError.sub_exceptions[args[0]], args[1:])) # DEBUG 
      return super(GNULibError, cls).__new__(GNULibError.sub_exceptions[args[0]], *(args[1:])) 
     else: 
      print(" plain {} {}".format(cls, args)) # DEBUG 
      return super(GNULibError, cls).__new__(cls, *args) 

    def __init__(self, *args): 
     cls = type(self) 
     print("init {} {}".format(cls, args)) # DEBUG 
     self.args = args 
     if cls.err_format is None: 
      self.message = str(args) 
     else: 
      self.message = "[GNU Error {}] ".format(cls.err_num) + cls.err_format.format(*args) 

    def __str__(self): 
     return self.message 

    def __repr__(self): 
     return '{}{}'.format(type(self).__name__, self.args) 

class GNULibError_Directory(GNULibError): 
    err_num = 1 
    err_format = "destination directory does not exist: {}" 

class GNULibError_Config(GNULibError): 
    err_num = 2 
    err_format = "configure file does not exist: {}" 

class GNULibError_Module(GNULibError): 
    err_num = 3 
    err_format = "selected module does not exist: {}" 

class GNULibError_Cache(GNULibError): 
    err_num = 4 
    err_format = "{} is expected to contain gl_M4_BASE({})" 

class GNULibError_Sourcebase(GNULibError): 
    err_num = 5 
    err_format = "missing sourcebase argument: {}" 

class GNULibError_Docbase(GNULibError): 
    err_num = 6 
    err_format = "missing docbase argument: {}" 

class GNULibError_Testbase(GNULibError): 
    err_num = 7 
    err_format = "missing testsbase argument: {}" 

class GNULibError_Libname(GNULibError): 
    err_num = 8 
    err_format = "missing libname argument: {}" 

# patch master class with subclass reference 
# (TO DO: auto-detect all available subclasses instead of hardcoding them) 
GNULibError.sub_exceptions = { 
    1: GNULibError_Directory, 
    2: GNULibError_Config, 
    3: GNULibError_Module, 
    4: GNULibError_Cache, 
    5: GNULibError_Sourcebase, 
    6: GNULibError_Docbase, 
    7: GNULibError_Testbase, 
    8: GNULibError_Libname 
} 

이 공장 클래스로 GNULibError로 시작 :

나는 그것이 더 나은 예외 클래스의 계층 구조로 작성하고, 그렇게에 착수 할 것입니다 생각 인식 된 서브 클래스에 속한 경우 해당 서브 클래스에 속한 객체를 리턴하고, 그렇지 않으면 디폴트 오류 유형으로 자신을 리턴합니다.

이 코드를 바탕으로, 다음과 정확히 상응하는 (그러나 아니다)해야합니다

e = GNULibError(3, 'missing.lib') 
f = GNULibError_Module('missing.lib') 

print e # -> '[GNU Error 3] selected module does not exist: 3' 
print f # -> '[GNU Error 3] selected module does not exist: missing.lib' 

내가 몇 가지 전략적 인쇄 문을 추가하고, 오류가 GNULibError.__new__ 것 같다 :

>>> e = GNULibError(3, 'missing.lib') 

new <class '__main__.GNULibError'> 
    factory -> <class '__main__.GNULibError_Module'> ('missing.lib',) # good... 
init <class '__main__.GNULibError_Module'> (3, 'missing.lib')  # NO! 
              ^
              why? 

하위 클래스 생성자를 subclass.__new__(*args[1:])으로 호출합니다. 하위 클래스 ID 3을 삭제해야하지만 아직 __init__은 여전히 ​​3을 얻고 있습니다! subclass.__init__으로 전달되는 인수 목록을 어떻게 트리밍 할 수 있습니까?

답변

1

__init__에 전달되는 내용에는 영향을주지 않습니다. 이제는 자신의 하위 클래스를 반환하는 것처럼 "팩토리 클래스"로 작업하는 한 영향을 미칠 수 있습니다. "3"인수가 여전히 전달되는 이유는 GNULibError의 인스턴스를 여전히 __new__에서 반환하기 때문입니다. __new__이 호출 될 때까지는 __init__으로 전달 될 내용을 결정하기에는 너무 늦었습니다. the documentation에 명시된 바와 같이 (강조는 추가) : __new__()가 CLS의 인스턴스를 반환

경우, 새로운 인스턴스의 __init__() 메소드가 자기 새 인스턴스 입니다 __init__(self[, ...])처럼 호출되고, 나머지 인수한다 __new__()으로 전달 된 것과 같습니다. 당신이 GNULibError(3, 'missing.lib')를 호출 할 때 즉

는, 당신이 사람들은 __init__에 전달 될 인수가 있음을 보장 한 그 인수를 사용하여 클래스를 호출하여 --- 너무 늦었어요. __new__은 얻을 수있는 것보다 다른 인스턴스를 반환 할 수 있지만 정상적인 초기화가 중지되지는 않습니다. @Ned BATCHELDER에 의해 제안하는 기능이 __new__/__init__ 기계를 가지고 있지 않으며 단지 클래스의 인스턴스를 반환 할 수 있기 때문에

, 당신은 대신 "팩토리 클래스"의 공장 기능을 사용하는 것이 더 낫다 당신 필요.

0

이 방법은 필요 이상으로 복잡합니다. 클래스가 다른 클래스의 객체를 만들도록 시도하지 마십시오. 예외를 만들기 위해 팩토리 함수를 작성하고 __new__을 사용하지 마십시오. 당신이 알아내는 것처럼 너무 까다 롭습니다.

0

사용 사례 - Ned와 동의합니다 - 좀 더 복잡해야합니다.

(파생 클래스가 아무 것도하지 않는 것처럼 보이지만 오류 메시지와 다르기 때문에) 뭔가를 시도해 볼 수 있습니다.

class GNULibError(Exception): 
    pass # put logic code here 

GNULibErrors = { 
    1: type('GNULibError_Directory', (GNULibError,), {'message': 'suitable whatever here'}) 
} 

그리고 거기에서 조정 ...

관련 문제