Python에서 싱글톤 만들기
이 질문은 싱글톤 디자인 패턴이 바람직한지, 반(反) 패턴인지, 종교 전쟁인지에 대한 토론이 아니라, 이 패턴이 파이썬에서 가장 피톤적인 방식으로 어떻게 구현되는지에 대한 토론입니다. 이 경우 나는 '가장 놀라운 것'을 '최소한의 놀라움'의 원칙을 따른다는 의미로 정의한다.
싱글톤이 되는 클래스가 여러 개 있습니다(로거에 대한 사용 사례는 있지만 이는 중요하지 않습니다).단순히 상속이나 장식을 할 수 있을 때 gumph가 추가된 여러 클래스를 난잡하게 만들고 싶지 않습니다.
최적의 방법:
방법 1: 데코레이터
def singleton(class_):
instances = {}
def getinstance(*args, **kwargs):
if class_ not in instances:
instances[class_] = class_(*args, **kwargs)
return instances[class_]
return getinstance
@singleton
class MyClass(BaseClass):
pass
장점
- 데코레이터는 종종 다중 상속보다 직관적인 방식으로 가법적입니다.
단점
를 사용하여
MyClass()
한 입니다.MyClass
그 자체는 클래스가 아닌 함수이기 때문에 클래스 메서드를 호출할 수 없습니다., ,의 경우,x = MyClass(); y = MyClass(); t = type(n)();
x == y
x != t && y != t
방법 2: 기본 클래스
class Singleton(object):
_instance = None
def __new__(class_, *args, **kwargs):
if not isinstance(class_._instance, class_):
class_._instance = object.__new__(class_, *args, **kwargs)
return class_._instance
class MyClass(Singleton, BaseClass):
pass
장점
- 참다운 수업이다
단점
- 중중중 - !!!
__new__
두 번째 기본 클래스에서 상속하는 동안 덮어쓸 수 있습니까?하다
방법 3: 메타클래스
class Singleton(type):
_instances = {}
def __call__(cls, *args, **kwargs):
if cls not in cls._instances:
cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs)
return cls._instances[cls]
#Python2
class MyClass(BaseClass):
__metaclass__ = Singleton
#Python3
class MyClass(BaseClass, metaclass=Singleton):
pass
장점
- 참다운 수업이다
- 상속을 자동으로 커버
__metaclass__
해주었다 (적절한 .
단점
- 있어요?
방법 4: 같은 이름의 클래스를 반환하는 데코레이터
def singleton(class_):
class class_w(class_):
_instance = None
def __new__(class_, *args, **kwargs):
if class_w._instance is None:
class_w._instance = super(class_w,
class_).__new__(class_,
*args,
**kwargs)
class_w._instance._sealed = False
return class_w._instance
def __init__(self, *args, **kwargs):
if self._sealed:
return
super(class_w, self).__init__(*args, **kwargs)
self._sealed = True
class_w.__name__ = class_.__name__
return class_w
@singleton
class MyClass(BaseClass):
pass
장점
- 참다운 수업이다
- 상속을 자동으로 커버
단점
- 새 클래스를 만들 때마다 오버헤드가 발생하지 않습니까?여기에서는 싱글톤을 만들고 싶은 클래스마다 2개의 클래스를 만들고 있습니다.제 경우는 괜찮지만, 확장성이 떨어지는 것은 아닌지 걱정입니다.물론 이 패턴을 확대하는 것이 너무 쉬운지에 대해서는 논란의 여지가 있다.
- 의 요점은 무엇입니까?
_sealed
- 할 수
super()
커스터마이즈할 수 없다는 입니다.__new__
수 .__init__
.
방법 5: 모듈
파일 '''」singleton.py
장점
- 단순한 것이 복잡한 것보다 낫다
단점
- 게으르게 인스턴스화되지 않음
메타클래스 사용
Method #2를 추천하지만 기본 클래스보다는 메타클래스를 사용하는 것이 좋습니다.다음으로 구현 예를 제시하겠습니다.
class Singleton(type):
_instances = {}
def __call__(cls, *args, **kwargs):
if cls not in cls._instances:
cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs)
return cls._instances[cls]
class Logger(object):
__metaclass__ = Singleton
또는 Python3에서는
class Logger(metaclass=Singleton):
pass
「」를 경우__init__
부를 마다 덧셈하다
else:
cls._instances[cls].__init__(*args, **kwargs)
if
입니다.Singleton.__call__
.
메타클래스에 대해 몇 마디 하겠습니다.메타클래스는 클래스의 클래스입니다.즉, 클래스는 메타클래스의 인스턴스입니다.Python에서 객체의 메타클래스를 찾을 수 있습니다.type(obj)
. 일반 신식 클래스는 유형입니다.type
Logger
에서는 타입이 「유형」이.class 'your_module.Singleton'
"" (") " " " " " 입니다.Logger
이 될 것이다class 'your_module.Logger'
에 「」를 붙여 콜 Logger()
Python의 Logger
,Singleton
수 이 에게 "Python"을 호출하여 .__getattr__
중 할 때, 그 속성 중 하나를 할 수 있습니다.myclass.attribute
.
메타클래스는 기본적으로 클래스의 정의가 무엇을 의미하며 그 정의를 구현하는 방법을 결정합니다.C-style을 기본적으로 재생성하는 예를 들어 http://code.activestate.com/recipes/498149/,을 참조하십시오.struct
메타클래스를 사용하여 Python에서 s를 실행합니다.스레드 메타클래스의 (구체적인) 사용 사례는 무엇입니까?는 몇 가지 예를 제시합니다.일반적으로 선언형 프로그래밍과 관련된 것 같습니다.특히 ORM에서 사용되는 경우입니다.
이 상황에서 메서드 #2를 사용하여 서브클래스가 정의되어 있는 경우__new__
메서드, 호출할 때마다 실행됩니다.SubClassOfSingleton()
--저장된 인스턴스를 반환하는 메서드를 호출하기 때문입니다.메타클래스를 사용하면 인스턴스가 하나밖에 생성되지 않을 때 한 번만 호출됩니다.클래스 유형에 따라 결정되는 클래스라는 의미를 사용자 정의하려고 합니다.
일반적으로 메타클래스를 사용하여 싱글톤을 구현하는 것이 좋습니다.싱글톤은 한 번만 작성되기 때문에 특별하며 메타클래스는 클래스 작성을 커스터마이즈하는 방법입니다.메타클래스를 사용하면 싱글톤 클래스 정의를 다른 방법으로 커스터마이즈해야 할 경우에 대비하여 보다 많은 제어를 할 수 있습니다.
metaclass는 기본 클래스가 아니기 때문에 singleton에는 다중 상속이 필요하지 않지만 다중 상속을 사용하는 클래스의 하위 클래스에 대해서는 singleton 클래스가 metaclass를 재정의하는 첫 번째/왼쪽 클래스인지 확인해야 합니다.__call__
이것은 문제가 될 가능성이 매우 낮다.인스턴스 dict가 인스턴스의 네임스페이스에 없으므로 실수로 덮어쓰지 않습니다.
또한 싱글톤 패턴이 "단일 책임 원칙"에 위배된다는 것을 듣게 될 것입니다. 각 클래스는 한 가지 일만 해야 합니다.이렇게 하면 다른 코드를 변경해야 할 때 코드 하나가 망칠 염려가 없어집니다. 왜냐하면 코드들은 분리되어 캡슐화되어 있기 때문입니다.메타클래스 실장은 이 테스트에 합격했습니다.메타클래스는 패턴 적용을 담당하며 생성된 클래스 및 서브클래스는 싱글톤임을 인식할 필요가 없습니다.메서드 #1은 "MyClass 자체는 클래스가 아닌 함수이므로 클래스에서 클래스 메서드를 호출할 수 없습니다."에서 설명한 바와 같이 이 테스트에서 실패합니다.
Python 2 및 3 호환 버전
Python2와 3으로 동작하는 것을 쓰려면 조금 더 복잡한 방식을 사용해야 합니다.이기 때문에type
실행 시 중간 베이스 클래스를 메타클래스로 동적으로 만들고 이를 퍼블릭의 베이스 클래스로 사용할 수 있습니다.Singleton
하는 것이 더 에서 설명하겠습니다.다음 예시와 같이 설명하는 것보다 설명하는 것이 더 어렵습니다.
# works in Python 2 & 3
class _Singleton(type):
""" A metaclass that creates a Singleton base class when called. """
_instances = {}
def __call__(cls, *args, **kwargs):
if cls not in cls._instances:
cls._instances[cls] = super(_Singleton, cls).__call__(*args, **kwargs)
return cls._instances[cls]
class Singleton(_Singleton('SingletonMeta', (object,), {})): pass
class Logger(Singleton):
pass
이 접근방식의 아이러니한 점은 메타클래스를 구현하기 위해 서브클래싱을 사용한다는 것입니다.한 가지 가능한 장점은 순수 메타클래스와는 달리isinstance(inst, Singleton)
True
.
수정
또 다른 토픽에서는 이미 알고 계시겠지만, 원래 포스트에 기재되어 있던 기본 클래스의 실장은 잘못되어 있습니다. _instances
클래스에서 참조할 필요가 있습니다.super()
아니면 재발하고 있는 거고__new__
는 실제 클래스가 아직 생성되지 않았기 때문에 클래스 메서드가 아닌 실제로 전달해야 하는 정적 메서드입니다.이 모든 것은 메타클래스 구현에도 해당됩니다.
class Singleton(object):
_instances = {}
def __new__(class_, *args, **kwargs):
if class_ not in class_._instances:
class_._instances[class_] = super(Singleton, class_).__new__(class_, *args, **kwargs)
return class_._instances[class_]
class MyClass(Singleton):
pass
c = MyClass()
A클래스를 반환하는 데코레이터
제가 원래 댓글을 쓰려고 했는데 너무 길어서 여기에다가 넣도록 하겠습니다.Method #4는 다른 데코레이터 버전보다 낫지만 싱글톤에 필요한 것보다 더 많은 코드이며, 어떤 기능을 하는지 명확하지 않습니다.
주요 문제는 클래스가 자신의 기본 클래스이기 때문에 발생합니다.가 거의 있고, 같은 의 서브클래스로 있는 ?__class__
속성?이는 기본 클래스에서 같은 이름의 메서드를 호출하는 메서드를 정의할 수 없음을 의미합니다.super()
이 에서 커스터마이즈할 수 뜻입니다.__new__
어떤 로부터도 파생될 수 .__init__
그들을 방문했습니다.
싱글톤 패턴을 사용하는 경우
싱글톤을 사용하고 싶은 경우의 좋은 예 중 하나가 바로 이 유스케이스입니다.댓글 중 하나에서 "나에게 로깅은 항상 싱글톤의 자연스러운 후보처럼 보였다"고 말합니다.당신이 전적으로 옳아요.
사람들이 싱글톤이 나쁘다고 말할 때, 가장 일반적인 이유는 그들이 암묵적인 공유 상태이기 때문입니다.글로벌 변수 및 최상위 모듈의 Import는 명시적인 공유 상태이지만 전달되는 다른 오브젝트는 일반적으로 인스턴스화됩니다.이것은 두 가지 예외를 제외하고는 좋은 점이다.
첫 번째, 그리고 여러 곳에서 언급되는 것은 싱글톤이 일정할 때입니다.글로벌 상수(특히 enum)의 사용은 널리 받아들여지고 있으며, 어떤 경우에도 다른 사용자에게 혼란을 줄 수 없기 때문에 정상으로 간주됩니다.이것은 항상 싱글톤에 대해서도 마찬가지입니다.
두 번째 예외는 그 반대입니다.싱글톤이 데이터 소스(직접 또는 간접)가 아닌 데이터 싱크일 경우입니다.이것이 벌목꾼들이 싱글톤의 "자연스러운" 사용이라고 느끼는 이유입니다.다양한 사용자가 다른 사용자가 관심을 갖는 방식으로 로거를 변경하지 않기 때문에 실제로 공유 상태는 없습니다.이로 인해 싱글톤 패턴에 대한 프라이머리 인수는 무효가 됩니다.또, 작업에 사용하기 쉽기 때문에, 이러한 인수는 합리적인 선택이 됩니다.
다음은 http://googletesting.blogspot.com/2008/08/root-cause-of-singletons.html에서 인용한 내용입니다.
싱글톤은 한 종류로 괜찮습니다.이는 도달 가능한 모든 객체가 불변인 싱글톤입니다.모든 객체가 불변의 경우 모든 것이 일정하기 때문에 Singleton보다 더 큰 전역 상태는 없습니다.하지만 이런 싱글톤을 변이 가능한 것으로 만드는 것은 매우 간단합니다. 매우 미끄러운 경사면입니다.그래서 저도 이 싱글톤에 반대합니다.나쁘기 때문이 아니라 나빠지기 쉽기 때문입니다.(한마디로 Java 열거는 이러한 종류의 싱글톤에 불과합니다.주의 사항을 열거하지 않는 한, 당신은 괜찮습니다.그러지 말아 주세요.)
반수용 가능한 다른 종류의 싱글톤은 코드 실행에 영향을 미치지 않고 "부작용"이 없습니다.로깅은 완벽한 예입니다.싱글톤과 글로벌 상태가 로딩됩니다.특정 로거가 유효하게 되어 있는지 아닌지에 관계없이, 애플리케이션의 동작은 변화하지 않기 때문에(와 같이) 허용됩니다.이 정보는 어플리케이션에서 로거로 한 방향으로 흐릅니다.로거에서 어플리케이션으로 정보가 흐르지 않기 때문에 로거가 글로벌 상태라고 생각되더라도 로거는 허용됩니다.테스트에서 로그가 기록되고 있다고 단언하려면 로거를 삽입해야 합니다.그러나 일반적으로 로거는 상태가 가득 차도 해가 되지 않습니다.
class Foo(object):
pass
some_global_variable = Foo()
모듈은 한 번만 Import되며, 다른 모든 것은 지나치게 고려됩니다.싱글톤을 사용하지 말고 글로벌을 사용하지 않도록 하세요.
모듈을 사용합니다.1회만 Import 됩니다.여기서 몇 가지 글로벌 변수를 정의하십시오. 싱글톤의 '속성'이 됩니다.싱글톤의 '방법'이라는 기능을 추가합니다.
Python에서는 아마 싱글톤이 필요 없을 겁니다.모듈 내의 모든 데이터와 함수를 정의하기만 하면 다음과 같은 사실상의 싱글톤을 얻을 수 있습니다.
import datetime
file_name=None
def set_file_name(new_file_name: str):
global file_name
file_name=new_file_name
def write(message: str):
global file_name
if file_name:
with open(file_name, 'a+') as f:
f.write("{} {}\n".format(datetime.datetime.now(), message))
else:
print("LOG: {}", message)
사용 방법:
import log
log.set_file_name("debug.log")
log.write("System starting")
...
꼭 싱글톤 수업을 들어야 한다면, 저는 다음 수업을 듣겠습니다.
class MySingleton(object):
def foo(self):
pass
my_singleton = MySingleton()
사용 방법:
from mysingleton import my_singleton
my_singleton.foo()
서 ''는mysingleton.py
「」라고 하는 입니다.MySingleton
을 사용하다이것은 파일을 처음 Import한 후 Python이 코드를 다시 실행하지 않기 때문에 작동합니다.
여기 한 가지 소개가 있습니다.
singleton = lambda c: c()
사용 방법은 다음과 같습니다.
@singleton
class wat(object):
def __init__(self): self.x = 1
def get_x(self): return self.x
assert wat.get_x() == 1
객체가 빠르게 인스턴스화됩니다.이것은 당신이 원하는 것일 수도 있고 아닐 수도 있습니다.
스택 오버플로우 질문 확인 Python에서 싱글톤을 단순하고 우아하게 정의할 수 있는 방법이 있습니까?다양한 솔루션을 제공합니다.
Python의 디자인 패턴에 관한 Alex Martelli의 강연(파트 1과 파트 2)을 보는 것을 강력히 추천합니다.특히 파트 1에서는 싱글톤/공유 상태 객체에 대해 설명합니다.
- args 또는 kwargs가 다른 경우에만 동일한 클래스의 인스턴스를 여러 개 가지고 싶을 경우 서드파티제의 python 핸디 Decorators(패키지)를 사용할 수 있습니다.
decorators
를 참조해 주세요. - ②.
- 「」를 취급하는 가 .
serial
로서 시리얼 포트를하려면 , - 위의 데코레이터를 사용하여 arg가 다른 경우 클래스의 여러 인스턴스를 만들 수 있습니다.
- 같은 arg의 경우 데코레이터는 이미 작성된 동일한 인스턴스를 반환합니다.
- 「」를 취급하는 가 .
>>> from decorators import singleton
>>>
>>> @singleton
... class A:
... def __init__(self, *args, **kwargs):
... pass
...
>>>
>>> a = A(name='Siddhesh')
>>> b = A(name='Siddhesh', lname='Sathe')
>>> c = A(name='Siddhesh', lname='Sathe')
>>> a is b # has to be different
False
>>> b is c # has to be same
True
>>>
함수 속성을 사용하는 것도 매우 간단합니다.
def f():
if not hasattr(f, 'value'):
setattr(f, 'value', singletonvalue)
return f.value
여기 싱글톤이 있습니다., '싱글톤'을 .Instance
들어 하다
@Singleton
class Foo:
def __init__(self):
print 'Foo created'
f = Foo() # Error, this isn't how you get the instance of a singleton
f = Foo.Instance() # Good. Being explicit is in line with the Python Zen
g = Foo.Instance() # Returns already created instance
print f is g # True
코드는 다음과 같습니다.
class Singleton:
"""
A non-thread-safe helper class to ease implementing singletons.
This should be used as a decorator -- not a metaclass -- to the
class that should be a singleton.
The decorated class can define one `__init__` function that
takes only the `self` argument. Other than that, there are
no restrictions that apply to the decorated class.
To get the singleton instance, use the `Instance` method. Trying
to use `__call__` will result in a `TypeError` being raised.
Limitations: The decorated class cannot be inherited from.
"""
def __init__(self, decorated):
self._decorated = decorated
def Instance(self):
"""
Returns the singleton instance. Upon its first call, it creates a
new instance of the decorated class and calls its `__init__` method.
On all subsequent calls, the already created instance is returned.
"""
try:
return self._instance
except AttributeError:
self._instance = self._decorated()
return self._instance
def __call__(self):
raise TypeError('Singletons must be accessed through `Instance()`.')
def __instancecheck__(self, inst):
return isinstance(inst, self._decorated)
나는 매우 명확하고 알기 쉬운 이 해결책을 선호한다.예를 들어 다른 스레드가 이미 작성한 경우 이중 검사를 사용합니다.기타 고려해야 할 사항은 역직렬화로 인해 다른 인스턴스가 생성되지 않는지 확인하는 것입니다.https://gist.github.com/werediver/4396488
import threading
# Based on tornado.ioloop.IOLoop.instance() approach.
# See https://github.com/facebook/tornado
class SingletonMixin(object):
__singleton_lock = threading.Lock()
__singleton_instance = None
@classmethod
def instance(cls):
if not cls.__singleton_instance:
with cls.__singleton_lock:
if not cls.__singleton_instance:
cls.__singleton_instance = cls()
return cls.__singleton_instance
if __name__ == '__main__':
class A(SingletonMixin):
pass
class B(SingletonMixin):
pass
a, a2 = A.instance(), A.instance()
b, b2 = B.instance(), B.instance()
assert a is a2
assert b is b2
assert a is not b
print('a: %s\na2: %s' % (a, a2))
print('b: %s\nb2: %s' % (b, b2))
from functools import cache
@cache
class xxx:
....
아주 쉽고 효과적이야!
클래스 변수 사용(데코레이터 없음)
「 」를 합니다.__new__
method를 사용하여 클래스의 동일한 인스턴스를 반환합니다.클래스를 처음 초기화하기 위한 부울:
class SingletonClass:
_instance = None
def __new__(cls, *args, **kwargs):
# If no instance of class already exits
if cls._instance is None:
cls._instance = object.__new__(cls)
cls._instance._initialized = False
return cls._instance
def __init__(self, *args, **kwargs):
if self._initialized:
return
self.attr1 = args[0]
# set the attribute to `True` to not initialize again
self._initialized = True
Method 3은 매우 깔끔해 보이지만 Python 2와 Python 3 모두에서 프로그램을 실행하고 싶다면 작동하지 않습니다.Python 3 버전은 Python 2에서 구문 오류를 발생시키기 때문에 Python 버전에 대한 테스트를 통해 별도의 변형을 보호하는 것조차 실패합니다.
Mike Watkins http://mikewatkins.ca/2008/11/29/python-2-and-3-metaclasses/ 님께 감사드립니다.Python 2와 Python 3 모두에서 프로그램을 작동시키려면 다음과 같은 작업을 수행해야 합니다.
class Singleton(type):
_instances = {}
def __call__(cls, *args, **kwargs):
if cls not in cls._instances:
cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs)
return cls._instances[cls]
MC = Singleton('MC', (object), {})
class MyClass(MC):
pass # Code for the class implementation
과제의 'object'를 'BaseClass'로 대체할 필요가 있다고 생각합니다만, 아직 시도하지 않았습니다(그림과 같이 코드를 사용해 보았습니다).
나는 링에 내 것을 던질 것이다.간단한 장식품입니다.
from abc import ABC
def singleton(real_cls):
class SingletonFactory(ABC):
instance = None
def __new__(cls, *args, **kwargs):
if not cls.instance:
cls.instance = real_cls(*args, **kwargs)
return cls.instance
SingletonFactory.register(real_cls)
return SingletonFactory
# Usage
@singleton
class YourClass:
... # Your normal implementation, no special requirements.
다른 솔루션에 비해 다음과 같은 이점이 있다고 생각합니다.
- 그것은 (내 눈에는) 명료.
- 그 액션은 완전히 캡슐화되어 있습니다. 해서 꼭
YourClass
여기에는 클래스용으로 메타클래스를 사용할 필요가 없습니다(위의 메타클래스는 "진짜" 클래스가 아니라 공장 출하 시입니다). - 원숭이를 잡아채는 데 의존하지 않습니다.
- 발신자에게는 투과적입니다.
- 는, 「Import」라고 하는 것만으로 Import 할 수 .
YourClass
클래스처럼 보이고(그렇게 되어있기 때문에), 통상은 사용하고 있습니다.발신자를 공장 출하시의 기능에 적응시킬 필요는 없습니다. - what?
YourClass()
인스턴스화는 여전히 의 실제 사례입니다.YourClass
어떤 종류의 대리인이 아니라 당신이 시행했으니까 부작용은 없을 겁니다 isinstance(instance, YourClass)
, 같은 이 비트는 Python 2.6합니다).「 abc 」 、 「 Python < 2 」6시)
- 는, 「Import」라고 하는 것만으로 Import 할 수 .
한 가지 단점이 있습니다.실제 클래스의 클래스 메서드 및 스태틱메서드는 공장 클래스를 통해 투과적으로 호출할 수 없습니다.는 이 하지 않아를 사용하여 쉽게 할 수 이다.__getattr__()
액세스를 realclass.all-ish Atribute에 합니다.
내가 실제로 더 유용하다고 느낀 관련 패턴은 (이런 종류의 것이 매우 자주 필요하다고 말하는 것은 아니다) 같은 인수로 클래스를 인스턴스화하면 같은 인스턴스가 반환되는 "독특한" 패턴입니다.즉, "인수당 싱글톤"입니다.위의 내용은 이에 잘 적응하고 더욱 간결해집니다.
def unique(real_cls):
class UniqueFactory(ABC):
@functools.lru_cache(None) # Handy for 3.2+, but use any memoization decorator you like
def __new__(cls, *args, **kwargs):
return real_cls(*args, **kwargs)
UniqueFactory.register(real_cls)
return UniqueFactory
이 모든 것은, 만약 당신이 이것들 중 하나가 필요하다고 생각한다면, 당신은 아마도 잠시 멈추고 정말로 필요한지를 자문해야 한다는 일반적인 조언에 동의합니다. 99%의 경우, YAGNI.
메타클래스를 사용한 우아한 솔루션을 추천합니다.
class Singleton(type):
# Inherit from "type" in order to gain access to method __call__
def __init__(self, *args, **kwargs):
self.__instance = None # Create a variable to store the object reference
super().__init__(*args, **kwargs)
def __call__(self, *args, **kwargs):
if self.__instance is None:
# if the object has not already been created
self.__instance = super().__call__(*args, **kwargs) # Call the __init__ method of the subclass (Spam) and save the reference
return self.__instance
else:
# if object (Spam) reference already exists; return it
return self.__instance
class Spam(metaclass=Singleton):
def __init__(self, x):
print('Creating Spam')
self.x = x
if __name__ == '__main__':
spam = Spam(100)
spam2 = Spam(200)
출력:
Creating Spam
출력에서 알 수 있듯이 1개의 오브젝트만 인스턴스화 됩니다.
모듈 레벨의 글로벌화에 관한 일반적인 Phythonic의 제안에 동의하는 것 외에 다음과 같은 것은 어떻습니까.
def singleton(class_):
class class_w(class_):
_instance = None
def __new__(class2, *args, **kwargs):
if class_w._instance is None:
class_w._instance = super(class_w, class2).__new__(class2, *args, **kwargs)
class_w._instance._sealed = False
return class_w._instance
def __init__(self, *args, **kwargs):
if self._sealed:
return
super(class_w, self).__init__(*args, **kwargs)
self._sealed = True
class_w.__name__ = class_.__name__
return class_w
@singleton
class MyClass(object):
def __init__(self, text):
print text
@classmethod
def name(class_):
print class_.__name__
x = MyClass(111)
x.name()
y = MyClass(222)
print id(x) == id(y)
출력:
111 # the __init__ is called only on the 1st time
MyClass # the __name__ is preserved
True # this is actually the same instance
이거 어때:
def singleton(cls):
instance=cls()
cls.__new__ = cls.__call__= lambda cls: instance
cls.__init__ = lambda self: None
return instance
싱글톤이어야 할 클래스의 장식가로 사용하세요.다음과 같이 합니다.
@singleton
class MySingleton:
#....
은 '비슷하다'와.singleton = lambda c: c()
데코레이터가 또 다른 대답입니다.솔루션과 이름이 (</FONT CHANGE:>MySingleton
이할 수 .클래스에서 실제로 유일한 를 할 수 MySingleton()
해서 가 더 됩니다type(MySingleton)()
(어느 쪽인가 하면)
이 답은 당신이 원하는 것이 아닐 것입니다.저는 그 물건만이 정체성을 갖는다는 의미에서 싱글톤을 원했습니다. 비교해서 말이죠.내 경우 Sentinel Value로 사용되고 있었다.답은 매우 간단하지만, 어떤 오브젝트라도 만듭니다.mything = object()
그리고 비단뱀의 천성으로, 오직 그것만이 정체성을 가질 것이다.
#!python
MyNone = object() # The singleton
for item in my_list:
if item is MyNone: # An Example identity comparison
raise StopIteration
싱글톤 패턴을 잘못 이해한 것 같습니다만, 저의 해결책은 심플하고 실용적입니다(피톤?).이 코드는 두 가지 목표를 채웁니다.
- 의 인스턴스를 만듭니다.
Foo
어디에서나 액세스 할 수 있습니다(글로벌). - 한 .
Foo
존재할 수 있습니다.
이게 암호야.
#!/usr/bin/env python3
class Foo:
me = None
def __init__(self):
if Foo.me != None:
raise Exception('Instance of Foo still exists!')
Foo.me = self
if __name__ == '__main__':
Foo()
Foo()
산출량
Traceback (most recent call last):
File "./x.py", line 15, in <module>
Foo()
File "./x.py", line 8, in __init__
raise Exception('Instance of Foo still exists!')
Exception: Instance of Foo still exists!
장점
진정한 클래스 상속을 마법처럼 자동으로 커버합니다 메타클래스를 적절한 목적으로 사용합니다(그리고 그것을 알게 해주었습니다). 단점
있어요?
이것은 시리얼 존분할에 관한 문제입니다.는 "(피클)"을 사용하지 .__call__
할 수 .__new__
그걸 막으려고요
메타클래스에서 파생되는 것보다 데코레이터 구문을 선호합니다.내 의견:
from typing import Callable, Dict, Set
def singleton(cls_: Callable) -> type:
""" Implements a simple singleton decorator
"""
class Singleton(cls_): # type: ignore
__instances: Dict[type, object] = {}
__initialized: Set[type] = set()
def __new__(cls, *args, **kwargs):
if Singleton.__instances.get(cls) is None:
Singleton.__instances[cls] = super().__new__(cls, *args, **kwargs)
return Singleton.__instances[cls]
def __init__(self, *args, **kwargs):
if self.__class__ not in Singleton.__initialized:
Singleton.__initialized.add(self.__class__)
super().__init__(*args, **kwargs)
return Singleton
@singleton
class MyClass(...):
...
다른 데코레이터보다 몇 가지 장점이 있습니다.
isinstance(MyClass(), MyClass)
계속 기능합니다(클래스 대신 클라우저에서 기능을 사용하면 장애가 발생합니다).property
,classmethod
★★★★★★★★★★★★★★★★★」staticmethod
대로 될 것이다__init__()
됩니다.- 당신이 꾸민 수업에서 물려받을 수 있다(쓸데없는)?다시 @singleton 사용
단점:
print(MyClass().__class__.__name__)
Singleton
MyClass
그래도 이것이 필요하다면 위와 같은 메타클래스를 사용하는 것을 추천합니다.
컨스트럭터 파라미터에 따라 다른 인스턴스가 필요한 경우 이 솔루션을 개선해야 합니다(siddhesh-suhas-sathe에서 제공하는 솔루션 제공).
마지막으로, 다른 제안과 같이 python에서 모듈을 사용하는 것을 고려해 보십시오.모듈은 객체입니다.변수를 전달하고 다른 클래스에 주입할 수도 있습니다.
우연히 간단한 걸 만들어서 공유하려고 했는데...
class MySingleton(object):
def __init__(self, *, props={}):
self.__dict__ = props
mything = MySingleton()
mything.test = 1
mything2 = MySingleton()
print(mything2.test)
mything2.test = 5
print(mything.test)
그것은 팹의 답변과 약간 비슷하지만 완전히 같지는 않다.
싱글톤 패턴에서는 컨스트럭터를 여러 번 호출할 필요가 없습니다.싱글톤은 단 한 번, 단 한 번 만들어져야 하는 만큼 한 번 만들어져야 하는 것 아닌가요?컨스트럭터를 "스푸핑"하면 가독성이 저하됩니다.
그래서 제가 제안하는 것은 다음과 같습니다.
class Elvis():
def __init__(self):
if hasattr(self.__class__, 'instance'):
raise Exception()
self.__class__.instance = self
# initialisation code...
@staticmethod
def the():
if hasattr(Elvis, 'instance'):
return Elvis.instance
return Elvis()
.instance
다음 중 하나:
if Elvis() is King.instance:
...신신면면면면면면면면면면Elvis
되지 않은 것, 은 만들어지지 않았다.King
단, 사용자는 이 기능을 사용하여the
다음 중 하나:
Elvis.the().leave(Building.the())
하려면 , 「 」를 수도 있습니다.__delattr__()
하려고 instance
및 「」를 덮어씁니다.__del__()
그그 ) ) ) ) ) ) ) ) ) ) )))))))...)
한층 더 개선
코멘트나 편집에 협력해 주신 분들께 감사드리며, 그 밖에도 감사 드립니다.제가 Jython을 사용하는 동안, 이것은 더 일반적으로 작동하며 스레드 세이프합니다.
try:
# This is jython-specific
from synchronize import make_synchronized
except ImportError:
# This should work across different python implementations
def make_synchronized(func):
import threading
func.__lock__ = threading.Lock()
def synced_func(*args, **kws):
with func.__lock__:
return func(*args, **kws)
return synced_func
class Elvis(object): # NB must be subclass of object to use __new__
instance = None
@classmethod
@make_synchronized
def __new__(cls, *args, **kwargs):
if cls.instance is not None:
raise Exception()
cls.instance = object.__new__(cls, *args, **kwargs)
return cls.instance
def __init__(self):
pass
# initialisation code...
@classmethod
@make_synchronized
def the(cls):
if cls.instance is not None:
return cls.instance
return cls()
주의사항:
- python2를 의 클래스를 얻을 수 .x의 오브젝트에서 서브클래스를 하지 않으면 오래된 스타일의 클래스가 생성됩니다.이 클래스는
__new__
- 할 때 ★★★★
__new__
@ @classmethod로.__new__
메서드가 . - 은 메타클래스를될 수 , 「이러한 것은 아니다」라고 하기 때문입니다.이것에 의해, 다음과 같이 할 수 있기 때문입니다.
the
의 속성.아마도 「 레벨」로 이 바뀔 가능성이 .instance
어디서 이 솔루션을 찾았는지는 기억나지 않지만, Python 전문가가 아닌 내 입장에서 가장 '고급'이라는 것을 알 수 있습니다.
class SomeSingleton(dict):
__instance__ = None
def __new__(cls, *args,**kwargs):
if SomeSingleton.__instance__ is None:
SomeSingleton.__instance__ = dict.__new__(cls)
return SomeSingleton.__instance__
def __init__(self):
pass
def some_func(self,arg):
pass
가가왜 걸걸? ???에는 삭제해 주세요.__new__
as. )에 에 왜 이 나쁜해 줄 합니다.저는 Python(그리고 일반적으로 OOP)에 익숙하지 않기 때문에, 왜 이것이 나쁜 접근법인지 누군가가 저에게 설명해 줄 것으로 예상합니다.
톨리의 대답에 기반한 코드입니다.
#decorator, modyfies new_cls
def _singleton(new_cls):
instance = new_cls() #2
def new(cls):
if isinstance(instance, cls): #4
return instance
else:
raise TypeError("I can only return instance of {}, caller wanted {}".format(new_cls, cls))
new_cls.__new__ = new #3
new_cls.__init__ = lambda self: None #5
return new_cls
#decorator, creates new class
def singleton(cls):
new_cls = type('singleton({})'.format(cls.__name__), (cls,), {} ) #1
return _singleton(new_cls)
#metaclass
def meta_singleton(name, bases, attrs):
new_cls = type(name, bases, attrs) #1
return _singleton(new_cls)
설명:
.이 클래스는 지정된 클래스에서 됩니다.
cls
하지 않습니다)cls
를 , 누군가가singleton(list)
)인스턴스를 만듭니다.「 」를 덮어쓰기
__new__
말말쉽쉽쉽쉽- 쉽게 수 있게 now면면면면면면면면면면면보다 우선됩니다.
__new__
조금 전에 정의한 방법을 사용합니다. 가 반환하다
instance
발신자가한 대로의 에만, 「기대할 수 있다」 「기대할 수 없다」 「기대할 수 없다.TypeError
.
누군가 장식된 클래스에서 상속을 시도하면 조건이 충족되지 않습니다.-
에서 인스턴스를 반환할 경우 새 인스턴스의 메서드는 다음과 같이 호출됩니다.
__init__(self[, ...])
는 self로__new__()
.instance
는 이미되어 있기 이 기능이 대체됩니다.__init__
기능은 아무것도 하지 않습니다.
Singleton 인스턴스의 느린 초기화가 필요하지 않은 경우 다음을 쉽고 스레드 세이프해야 합니다.
class A:
instance = None
# Methods and variables of the class/object A follow
A.instance = A()
입니다.A
Import하다
한동안 이 문제로 고민하다가 결국 다음과 같은 것을 생각해냈습니다.따라서 config 오브젝트는 다른 모듈에서 호출되었을 때 한 번만 로드됩니다.메타클래스를 사용하면 글로벌클래스 인스턴스를 빌트인 dict에 저장할 수 있습니다.이것은 현재 적절한 프로그램을 글로벌하게 저장하는 가장 깔끔한 방법입니다.
import builtins
# -----------------------------------------------------------------------------
# So..... you would expect that a class would be "global" in scope, however
# when different modules use this,
# EACH ONE effectively has its own class namespace.
# In order to get around this, we use a metaclass to intercept
# "new" and provide the "truly global metaclass instance" if it already exists
class MetaConfig(type):
def __new__(cls, name, bases, dct):
try:
class_inst = builtins.CONFIG_singleton
except AttributeError:
class_inst = super().__new__(cls, name, bases, dct)
builtins.CONFIG_singleton = class_inst
class_inst.do_load()
return class_inst
# -----------------------------------------------------------------------------
class Config(metaclass=MetaConfig):
config_attr = None
@classmethod
def do_load(cls):
...<load-cfg-from-file>...
'어울리다'를 사용할 수 요.metaclass
instance
예를 들면,
class SingletonMeta(type):
def __init__(cls, *args, **kwargs):
super().__init__(*args, **kwargs)
cls._instance = None
cls._locker = threading.Lock()
@property
def instance(self, *args, **kwargs):
if self._instance is None:
with self._locker:
if self._instance is None:
self._instance = self(*args, **kwargs)
return self._instance
class MyClass(metaclass=SingletonMeta):
def __init__(self):
# init here
pass
# get the instance
my_class_instance = MyClass.instance
1개의 라이너(자랑스럽지는 않지만 효과가 있습니다):
import sys
class Myclass:
def __init__(self):
# do your stuff
vars(sys.modules[__name__])[type(self).__name__] = lambda: self # singletonify
메서드: 1회 사용 후 __new__ 덮어쓰기
class Singleton():
def __init__(self):
Singleton.instance = self
Singleton.__new__ = lambda _: Singleton.instance
장점
- 매우 심플하고 간결함
- 진정한 클래스, 모듈 불필요
- 람다와 피토닉 원숭이 패치 적용의 적절한 사용
단점
- __new__는 다시 덮어쓸 수 있습니다.
언급URL : https://stackoverflow.com/questions/6760685/creating-a-singleton-in-python
'programing' 카테고리의 다른 글
어레이에 값이 포함되어 있는지 확인합니다. (0) | 2022.09.13 |
---|---|
SELECT MAX('Id')를 테이블에서 setval()로 전달합니다. (0) | 2022.09.13 |
json 개체로 반환할 여러 DB 쿼리가 있습니다. 더 깔끔한 접근 방식? (0) | 2022.09.13 |
PHP 치명적 오류: 클래스를 다시 닫을 수 없습니다. (0) | 2022.09.13 |
"SET NAMS" 사용 여부 (0) | 2022.09.12 |