SingleTon

codakcodak·2023년 10월 22일
0

OOP python

목록 보기
16/19
post-thumbnail
post-custom-banner

싱글톤

  • 하나의 클래스에 대해 어플리케이션이 시작될 때 최초 한번만 메모리를 할당하고 그 메모리에 인스턴스를 생성한다. 즉, 인스턴스를 단 하나만 생성한다.
  • 고정된 메모리영역을 얻어 하나의 인스턴스만 생성하기 때문에 메모리 낭비를 방지한다.
  • 인스턴스가 전역적으로 사용될 수 있기에 다른 클래스의 인스턴스들이 데이터를 공유하고 변경할 수 있다.
  • 멀티스레드 환경에서 데이터 동기화 문제가 발생할 수 있다

1.인스턴시에이터(Instantiator)

  • 객체를 메모리에 할당하며 직접 생성하는 메서드
  • new메서드를 통해 실제로 메모리상에 할당한다.
  • 클래스()를 실행하면 내부적으로 new 메서드부터 호출한다.
class Test:
    def __new__(cls, *args, **kwargs):
        print("im new")
        # 현재 자신인 Test를 가르킨다.
        print(cls)
        print(args)
        print(kwargs)
        # Object의 객체를 생성하고 반환(메모리에 할당하는 부분)
        obj = super().__new__(cls)
        #현재 cls인 Test를 받았기에 출력은 Test클래스로 나오지만 실제로는 Object의 객체이다.
        print("created obj", obj)
        return obj

    def __init__(self, x, y):
        # 다양한 매개변수들을 받고 인스턴스 속성들을 설정한다.
        print("im init")
        self.x = x
        self.y = y


test1 = Test(10, 20)
im new
<class '__main__.Test'>
(10, 20)
{}
created obj <__main__.Test object at 0x100977bb0>
im init

2.생성자(Constructor)

  • 인스턴스를 사용자가 원하는 대로 사용하도록 커스토마이징하는 메서드
  • init메서드를 통해 super와 다양한 매개변수를 이용하여 인스턴스 속성을 설정한다.
class Test1:
    def __init__(self, name):
        self.name = name


class Test2(Test1):
    def __init__(self, name, age):
        # 자신의 부모 클래스인 Test1을 가르킨다.
        super().__init__(name)
        self.age = age


test = Test2("steve", 20)
print(test)
print(test.name)
print(test.age)
<__main__.Test2 object at 0x103177b80>
steve
20

싱글톤생성 방법

  • 싱글톤은 메모리상에 객체가 한번만 할당되는 것이 중요하기에 new 메서드를 잘 이용해야한다.

    1. new 메서드
class SingleTon:
    def __new__(cls):
        # 아직 생성된 인스턴스가 없다면 새롭게 인스턴스를 생성
        if not hasattr(cls, "instance"):
            print("create single instance!")
            cls.instance = super().__new__(cls)
        else:
            print("use maden single instance!")
        return cls.instance

    def __init__(self):
        print("init!")


for i in range(10):
    instance = SingleTon()
    print(i, "번째 인스턴스:", instance)
create single instance!
init!
0 번째 인스턴스: <__main__.SingleTon object at 0x102967b50>
use maden single instance!
init!
1 번째 인스턴스: <__main__.SingleTon object at 0x102967b50>
use maden single instance!
init!
2 번째 인스턴스: <__main__.SingleTon object at 0x102967b50>
use maden single instance!
init!
3 번째 인스턴스: <__main__.SingleTon object at 0x102967b50>
use maden single instance!
init!
4 번째 인스턴스: <__main__.SingleTon object at 0x102967b50>
use maden single instance!
init!
5 번째 인스턴스: <__main__.SingleTon object at 0x102967b50>
use maden single instance!
init!
6 번째 인스턴스: <__main__.SingleTon object at 0x102967b50>
use maden single instance!
init!
7 번째 인스턴스: <__main__.SingleTon object at 0x102967b50>
use maden single instance!
init!
8 번째 인스턴스: <__main__.SingleTon object at 0x102967b50>
use maden single instance!
init!
9 번째 인스턴스: <__main__.SingleTon object at 0x102967b50>
    1. 클래스 메서드
