ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 파이썬 싱글턴(Singleton) 패턴
    파이썬 2021. 4. 25. 20:43

    싱글턴 패턴

    싱글턴은 생성패턴중 하나로, 프로그램내의 어느곳에서 접근하든지 하나의 객체만 이용하도록 만든다. 디시말하면, 싱글턴 패턴으로 구현된 클래스는 프로그램 내에서 하나의 객체만 갖는다. 생성자가 여러번 호출되더라도 실제로는 최초 호출될때 한번만 객체를 생성하고 그 이후에 생성자가 호출될 때는 이 객체를 반환한다.

     

    파이썬에서의 싱글턴 패턴

    • __new__ 메소드로 구현하기

    파이썬에서 클래스의 인스턴스 생성은 매직 메소드 __new__를 통해 이뤄진다. 이를 이용하여 다음과 같이 구현할 수 있다.

    class Singleton:
        _instance = None
    
        def __new__(cls):
            if cls._instance is None:
                cls._instance = super(Singleton, cls).__new__(cls)
    
            return cls._instance
    

     이를 상속받아 싱글턴 패턴을 따르는 클래스를 만들고 이 클래스로 생성한 인스턴스가 실제로 동일한 객체인지 확인해 보는 코드이다.

    class A(Singleton):
        def print_my_id(self):
            print(id(self))
    
    
    first_call = A()
    second_call = A()
    
    
    print(first_call)
    print(second_call)
    
    first_call.print_my_id()
    second_call.print_my_id()
    
    // 출력 결과
    <__main__.A object at 0x000002069DE31250>
    <__main__.A object at 0x000002069DE31250>
    2227441963600
    2227441963600

     

    • get_instance 메소드로 구현하기

    get_instance를 이용하여 아래처럼 Singleton 객체를 갖도록 구현할 수도 있다.

    class Singleton:
        _instance = None
        
        @classmethod
        def get_instance(cls):
            if cls._instance is None:
                cls._instance = super().__new__(cls)
    
            return cls._instance
    
    
    class A(Singleton):
        def print_my_id(self):
            print(id(self))
    
    
    first_call = A()
    second_call = A()
    
    print(first_call)
    print(second_call)
    
    first_call.get_instance().print_my_id()
    second_call.get_instance().print_my_id()
    

     

    • 메타클래스로 구현하기

    Singleton() 을 call했을때 생성된 객체가 없다면 객체를 생성하여 리턴하고, 생성된 객체가 있다면 그 객체를 리턴하면 된다. 이 기능을 파이썬의 메타클래스를 이용하여 구현할 수 있다. 메타클래스는 파이썬 클래스의 동작을 정의할 수 있고 클래스가 call될때 어떻게 동작할 것인지를 정의할 수 있다.

    class MetaSingleton(type):
        _instances = {}
    
        def __call__(cls, *args, **kwargs):
            if cls not in cls._instances:
                cls._instances[cls] = super().__call__(*args, **kwargs)
            return cls._instances[cls]
    
    
    class Singleton(metaclass=MetaSingleton):
        pass
    
    print(Singleton._instances)
    s = Singleton()
    s.variable = 10
    print(Singleton._instances)
    s1 = Singleton()
    print(Singleton._instances)
    print(s1.variable, s.variable)
    
    assert id(s) == id(s1)
    
    // 출력결과
    {}
    {<class '__main__.Singleton'>: <__main__.Singleton object at 0x0000017E6F5FB0A0>}
    {<class '__main__.Singleton'>: <__main__.Singleton object at 0x0000017E6F5FB0A0>}
    10 10

    위와같이 메타클래스의 __call__내부에 이 메타클래스를 상속받는 클래스가 call될때 생성된 객체가 없으면 객체를 생성하고 객체가 있으면 그 객체를 반환하도록 구현한다. Singleton클래스는 이 싱글턴 메타클래스를 메타클래스로 지정하여 싱글턴패턴을 따르도록 한다.

     

    참고자료

    refactoring.guru

    '파이썬' 카테고리의 다른 글

    networkx를 이용하여 multidigraph 그리기  (0) 2021.06.05

    댓글

Designed by Tistory.