2010-01-30 4 views
17

__init__ 클래스를 초기화하는 동안 클래스 메서드에서 호출하는 것을 피할 수있는 방법이 있습니까?Python : 초기화 프로그램을 호출하지 않고 클래스 인스턴스 생성

효과적인 비교를 위해 파이썬에서 대소 문자를 구별하지 않는 문자열 클래스를 만들고 싶지만 __init__을 호출하지 않고 새 인스턴스를 만드는 데 문제가 있습니다.

>>> class String: 

    def __init__(self, string): 
     self.__string = tuple(string.split()) 
     self.__simple = tuple(self.__simple()) 

    def __simple(self): 
     letter = lambda s: ''.join(filter(lambda s: 'a' <= s <= 'z', s)) 
     return filter(bool, map(letter, map(str.lower, self.__string))) 

    def __eq__(self, other): 
     assert isinstance(other, String) 
     return self.__simple == other.__simple 

    def __getitem__(self, key): 
     assert isinstance(key, slice) 
     string = String() 
     string.__string = self.__string[key] 
     string.__simple = self.__simple[key] 
     return string 

    def __iter__(self): 
     return iter(self.__string) 

>>> String('Hello, world!')[1:] 
Traceback (most recent call last): 
    File "<pyshell#2>", line 1, in <module> 
    String('Hello, world!')[1:] 
    File "<pyshell#1>", line 17, in __getitem__ 
    string = String() 
TypeError: __init__() takes exactly 2 positional arguments (1 given) 
>>> 
나는 슬라이스로 새 개체를 초기화하는 데 사용할 string = String(); string.__string = self.__string[key]; string.__simple = self.__simple[key]를 교체해야합니까

?

은 편집 :로 아래 서면 답변을 영감으로

, 이니셜 신속 인수를 확인하기 위해 편집되었다.

def __init__(self, string=None): 
    if string is None: 
     self.__string = self.__simple =() 
    else: 
     self.__string = tuple(string.split()) 
     self.__simple = tuple(self.__simple()) 
+0

가능한 복제본 [\ _ \ _ init \ _ \ _을 (를) 호출하지 않고 클래스를 인스턴스화하는 방법이 있습니까?] (http : // stackoverflow.com/questions/6383914/is-there-a-way-to-instantiate-a-class-without-calling-init) – kay

답변

1

메타 클래스를 사용하면이 예제에서 좋은 해결책이됩니다. 메타 클래스는 사용이 제한되어 있지만 잘 작동합니다.

>>> class MetaInit(type): 

    def __call__(cls, *args, **kwargs): 
     if args or kwargs: 
      return super().__call__(*args, **kwargs) 
     return cls.__new__(cls) 

>>> class String(metaclass=MetaInit): 

    def __init__(self, string): 
     self.__string = tuple(string.split()) 
     self.__simple = tuple(self.__simple()) 

    def __simple(self): 
     letter = lambda s: ''.join(filter(lambda s: 'a' <= s <= 'z', s)) 
     return filter(bool, map(letter, map(str.lower, self.__string))) 

    def __eq__(self, other): 
     assert isinstance(other, String) 
     return self.__simple == other.__simple 

    def __getitem__(self, key): 
     assert isinstance(key, slice) 
     string = String() 
     string.__string = self.__string[key] 
     string.__simple = self.__simple[key] 
     return string 

    def __iter__(self): 
     return iter(self.__string) 

>>> String('Hello, world!')[1:] 
<__main__.String object at 0x02E78830> 
>>> _._String__string, _._String__simple 
(('world!',), ('world',)) 
>>> 
0

과 같이, 생성자에 또 다른 인수를 전달합니다

def __init__(self, string, simple = None): 
    if simple is None: 
     self.__string = tuple(string.split()) 
     self.__simple = tuple(self.__simple()) 
    else: 
     self.__string = string 
     self.__simple = simple 

당신은 다음과 같이 호출 할 수 있습니다

def __getitem__(self, key): 
    assert isinstance(key, slice) 
    return String(self.__string[key], self.__simple[key]) 

을 또한, 나는이 이름을 사용할 수있어 확실하지 않다 필드와 방법 모두 __simple. 가독성을 위해서만 변경해야합니다.

+0

첫 번째 대답이 더 마음에 들었습니다. 'str() == '''을 고려할 때, 나는 코드를'def __init __ (self, string = '') :'로 변경할 것이라고 생각한다. 당신의 도움과 생각에 감사드립니다! 나는'__init__'을 피하기를 희망했지만, 언급 된 변경으로'String() '을 호출하는 것은 매우 비싼 작업이되어서는 안됩니다. 이 시점에서 가장 좋은 해결책 인 것 같습니다. –

+0

미안하지만, 내 첫 번째 대답은 정말로 문제를 해결하지 못했다고 생각합니다 :) 나는 그것을 되돌릴 수있는 방법이 없을 것 같습니다 ...? – Thomas

21

실현 가능한 경우 __init__이 호출되도록 허용하고 (적절한 인수로 무해한 호출을 수행하는 것이 좋습니다). 그러나 너무 많은 왜곡이 필요하면 구식 클래스를 사용하는 비참한 선택을 피할 수있는 한 대안이 있습니다 (아니요 새 코드에서 구식 클래스를 사용하는 데는 합당한 이유가 있습니다. 여러 가지 이유 하지에) ... :

class String(object): 
     ... 

    bare_s = String.__new__(String) 
당신이 보통과 같은 방법으로 사용 볼 수 있도록이 관용구는 일반적으로, "대안 생성자"로 작동하기위한 것입니다 classmethod들에 사용되는

... :

@classmethod 
def makeit(cls): 
    self = cls.__new__(cls) 
    # etc etc, then 
    return self 

(이렇게하면 classmethod 기본 클래스가 아닌 하위 클래스에서 호출 될 때 하위 클래스 인스턴스가 제대로 상속되고 생성됩니다.

+6

Python 3.1에서 어떻게 이것을 다시 작성 하시겠습니까? –

+0

String이 하위 클래스 인 경우 어떻게 상위 클래스의 생성자를 호출할까요? – gozzilli

+0

오, 발견했습니다.''self''를 생성 한 후에''SuperClass .__ init __ (self)''를 할 것입니다. – gozzilli

5

표준 pickle 및 복사 모듈에서 사용하는 트릭은 빈 클래스를 만들고이를 사용하여 객체를 인스턴스화 한 다음 해당 인스턴스의 __class__을 "실제"클래스에 할당하는 것입니다. 예 :

>>> class MyClass(object): 
...  init = False 
...  def __init__(self): 
...   print 'init called!' 
...   self.init = True 
...  def hello(self): 
...   print 'hello world!' 
... 
>>> class Empty(object): 
...  pass 
... 
>>> a = MyClass() 
init called! 
>>> a.hello() 
hello world! 
>>> print a.init 
True 
>>> b = Empty() 
>>> b.__class__ = MyClass 
>>> b.hello() 
hello world! 
>>> print b.init 
False 

그러나이 방법은 거의 필요하지 않습니다. __init__을 우회하면 예기치 않은 부작용이 생길 수 있습니다. 특히 원래 수업에 익숙하지 않은 경우에는 무엇을하고 있는지 확인하십시오.

관련 문제