class SingleTon:
    __instance = None

    #외부에서 접근 불가능한 메서드
    @classmethod
    def __getInstance(cls):
        return cls.__instance

    @classmethod
    def instance(cls, *args, **kargs):
        # 인스턴스 한 개를 할당
        cls.__instance = cls(*args, **kargs)
        # 인스턴스 한 개를 할당하는 메서드인 instance를 가져오는 메서드인 __getInstance로 대치(초기에 한번 불려오면 현재의 기능은 없어지기 때문에 메모리에 한번만 적재할 수 있다.)
        cls.instance = cls.__getInstance
        # 생성된 인스턴스 반환
        return cls.__instance


for i in range(10):
    instance = SingleTon.instance()
    print(i, "번째 인스턴스:", instance)
0 번째 인스턴스: <__main__.SingleTon object at 0x100fa3af0>
1 번째 인스턴스: <__main__.SingleTon object at 0x100fa3af0>
2 번째 인스턴스: <__main__.SingleTon object at 0x100fa3af0>
3 번째 인스턴스: <__main__.SingleTon object at 0x100fa3af0>
4 번째 인스턴스: <__main__.SingleTon object at 0x100fa3af0>
5 번째 인스턴스: <__main__.SingleTon object at 0x100fa3af0>
6 번째 인스턴스: <__main__.SingleTon object at 0x100fa3af0>
7 번째 인스턴스: <__main__.SingleTon object at 0x100fa3af0>
8 번째 인스턴스: <__main__.SingleTon object at 0x100fa3af0>

성능비교

  • new를 이용한 방법이 class method방법보다 메모리를 적게 사용한다.
  • class method방법이 new를 이용한 방법보다 실생시간이 짧다.
from memory_profiler import profile
import time


class SingleTon1:
    def __new__(cls):
        # 아직 생성된 인스턴스가 없다면 새롭게 인스턴스를 생성
        if not hasattr(cls, "instance"):
            cls.instance = super().__new__(cls)
        return cls.instance


class SingleTon2:
    __instance = None

    # 외부에서 접근 불가능한 메서드
    @classmethod
    def __getInstance(cls):
        return cls.__instance

    @classmethod
    def instance(cls, *args, **kargs):
        # 인스턴스 한 개를 할당
        cls.__instance = cls(*args, **kargs)
        # 인스턴스 한 개를 할당하는 메서드인 instance를 가져오는 메서드인 __getInstance로 대치(초기에 한번 불려오면 현재의 기능은 없어지기 때문에 메모리에 한번만 적재할 수 있다.)
        cls.instance = cls.__getInstance
        # 생성된 인스턴스 반환
        return cls.__instance


loop = 1000000


@profile
def useNew():
    for i in range(loop):
        instance = SingleTon1()


@profile
def useClassMethod():
    for i in range(loop):
        instance = SingleTon2.instance()


def execute_time_new():
    for i in range(loop):
        instance = SingleTon1()


def execute_class_method():
    for i in range(loop):
        instance = SingleTon2.instance()


print("===================Memory compare===================")
print("-------------------with new")
useNew()
print("-------------------with ClassMethod")
useClassMethod()

print("===================Execute Time compare===================")
print("-------------------with new")
start = time.time()
execute_time_new()
print("time :", time.time() - start)
print("-------------------with ClassMethod")
start = time.time()
execute_class_method()
print("time :", time.time() - start)
===================Memory compare===================
-------------------with new
Filename: 
경로생략

Line #    Mem usage    Increment  Occurrences   Line Contents
=============================================================
    62     20.3 MiB     20.3 MiB           1   @profile
    63                                         def useNew():
    64     20.4 MiB      0.1 MiB     1000001       for i in range(loop):
    65     20.4 MiB      0.1 MiB     1000000           instance = SingleTon1()


-------------------with ClassMethod
Filename: 
경로생략

Line #    Mem usage    Increment  Occurrences   Line Contents
=============================================================
    68     20.5 MiB     20.5 MiB           1   @profile
    69                                         def useClassMethod():
    70     20.5 MiB      0.0 MiB     1000001       for i in range(loop):
    71     20.5 MiB      0.0 MiB     1000000           instance = SingleTon2.instance()


===================Execute Time compare===================
-------------------with new
time : 0.09079909324645996
-------------------with ClassMethod
time : 0.07572388648986816
profile
숲을 보는 코더
post-custom-banner

0개의 댓글