이 프로젝트는 Python에서 싱글톤 클래스를 생성하기 위한 Singleton 및 TtlSingleton 메타클래스를 제공합니다. TtlSingleton 메타클래스는 Singleton 기능을 확장하여 지정된 시간이 지나면 인스턴스가 만료되는 TTL(Time-To-Live) 기능을 추가합니다.
- Singleton: 클래스 이름과 초기화 매개변수가 동일한 경우 하나의 인스턴스만 생성되도록 보장합니다.
- TtlSingleton:
Singleton을 확장하여 TTL을 지원하며, 지정된 시간이 지나면 인스턴스가 만료되고 새로 생성됩니다. - 두 클래스 모두
use_class_name_only매개변수를 true로 지정하면 초기화 매개변수와 관계없이 클래스 이름만으로 싱글톤을 생성할 수 있습니다. (전통적인 싱글톤과 동일)
pip install advanced-python-singleton` 이 프로젝트를 사용하려면 저장소를 클론하고 필요한 종속성을 설치하십시오:
git clone https://github.com/jogakdal/advanced-singleton.git
cd <repository-directory>
pip install -r requirements.txt- 싱글톤 클래스를 생성하려면
Singleton메타 클래스로 지정해 주면 됩니다. use_class_name_only매개변수를 true로 지정하면 초기화 매개변수와 관계없이 클래스 이름만으로 싱글톤을 생성합니다. (전통적인 싱글톤과 동일, default는 false)
from advanced_python_singleton.singleton import Singleton
class SomeClass(metaclass=Singleton):
def __init__(self, name):
self.name = name- TTL 기반 싱글톤 클래스를 생성하려면
TtlSingleton메타클래스를 사용하고ttl매개변수를 지정해 주세요. - ttl 매개변수는 인스턴스가 만료되기까지의 시간(초)을 나타냅니다. default는 60초입니다.
use_class_name_only매개변수를 true로 지정하면 초기화 매개변수와 관계없이 클래스 이름만으로 싱글톤을 생성합니다. (전통적인 싱글톤과 동일, default는 false)
from advanced_python_singleton.ttlsingleton import TtlSingleton
class SomeClass(metaclass=TtlSingleton, ttl=10):
def __init__(self, name):
self.name = name다음은 TtlSingleton 사용법을 보여주는 예제입니다:
import time
from advanced_python_singleton.singleton import Singleton
from advanced_python_singleton.ttlsingleton import TtlSingleton
# Singleton 테스트
class SingletonWithParamExample(metaclass=Singleton):
def __init__(self, name):
self.name = name
print(f'{self.name}({self}) is created')
class SingletonWithoutParamExample(metaclass=Singleton, use_class_name_only=True):
def __init__(self, name):
self.name = name
print(f'{self.name}({self}) is created')
a = SingletonWithParamExample('a')
b = SingletonWithParamExample('b')
c = SingletonWithParamExample('a')
assert a != b
assert a == c
assert b == SingletonWithParamExample('b')
a = SingletonWithoutParamExample('a')
b = SingletonWithoutParamExample('b')
assert a == b
assert a == SingletonWithoutParamExample('c')
# TtlSingleton 테스트
class TtlSingletonExample(metaclass=TtlSingleton, ttl=2):
def __init__(self, name):
self.name = name
print(f' {self.name} is created')
class SingletonTest():
def test(self, p):
return TtlSingletonExample(p)
print('a creating')
a = TtlSingletonExample('a')
assert a.name == 'a'
print('b creating')
b = TtlSingletonExample('b')
assert b.name == 'b'
print('sleep 1 sec')
time.sleep(1)
print('a creating')
c = TtlSingletonExample('a')
assert a == c
assert c.name == 'a'
print('sleep 2 sec')
time.sleep(2)
print('a creating')
d = TtlSingletonExample('a')
assert a != d # 시간이 2초 이상 지났음으로 새로운 객체 생성
print('a creating via SingletonTest()')
assert d == SingletonTest().test('a')
print('sleep 2 sec')
time.sleep(2)
print('a creating via SingletonTest()')
e = SingletonTest().test('a')
assert d != e
print('a creating')
assert e == TtlSingletonExample('a')
# TTL이 서로 다른 클래스 테스트
class TtlSingletonExample_5(metaclass=TtlSingleton, ttl=5):
def __init__(self, name):
self.name = name
class TtlSingletonExample_8(metaclass=TtlSingleton, ttl=8):
def __init__(self, name):
self.name = name
a = TtlSingletonExample_5('a')
b = TtlSingletonExample_8('a')
assert a != b
time.sleep(6)
c = TtlSingletonExample_5('a')
d = TtlSingletonExample_8('a')
assert a != c
assert b == d
time.sleep(3)
assert c == TtlSingletonExample_5('a')
assert d != TtlSingletonExample_8('a')
# use_class_name_only=True 테스트
class SingletonClassNameOnly(metaclass=TtlSingleton, ttl=60, use_class_name_only=True):
def __init__(self, name, value):
self.name = name
self.value = value
instance1 = SingletonClassNameOnly('test', 123)
instance2 = SingletonClassNameOnly('test', 456)
assert instance1 == instance2
assert instance1.value == 123
assert instance2.value == 123
# 인자 관련 테스트
class SomeClass(metaclass=Singleton):
def __init__(self, user_name, user_id=0):
self.user_name = user_name
self.user_id = user_id
class AnotherClass(metaclass=Singleton):
def __init__(self, user_name, user_id=0):
self.user_name = user_name
self.user_id = user_id
assert SomeClass('abc', 1) == SomeClass('abc', 1) # 클래스 명과 인자가 모두 같으면 같은 인스턴스가 되어야 한다.
assert SomeClass('abc', 1) != AnotherClass('abc', 1) # 클래스 명이 다르면 다른 인스턴스가 되어야 한다.
assert SomeClass('abc', user_id=1) == SomeClass('abc', 1) # 명시적 파라미터로 전달되어도 값이 같으면 같은 인스턴스가 되어야 한다.
assert SomeClass('abc', 1) != SomeClass('abc', 2) # 파라미터 값이 하나라도 다르면 다른 인스턴스가 되어야 한다.
assert SomeClass('abc', user_id=1) != SomeClass('abc', 2) # 파라미터 값이 하나라도 다르면 다른 인스턴스가 되어야 한다.
assert SomeClass('abc') == SomeClass('abc', 0) # 파라미터 디폴트 값과 동일한 값으로 전달되면 같은 인스턴스가 되어야 한다.
assert SomeClass('abc') != SomeClass('abc', 1) # 파라미터 디폴트 값과 다른 값으로 전달되면 다른 인스턴스가 되어야 한다.
assert SomeClass('abc') == SomeClass('abc', user_id=0) # 파라미터 디폴트 값과 동일한 값이 명시적으로 전달되어도 같은 인스턴스가 되어야 한다.이 라이브러리는 누구나 사용할 수 있는 프리 소프트웨어입니다. 다만 코드를 수정할 경우 변경된 내용을 원작성자에게 통보해 주시면 감사하겠습니다.
황용호(jogakdal@gmail.com)