programing

__init__를 호출하지 않고 클래스를 인스턴스화하는 방법이 있습니까?

nasanasas 2020. 12. 24. 23:49
반응형

__init__를 호출하지 않고 클래스를 인스턴스화하는 방법이 있습니까?


__init__파이썬에서 클래스 생성자를 우회하는 방법이 있습니까?

예:

class A(object):    
    def __init__(self):
        print "FAILURE"

    def Print(self):
        print "YEHAA"

이제 인스턴스를 만들고 싶습니다 A. 다음과 같이 보일 수 있지만이 구문은 올바르지 않습니다.

a = A
a.Print()

편집하다:

더 복잡한 예 :

C하나의 단일 매개 변수를 저장하고이를 사용하여 몇 가지 계산을 수행하는 목적인 object가 있다고 가정 합니다. 그러나 매개 변수는 그대로 전달되지 않지만 거대한 매개 변수 파일에 포함됩니다. 다음과 같이 보일 수 있습니다.

class C(object):
    def __init__(self, ParameterFile):
        self._Parameter = self._ExtractParamterFile(ParameterFile)
    def _ExtractParamterFile(self, ParameterFile):
        #does some complex magic to extract the right parameter
        return the_extracted_parameter

이제 그 객체의 인스턴스를 덤프하고로드하고 싶습니다 C. 그러나이 개체를로드 할 때 단일 변수 만 self._Parameter있고 매개 변수 파일을 예상하기 때문에 생성자를 호출 할 수 없습니다.

    @staticmethod
    def Load(file):
        f = open(file, "rb")
        oldObject = pickle.load(f)
        f.close()

        #somehow create newObject without calling __init__
        newObject._Parameter = oldObject._Parameter
        return newObject

즉, 매개 변수 파일을 전달하지 않고 인스턴스를 생성 할 수 없습니다. 그러나 내 "실제"의 경우, 이것은 매개 변수 파일이 아니라 메모리에 저장하거나 디스크에 저장하고 싶지 않은 엄청난 양의 데이터입니다.

그리고 C메서드에서 인스턴스를 반환하고 싶기 때문에 Load어떻게 든 생성자를 호출해야합니다.

이전 편집 :

내가 질문하는 이유 를 설명하는 더 복잡한 예 :

class B(object):    
    def __init__(self, name, data):
        self._Name = name
        #do something with data, but do NOT save data in a variable

    @staticmethod
    def Load(self, file, newName):
        f = open(file, "rb")
        s = pickle.load(f)
        f.close()

        newS = B(???)
        newS._Name = newName
        return newS

보시다시피 data클래스 변수에 저장되지 않았으므로 __init__. 물론 간단하게 저장할 수 있지만 데이터가 항상 메모리에 저장하거나 디스크에 저장하고 싶지 않은 거대한 개체라면 어떻게해야합니까?


직접 전화를 걸어 우회 있습니다 . 그런 다음 주어진 유형의 객체를 만들고에 대한 대체 메서드를 호출 할 수 있습니다 . 이것은 할 일입니다.__init____new____init__pickle

그러나 먼저 그것은 당신 이하지 말아야 할 일이며 달성하려는 것이 무엇이든 그것을하는 더 좋은 방법이 있으며 그중 일부는 다른 답변에 언급되어 있음을 강조하고 싶습니다 . 특히 호출을 건너 뛰는 것은 좋지 않습니다__init__ .

객체가 생성되면 다소간 발생합니다.

a = A.__new__(A, *args, **kwargs)
a.__init__(*args, **kwargs)

두 번째 단계는 건너 뛸 수 있습니다.

당신이 여기 왜 다음을 수행 의 목적은 __init__모든 필드에 개체, 채우기를 초기화하고 있음을 확인하는 것입니다 __init__부모 클래스의 방법도 불린다. pickle그가 (를 포함하여 오브젝트와 연관된 모든 데이터를 저장하려고하기 때문에 예외가없는 모든 객체에 대해 설정된 필드 / 인스턴스 변수)에 의해 설정 한 것도 그래서 __init__이전의 시간이 피클 복원 할 것, 더있다 다시 전화해야합니다.

__init__대체 이니셜 라이저 를 건너 뛰고 사용하면 일종의 코드 중복이 발생합니다. 인스턴스 변수가 채워지는 두 곳이 있으며 이니셜 라이저 중 하나에서 그중 하나를 놓치거나 실수로 두 필드 채우기는 다르게 작동합니다. 이것은 추적하기가 그리 사소하지 않은 미묘한 버그의 가능성을 제공하며 ( 어떤 이니셜 라이저가 호출 되었는지 알아야 합니다) 코드를 유지하기가 더 어려워집니다. 상속을 사용하는 경우 더 큰 혼란에 빠질 것이라는 것은 말할 것도없고,이 대체 이니셜 라이저를 체인의 모든 곳에서 사용해야하기 때문에 문제는 상속 체인으로 올라갈 것입니다.

또한 그렇게함으로써 Python의 인스턴스 생성을 다소 무시하고 직접 만들 수 있습니다. 파이썬은 이미 당신을 위해 꽤 잘하고 있으며, 그것을 재발 명 할 필요가 없으며 당신의 코드를 사용하는 사람들을 혼란스럽게 할 것입니다.

대신 최선의 방법은 다음과 같습니다__init__ . 모든 인스턴스 변수를 올바르게 초기화하는 클래스의 가능한 모든 인스턴스화에 대해 호출 되는 단일 메서드를 사용합니다 . 다른 초기화 모드의 경우 두 가지 방법 중 하나를 사용하십시오.

  1. __init__선택적 인수를 사용하여 케이스를 처리하는 다른 서명을 지원 하십시오.
  2. 대체 생성자 역할을하는 여러 클래스 메서드를 만듭니다. 추가 작업 등을 수행하는 동안 Roman Bodnarchuk가 표시 한대로 모두 정상적인 방법 (예 : 호출 __init__) 으로 클래스의 인스턴스를 생성해야 합니다. 모든 데이터를 클래스에 전달하고 처리하는 것이 가장 좋지만 불가능하거나 불편한 경우 인스턴스가 생성되고 초기화가 완료된 후 일부 인스턴스 변수를 설정할 수 있습니다 .__init____init__

__init__선택적 단계가있는 경우 (예 : 해당 data인수를 처리하는 것과 같이 더 구체적이어야하지만) 선택적 인수로 만들거나 처리를 수행하는 일반 메서드를 만들 수 있습니다.


방법에 classmethod데코레이터를 사용하십시오 Load.

class B(object):    
    def __init__(self, name, data):
        self._Name = name
        #store data

    @classmethod
    def Load(cls, file, newName):
        f = open(file, "rb")
        s = pickle.load(f)
        f.close()

        return cls(newName, s)

따라서 다음을 수행 할 수 있습니다.

loaded_obj = B.Load('filename.txt', 'foo')

편집하다:

어쨌든 __init__방법 을 생략하고 싶다면 다음을 시도하십시오 __new__.

>>> class A(object):
...     def __init__(self):
...             print '__init__'
...
>>> A()
__init__
<__main__.A object at 0x800f1f710>
>>> a = A.__new__(A)
>>> a
<__main__.A object at 0x800f1fd50>

귀하의 질문을 말 그대로 메타 클래스를 사용합니다.

class MetaSkipInit(type):
    def __call__(cls):
        return cls.__new__(cls)


class B(object):
    __metaclass__ = MetaSkipInit

    def __init__(self):
        print "FAILURE"

    def Print(self):
        print "YEHAA"


b = B()
b.Print()

이것은 예를 들어 매개 변수 목록을 오염시키지 않고 생성자를 복사하는 데 유용 할 수 있습니다. 그러나 이것을 적절하게 수행하려면 내가 제안한 해킹보다 더 많은 노력과 관심이 필요합니다.


별로. 의 목적은 __init__개체를 인스턴스화하는 것이며 기본적으로 실제로는 아무 작업도 수행하지 않습니다. 는 IF __init__방법은 당신이 원하는 일을하지 않고,이 변화에 자신의 코드가 아닙니다, 당신은 비록을 전환 할 수 있습니다. 예를 들어 클래스 A를 가져 가면 해당 __init__메서드 호출을 피하기 위해 다음을 수행 할 수 있습니다 .

def emptyinit(self):
    pass
A.__init__ = emptyinit
a = A()
a.Print()

This will dynamically switch out which __init__ method from the class, replacing it with an empty call. Note that this is probably NOT a good thing to do, as it does not call the super class's __init__ method.

You could also subclass it to create your own class that does everything the same, except overriding the __init__ method to do what you want it to (perhaps nothing).

Perhaps, however, you simply wish to call the method from the class without instantiating an object. If that is the case, you should look into the @classmethod and @staticmethod decorators. They allow for just that type of behavior.

In your code you have put the @staticmethod decorator, which does not take a self argument. Perhaps what may be better for the purpose would a @classmethod, which might look more like this:

@classmethod
def Load(cls, file, newName):
    # Get the data
    data = getdata()
    # Create an instance of B with the data
    return cls.B(newName, data)

UPDATE: Rosh's Excellent answer pointed out that you CAN avoid calling __init__ by implementing __new__, which I was actually unaware of (although it makes perfect sense). Thanks Rosh!


I was reading the Python cookbook and there's a section talking about this: the example is given using __new__ to bypass __init__()

>>> class A:
    def __init__(self,a):
        self.a = a


>>> test = A('a')
>>> test.a
'a'
>>> test_noinit = A.__new__(A)
>>> test_noinit.a
Traceback (most recent call last):
  File "", line 1, in 
    test_noinit.a
AttributeError: 'A' object has no attribute 'a'
>>> 

However I think this only works in Python3. Below is running under 2.7

>>> class A:
    def __init__(self,a):
        self.a = a


>>> test = A.__new__(A)

Traceback (most recent call last):
  File "", line 1, in 
    test = A.__new__(A)
AttributeError: class A has no attribute '__new__'
>>> 

As I said in my comment you could change your __init__ method so that it allows creation without giving any values to its parameters:

def __init__(self, p0, p1, p2):
   # some logic

would become:

def __init__(self, p0=None, p1=None, p2=None):
   if p0 and p1 and p2:
       # some logic

or:

def __init__(self, p0=None, p1=None, p2=None, init=True):
    if init:
        # some logic

ReferenceURL : https://stackoverflow.com/questions/6383914/is-there-a-way-to-instantiate-a-class-without-calling-init

반응형