파이썬에서 싱글 톤 만들기


945

이 질문은 싱글 톤 디자인 패턴 이 바람직한 지 아닌지 , 반 패턴 또는 종교적 전쟁에 대한 토론이 아니라 파이썬 에서이 패턴이 가장 파이썬적인 방식으로 가장 잘 구현되는 방법에 대해 논의하는 것입니다. 이 예에서 나는 '가장 pythonic'을 '최소한 놀랍게도의 원리'를 따른다는 것을 의미합니다 .

싱글 톤이 될 여러 클래스가 있습니다 (사용 사례는 로거를위한 것이지만 이것은 중요하지 않습니다). 나는 단순히 상속하거나 장식 할 수있을 때 잇몸이 추가 된 여러 클래스를 어지럽히고 싶지 않습니다.

최선의 방법 :


방법 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 자체는 클래스가 아니라 함수이므로 클래스 메서드를 호출 할 수 없습니다. 또한 m = MyClass(); n = MyClass(); o = type(n)();그때m == n && m != o && n != o

방법 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

찬성

  • 진정한 클래스입니다

단점

  • 다중 상속-eugh! __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

찬성

  • 진정한 클래스입니다
  • 상속을 자동으로 다루기

단점

  • 각각의 새 클래스를 만드는 데 오버 헤드가 없습니까? 여기서 우리는 싱글 톤으로 만들 각 클래스에 대해 두 개의 클래스를 만듭니다. 내 경우에는 괜찮지 만 이것이 확장되지 않을까 걱정됩니다. 물론이 패턴을 확장하기가 너무 쉬운 지에 대해서는 논쟁의 여지가 있습니다 ...
  • _sealed속성 의 요점은 무엇입니까
  • 기본 클래스에서 동일한 이름의 메소드를 호출 할 수 없습니다 super(). 즉 __new__, 호출해야하는 클래스를 사용자 정의 할 수없고 서브 클래스 할 수 없습니다 __init__.

방법 5 : 모듈

모듈 파일 singleton.py

찬성

  • 단순한 것이 복잡한 것보다 낫다

단점


12
또 다른 세 가지 기술 : 대신 모듈을 사용하십시오 (종종-일반적으로 생각합니다-이것은 파이썬에 더 적합한 패턴이지만 모듈로 수행중인 작업에 따라 조금씩 다릅니다). 단일 인스턴스를 만들고 대신 처리하십시오 ( foo.x또는 Foo.x대신 주장 하는 경우 Foo().x). 클래스 속성과 정적 / 클래스 메소드 ( Foo.x)를 사용하십시오.
Chris Morgan

10
@ChrisMorgan : 클래스 / 정적 메소드 만 사용하려는 경우 실제로 클래스를 만들지 않아도됩니다.
Cat Plus Plus

2
@ 고양이 : 효과는 비슷하지만 전역 변수를 만드는 이유는 더 잘 모르는 것을 포함하여 무엇이든 가능합니다. 왜 싱글 톤을 만드는가? 물어봐야한다면 여기 있으면 안됩니다. 이 명시 성은 단순한 파이썬이 아니라 유지 보수를 훨씬 간단하게 만듭니다. 그렇습니다. 싱글 톤은 전 세계의 구문 설탕이지만, 수업은보기 흉한 것들에 대한 구문 설탕이며, 아무도 당신이 항상 당신에게 그들 없이는 더 나아 졌다고 말할 것이라고 생각하지 않습니다.
theheadofabroom

14
@BiggAl : 싱글 톤은 어떻게 구현하든 파이썬 이 아닙니다 . 그들은 결함이있는 디자인의 징조입니다.
Cat Plus Plus

8
안티-시그 니트 감정은 최악의화물 컬트 프로그래밍입니다. "실제로 간주되는 고토 진술"을 듣고 사람들이 상황에 관계없이 나쁜 코드의 표시라고 생각하는 사람들과 동일합니다 (실제로 읽기가 귀찮습니다).
Hejazzman

답변:


658

메타 클래스 사용

방법 # 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(), 파이썬은 처음의 메타 클래스 요청 Logger, Singleton, 인스턴스 생성을 선점 할 수 있도록 무엇을해야합니다. 이 프로세스는 파이썬이 클래스 __getattr__의 속성 중 하나를 참조 하여 호출 할 때 호출하여 수행 할 작업을 묻는 것과 같습니다 myclass.attribute.

메타 클래스는 본질적으로 클래스 의 정의무엇을 의미 하고 그 정의를 구현하는 방법을 결정합니다. 예를 들어 http://code.activestate.com/recipes/498149/를 참조하십시오 struct. 메타 클래스를 사용하여 Python에서 C 스타일을 본질적으로 재생성 합니다. 스레드 메타 클래스에 대한 (콘크리트) 사용 사례는 무엇입니까? 또한 일부 예제를 제공하는데, 일반적으로 특히 ORM에서 사용되는 선언적 프로그래밍과 관련이있는 것 같습니다.

이 상황에서 메소드 # 2 를 사용 하고 서브 클래스가 __new__메소드를 정의하는 경우, 메소드는 저장된 인스턴스를 리턴하는 메소드를 호출해야하기 때문에 호출 할 때마다 실행됩니다SubClassOfSingleton() . 메타 클래스를 사용 하면 유일한 인스턴스가 생성 될 때 한 번만 호출 됩니다. 클래스 호출의 의미사용자 정의하려고합니다 . 유형에 따라 결정됩니다.

일반적으로, 의미가 싱글 톤을 구현하는 메타 클래스를 사용합니다. 싱글 톤은 한 번만 생성 되기 때문에 특별 하며 메타 클래스는 클래스 생성을 사용자 정의하는 방법 입니다. 메타 클래스를 사용하면 싱글 톤 클래스 정의를 다른 방법으로 사용자 정의해야 할 경우에 대비 하여 더 많은 제어 가 가능합니다.

단일 클래스에는 다중 상속이 필요하지 않지만 (메타 클래스는 기본 클래스가 아니기 때문에) 다중 상속을 사용 하는 생성 된 클래스의 하위 클래스의 경우 단일 클래스가 재정의하는 메타 클래스가있는 첫 번째 / 가장 왼쪽 클래스인지 확인해야합니다. __call__이것은 문제가되지 않을 것입니다. 인스턴스 dict가 인스턴스의 네임 스페이스에 없으므로 실수로 덮어 쓰지 않습니다.

또한 싱글 톤 패턴이 "Single Responsibility Principle"을 위반한다는 말을들을 입니다. 각 수업은 한 가지만해야 합니다. 그렇게하면 코드가 분리되어 캡슐화되어 있기 때문에 코드를 변경해야 할 때 코드가 수행하는 작업을 엉망으로 만들 염려가 없습니다. 메타 클래스 구현 은이 테스트를 통과합니다 . 메타 클래스는 패턴시행하는 역할을 하며 생성 된 클래스와 서브 클래스 는 싱글 톤임을 인식 할 필요가 없다 . "MyClass 자체는 클래스가 아니라 함수이므로 클래스 메서드를 호출 할 수 없습니다."로 언급했듯이 메서드 # 1 은이 테스트에 실패합니다.

파이썬 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()

클래스를 돌려주는 데코레이터

원래 의견을 쓰고 있었지만 너무 길어서 여기에 추가하겠습니다. 방법 # 4 는 다른 데코레이터 버전보다 낫지 만 싱글 톤에 필요한 것보다 더 많은 코드이며, 그것이하는 일이 명확하지 않습니다.

주요 문제는 클래스가 자체 기본 클래스라는 데 있습니다. 첫째, 클래스가 __class__속성 에만 존재하는 동일한 이름을 가진 거의 동일한 클래스의 서브 클래스가되는 것이 이상하지 않습니까? 이것은 또한 사용자가 정의 할 수 없음을 의미 자신의 기본 클래스에 같은 이름의 메소드를 호출 어떤 방법 으로 super()그들이 재귀 때문입니다. 이것은 클래스가 사용자 정의 __new__할 수 없으며 __init__호출 해야하는 클래스에서 파생 될 수 없음 을 의미합니다.

싱글 톤 패턴을 사용하는 경우

유스 케이스는 싱글 톤을 사용하려는 더 좋은 예 중 하나입니다 . 당신은 의견 중 하나에서 "나에게 로깅은 항상 싱글 톤의 자연스러운 후보로 보였습니다."라고 말합니다. 당신은 절대적으로 맞습니다 .

사람들이 싱글 톤이 나쁘다고 말할 때 가장 일반적인 이유는 암시 적 공유 상태 이기 때문입니다 . 전역 변수와 최상위 모듈 가져 오기가 명시 적으로 공유 된 상태 인 반면 전달되는 다른 객체는 일반적으로 인스턴스화됩니다. 이것은 두 가지 예외 가 있지만 좋은 지적 입니다.

여러 곳에서 언급되는 첫 번째는 싱글 톤이 일정 할 때 입니다. 전역 상수, 특히 열거 형의 사용은 널리 받아 들여지고 어떤 사용자도 다른 사용자를 위해 그들을 엉망으로 만들 수 없기 때문에 제정신으로 간주됩니다 . 상수 싱글 톤에서도 마찬가지입니다.

덜 언급되는 두 번째 예외는 반대입니다. 싱글 톤이 데이터 소스가 아닌 데이터 싱크 일 경우 (직접 또는 간접). 이것이 로거가 싱글 톤을 "자연스럽게"사용하는 것처럼 느끼는 이유입니다. 다양한 사용자가 다른 사용자가 관심을 갖는 방식으로 로거변경 하지 않기 때문에 실제로 공유 된 상태없습니다 . 이것은 싱글 톤 패턴에 대한 주요 논증을 무시하고 , 작업에 대한 사용 편의성 때문에 합리적인 선택 입니다.

다음은 http://googletesting.blogspot.com/2008/08/root-cause-of-singletons.html 의 인용문입니다 .

자, 싱글 톤의 한 종류가 있습니다. 이는 도달 가능한 모든 객체가 변경 불가능한 싱글 톤입니다. 모든 객체가 불변 인 경우 Singleton은 전역 상태가 없으므로 모든 것이 일정합니다. 그러나 이런 종류의 싱글 톤을 변경 가능한 것으로 바꾸는 것은 매우 쉽습니다. 매우 미끄러운 경사입니다. 그러므로 나는이 싱글 톤들에 대해서도 반대한다. 왜냐하면 그것들이 나쁘기 때문이 아니라 그들이 나빠지 기가 매우 쉽다는 점이다. 참고로 Java 열거는 이러한 종류의 싱글 톤입니다. 열거에 상태를 넣지 않는 한 괜찮습니다. 그렇지 마십시오.

세미-허용되는 다른 종류의 싱글 톤은 코드의 실행에 영향을 미치지 않는 것입니다. "부작용"은 없습니다. 로깅은 완벽한 예입니다. 싱글 톤과 전역 상태로로드됩니다. 주어진 로거의 사용 가능 여부에 관계없이 응용 프로그램이 다르게 동작하지 않기 때문에 허용됩니다 (손상되지 않음). 여기에있는 정보는 한 가지 방법으로 흐릅니다. 응용 프로그램에서 로거로. 로거에서 응용 프로그램으로 정보가 흐르지 않기 때문에 로거가 전역 상태라고 생각하더라도 로거는 허용됩니다. 테스트 결과 무언가가 기록되고 있다고 주장하려면 로거를 계속 주입해야하지만 일반적으로 로거는 상태가 가득 차 있어도 유해하지 않습니다.


5
아니요, 싱글 톤은 결코 좋지 않습니다. 로깅은 전역과 같은 훌륭한 후보가 될 수 있지만 확실히 싱글 톤은 아닙니다.
Cat Plus Plus

11
googletesting.blogspot.com/2008/08/…를 보십시오 . 그것은 일반적으로 안티 싱글 톤이지만 (합당한 이유로) 불변의 싱글 톤과 부작용이없는 싱글 톤이 같은 문제가없는 이유에 대해 잘 설명되어 있습니다. 내 게시물 끝에 약간 인용하겠습니다.
agf

4
싱글 톤에 대한 나의 문제는 "단일 인스턴스"라는 어리석은 전제입니다. 그와 스레드 안전 문제의 톤. 그리고 의존성 숨기기. 글로벌은 나쁘고 싱글 톤은 더 많은 문제가있는 글로벌입니다.
고양이 플러스 플러스

4
@ 고양이 싱글 톤에는 매우 잘 사용됩니다. 하드웨어 모듈 (특히 단일 스레드 응용 프로그램)의 지연 인스턴스화는 그 중 하나입니다 (그러나 스레드 안전 싱글 톤도 존재합니다).
Paul Manta

3
__new__메타 클래스의 @Alcott 는 클래스 가 새로운 것이지 정의 된 때가 아니라 인스턴스 가 새로운 것이 될 때 입니다. 클래스 ( MyClass())를 호출하는 것은 클래스 정의가 아니라 재정의하려는 작업입니다. 파이썬의 작동 방식을 정말로 이해하려면 docs.python.org/reference/datamodel.html을 읽으십시오 ( 파이썬을 계속 사용하는 것 이외) . 메타 클래스에 대한 좋은 참조는 eli.thegreenplace.net/2011/08/14/python-metaclasses-by-example 입니다. 싱글 톤에 대한 좋은 기사는이 답변에 링크 된 Google 블로그의 시리즈입니다.
agf

91
class Foo(object):
     pass

some_global_variable = Foo()

모듈은 한 번만 가져 오며 다른 모든 항목은 지나치게 생각합니다. 싱글 톤을 사용하지 말고 전역을 사용하지 마십시오.


14
왜 "싱글 톤을 사용하지 마십시오"라고 말했습니까? 어떤 이유?
Alcott

3
싱글 톤을 피클해야하는 경우에는 작동하지 않습니다. 당신이 준 예제를 사용하여 :s = some_global_variable; str = pickle.dumps(s); s1 = pickle.loads(str); print s is s1; # False
dividebyzero

4
@dividebyzero : is연산자가 포인터 동등성을 테스트합니다. pickle.loads새로 만든 객체에 대한 참조가 아닌 기존 객체에 대한 참조를 반환 한 경우 버그라고하는 점에 다소 놀랐 습니다. 따라서 s is s1모듈을 싱글 톤으로 사용하는 데 적합한 지 여부를 테스트 하지 않는지 테스트 하십시오.
Jonas Kölker

1
@ JonasKölker pickle.loads()는 이미 예를 들어 bool및의 인스턴스에 대해이를 수행합니다 NoneType. pickle.loads(pickle.dumps(False)) is False수확량True
Dan Passaro

2
@ leo-the-manic : 페어 포인트; 그러나,이 개체를 인턴 파이썬의 단지 부작용의 True, False그리고 None, 그리고 코드 뒤에 함께 할 수 없다 pickle.loads. 또한 읽기 전용 개체에 대해서만 안전합니다. 모듈과 같은 pickle.loads이미 존재하는 수정 가능한 객체에 대한 참조를 반환 한다면 버그 일 것입니다. (그리고 나는 splitbyzero의 코드 예제가 아무 것도 증명하지 않는다는 내 암시로 서있다.)
Jonas Kölker

69

모듈을 사용하십시오. 한 번만 가져옵니다. 그 안에 일부 전역 변수를 정의하십시오-단일 변수의 '속성'이됩니다. 싱글 톤의 '메서드'기능을 추가하십시오.


11
그래서 당신이 끝내는 것은 ... 수업이 아닙니다. 당신은 이것을 클래스로 사용할 수없고, 다른 클래스를 기반으로 할 수 없으며, 가져 오기 구문을 사용하고, 갑자기 OOP의 모든 이점을 잃게됩니다 ...
theheadofabroom

16
다른 클래스를 기반으로 할 수 있다면 싱글 톤이 아닐 수도 있습니다. 파생 클래스 중 하나와 기본 클래스 중 하나를 만들 수 있지만 파생 클래스도 기본의 멤버이며 두 개의 기본 중 하나를 사용해야합니까?
SingleNegationElimination

여러 모듈에서 작동하지 않습니다. 내 "메인"모듈에서 값을 설정했습니다. 그런 다음 다른 모듈과 null에서 참조합니다. 한숨.
Paul Kenjora

1
@PaulKenjora 코드에 오류가 있어야합니다. 모듈에서 전역 변수를 정의하면 다른 모듈에서 액세스 할 때 값을 가져야합니다.
warvariuc

값이 있지만 변경하면 보존되지 않습니다. 작동하는 모듈의 속성이있는 클래스를 사용했습니다. 전역으로서의 간단한 유형은 나를 위해 작동하지 않았습니다 (범위가 변경되는 즉시 값이 손실 됨).
Paul Kenjora

29

파이썬에서는 싱글 톤이 필요하지 않을 것입니다. 모듈에서 모든 데이터와 함수를 정의하기 만하면 사실상 단일 항목이 있습니다.

정말로 싱글 톤 클래스를 가져야한다면 다음과 같이 갈 것입니다.

class My_Singleton(object):
    def foo(self):
        pass

my_singleton = My_Singleton()

쓰다:

from mysingleton import my_singleton
my_singleton.foo()

여기서 mysingleton.py는 My_Singleton이 정의 된 파일 이름입니다. 파일을 처음 가져온 후 Python은 코드를 다시 실행하지 않기 때문에 작동합니다.


4
대부분 사실이지만 때로는 충분하지 않습니다. 예를 들어 DEBUG 수준에서 많은 클래스의 인스턴스화를 기록 해야하는 프로젝트가 있습니다. 클래스를 인스턴스화 하기 전에 사용자 지정 로깅 레벨을 설정하려면 시작시 구문 분석 된 명령 행 옵션이 필요합니다 . 모듈 수준 인스턴스화로 인해 문제가 발생합니다. CLI 처리가 완료 될 때까지 해당 클래스를 모두 가져 오지 않도록 응용 프로그램을 신중하게 구성 할 수 있지만 내 응용 프로그램의 자연스러운 구조는 "단일 항목이 잘못되었습니다"라는 독단적 준수보다 중요합니다. 아주 깨끗하게 해냈습니다.
CryingCyclops

my_singleton을 패치하는 동안 코드를 테스트한다면 가능할까요? 이 my_singleton은 다른 모듈에서 인스턴스화 될 수 있기 때문에.
Naveen

@Naveen-my_singleton은 단일 객체입니다. "패치"하면 변경 사항이 다른 모듈에서도 향후의 모든 참조에 영향을 미칩니다.
Alan Dyke

16

여기 하나의 라이너가 있습니다.

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

객체가 간절히 인스턴스화됩니다. 이것은 당신이 원하는 것일 수도 아닐 수도 있습니다.


5
-1. 이것은 매우 나쁘고 바보입니다. 객체로 사용할 클래스를 정의하지 않았습니다. 더 이상 type(wat)또는 과 같이하지 않으면 더 이상 수업에 액세스 할 수 없습니다 wat.__class__. 실제로 이것을 달성하려면 클래스를 더 잘 정의하고 즉시 인스턴스화하십시오. 데코레이터를 망칠 필요가 없습니다.
0xc0de

2
왜 싱글 톤의 클래스를 사용해야합니까? 싱글 톤 객체를 사용하십시오.
Tolli

1
그것은 아닙니다 패턴 싱글 함수가 다른 이름을 지정해야합니다 때문에 IMO.
GingerPlusPlus

8
위키 백과 : "싱글 톤 패턴은 클래스의 인스턴스화를 하나의 객체로 제한하는 디자인 패턴"입니다. 내 솔루션이 그렇게한다고 말합니다. 좋아, 나는 할 수 있다고 생각 wat2 = type(wat)()하지만, 이것은 파이썬이며, 우리는 모두 동의하는 성인과 그 모든 것입니다. 인스턴스가 하나만 있다고 보장 할 수는 없지만 사람들이 두 번째 인스턴스를 만들면보기 흉한 것처럼 보이고, 괜찮은 사람들이 있다면 경고 표시처럼 보일 수 있습니다. 내가 무엇을 놓치고 있습니까?
Jonas Kölker

7

스택 오버플로 질문을 확인하십시오 . 파이썬에서 싱글 톤을 정의하는 간단하고 우아한 방법이 있습니까? 여러 솔루션으로.

파이썬에서 디자인 패턴에 대한 Alex Martelli의 이야기를 보길 강력히 권장합니다 : 1 2 부 . 특히, 1 부에서 그는 싱글 톤 / 공유 상태 객체에 대해 이야기합니다.


2
이것은 실제로 내 질문에 대한 답변은 아니지만 당신이 가리키는 리소스는 매우 유용합니다. 나는 당신에게 +1을
주었습니다

3

여기 내 싱글 톤 구현이 있습니다. 수업을 꾸미기 만하면됩니다. 싱글 톤을 얻으려면 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)

2
진정한 싱글 톤이 아닙니다. 진정한 싱글 톤으로 SingletonList = Singleton(list).Instance(); print(SingletonList is type(SingletonList)())인쇄해야합니다 True. 코드 인쇄False
GingerPlusPlus

@ GingerPlusPlus 나는 몇 가지 제한 사항을 알고 있었지만 지적한 제한은 없습니다. 언급 해 주셔서 감사합니다. 불행히도, 나는 지금 이것에 대한 해결책을 얇게 할 시간이 없습니다.
Paul Manta

2

방법 3은 매우 깔끔한 것처럼 보이지만 프로그램이 Python 2Python 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'로 바꿔야한다고 생각하지만 시도하지 않았습니다 (그림과 같이 코드를 시도했습니다).


분명히 이것은 메타 클래스가 아닙니다 class MyClass(metaclass=Singleton)
-python3

mikewatkins.ca의 링크 (효과적으로) 깨진입니다.
Peter Mortensen

1

글쎄, 모듈 수준의 전역을 갖는 것에 대한 일반적인 Pythonic 제안에 동의하는 것 외에는 어떻습니까?

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

_sealed속성 의 요점은 무엇입니까 ? 내가 아는 한 이것은 아무것도하지 않습니까? 성능이 좋지 않아야한다는 말에 대해 무언가를 자극하고 있습니다. 이번 주 후반에 비교 테스트를 실시하겠습니다.
theheadofabroom

_sealed는 init 가 한 번만 실행 되도록합니다 . 새로운 상속 클래스 기능 만 클래스 당 한 번만 실행되고, 반환 - 그것은 정기적으로 장식 함수처럼보다 더 수행해야하는 이유는 어떤 지점이 표시되지 않습니다
가드

BTW, 편집에는 들여 쓰기를 깨뜨리는 탭이 포함되어 있습니다. 또한 '우리는 2 개의 클래스를 만들고 있습니다'라고 말하고 있습니다. '1 개의 추가 클래스'를 만들고 있다는 의미입니까?
Guard

예, 하나의 추가 수업이 의미합니다. __init__초기화 될 때마다 호출 할 항목 을 포함하려고합니다 . 단순한 'class.method에서 초기화되고 있습니다'. 들여 쓰기에 관해서-당신은 탭과 공백을 사용했습니다-나는 그것을 대부분
고쳤 지

re init : 물론 그것은 당신에게 달려 있습니다. 다른 언어로 싱글 톤 동작을 모방하려고했습니다. 생성자 코드 (정확히 init 는 아니지만 의미가 매우 가깝습니다) init 를 원한다면 한 번만 호출 됩니다. 매번 호출, _sealed respaces / tabs에 대한 모든 참조를 제거하십시오-그렇다면 내 이맥스는 수정해야합니다. 어쨌든, 위의 수정 된 버전입니다
Guard

1

이건 어때요:

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()다른 답변 에서 데코레이터 와 유사합니다 . 다른 솔루션과 마찬가지로 유일한 인스턴스 이름은 클래스 ( MySingleton)입니다. 그러나이 솔루션을 사용하면 클래스를 통해 인스턴스를 "실제로 생성"할 수 있습니다 (실제로 유일한 인스턴스를 가져옵니다) MySingleton(). 또한 type(MySingleton)()동일한 인스턴스를 반환하여 추가 인스턴스를 만들지 못하게합니다 .


클래스를 객체로 사용하도록 정의하지 않았습니다.
0xc0de

1
전화 할 때마다 type(MySingleton)(), MySingleton.__init__()호출되는 및 개체가 여러 번 초기화됩니다; 에 글 cls.__init__ = lambda self: pass을 고칠 수 있습니다 singleton. 또한 재정의 cls.__call__는 무의미 해 보이며이 __call__컨텍스트에서 유해한 정의 조차도 전화 MySingleton(any, list, of, arguments)할 때가 아니라 전화 할 때 사용됩니다 type(MySingleton)(any, list, of, arguments).
GingerPlusPlus

@GingerPlusPlus,를 __init__()할 때 다시 호출 되는 것을 지적 해 주셔서 감사합니다 type(MySingleton)(). cls.__init__ = lambda self: pass람다 표현식의 마지막 부분은 명령문이 아닌 표현식이어야하므로 제안한 솔루션 ( )은 구문 오류를 발생시킵니다. 그러나 cls.__init__ = lambda self: None작품을 추가하면 답변에 추가했습니다.
Tolli

1
@GingerPlusPlus의 사용에 대하여 __call__. 내 의도는 둘 다 type(MySingleton)()만들고 MySingleton()인스턴스를 반환하는 것이 었습니다 . 그래서 내가 원하는 것을하고 있습니다. MySingleton을 싱글 톤의 유형 또는 싱글 톤의 인스턴스 (또는 둘 다)로 생각할 수 있습니다.
Tolli

1

반지에 광산을 던져 줄 게요. 간단한 데코레이터입니다.

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.

장점 다른 솔루션보다 이점이 있다고 생각합니다.

  • 명확하고 간결합니다 (내 눈에는 D).
  • 그 행동은 완전히 캡슐화되었습니다. 의 구현에 대해 한 가지만 변경할 필요는 없습니다 YourClass. 여기에는 클래스에 메타 클래스를 사용할 필요가 없습니다 (위의 메타 클래스는 "실제"클래스가 아닌 팩토리에 있습니다).
  • 원숭이 패치에 의존하지 않습니다.
  • 발신자에게 투명합니다.
    • 호출자는 여전히 간단하게 import YourClass하고 클래스처럼 보이므로 정상적으로 사용합니다. 발신자를 공장 기능에 맞출 필요가 없습니다.
    • 무엇 YourClass()인스턴스화하는 것은 아직도의 진정한 인스턴스 YourClass부작용의 기회가의 결과 없습니다, 그래서 당신은 어떤 종류의,하지 프록시를 구현했습니다.
    • isinstance(instance, YourClass) 비슷한 연산이 여전히 예상대로 작동합니다 (이 비트에는 abc가 필요하므로 Python <2.6은 제외).

한 가지 단점이 있습니다. 실제 클래스의 클래스 메소드와 정적 메소드는 그것을 숨기는 팩토리 클래스를 통해 투명하게 호출 할 수 없습니다. 필자는이 요구에 부딪치지 않을 정도로 이것을 거의 사용하지 않았지만 팩토리에서 사용자 정의 메타 클래스를 사용 __getattr__()하여 실제 클래스에 대한 모든 속성 액세스를 위임 하여 쉽게 수정할 수 있습니다 .

실제로 더 유용한 것으로 밝혀진 관련 패턴 (이러한 종류의 것들이 매우 자주 필요하다고 말하는 것은 아닙니다)은 동일한 인수로 클래스를 인스턴스화 하면 동일한 인스턴스를 다시 얻는 "고유 한"패턴 입니다. 즉 "인수 당 단일 항목"입니다. 위의 내용은이 내용에 잘 적응하고 더 간결 해집니다.

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 %, 야니


1
  • 동일한 클래스의 여러 인스턴스를 원하지만 args 또는 kwargs가 다른 경우에만 이것을 사용할 수 있습니다
  • 전의.
    1. serial통신을 처리하는 클래스가 있고 인스턴스를 만들려면 직렬 포트를 인수로 보내려는 경우 기존 방식으로는 작동하지 않습니다.
    2. 위에서 언급 한 데코레이터를 사용하면 인수가 다른 경우 클래스의 여러 인스턴스를 만들 수 있습니다.
    3. 동일한 인수의 경우 데코레이터는 이미 작성된 동일한 인스턴스를 리턴합니다.
>>> 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
>>>

0

Tolli의 답변을 기반으로 한 코드 .

#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)

설명:

  1. 주어진 클래스에서 상속받은 새 클래스를 만듭니다 cls
    ( cls예를 들어 누군가가 원하는 경우 수정하지 않음 singleton(list))

  2. 인스턴스를 만듭니다. 재정의하기 전에 __new__너무 쉽습니다.

  3. 이제 인스턴스를 쉽게 만들었을 때, 얼마 __new__전에 정의 된 메서드를 사용하여 재정의 합니다.
  4. 이 함수는 instance호출자가 기대하는 경우에만 반환 하고 그렇지 않으면 발생합니다 TypeError.
    누군가 꾸며진 클래스에서 상속하려고 할 때 조건이 충족되지 않습니다.

  5. 경우 __new__()반환의 인스턴스 cls, 새로운 인스턴스의 __init__()메소드가 호출 될 것 같은 __init__(self[, ...])자기 새 인스턴스이고, 나머지 인수에 전달 된 동일합니다 __new__().

    instance이미 초기화되었으므로 함수는 __init__아무것도하지 않는 함수로 대체 됩니다.

온라인 작업 확인


0

그것은 fab의 답변과 약간 유사하지만 정확히 동일하지는 않습니다.

단일 계약은 우리가 생성자를 여러 번 호출 할 수 필요가 없습니다. 싱글 톤은 한 번만 생성해야하므로 한 번만 생성되는 것으로 보이지 않아야합니까? 생성자를 "스푸핑"하면 가독성이 손상 될 수 있습니다.

그래서 내 제안은 이것입니다 :

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()

참고 사항 :

  1. python2.x의 객체에서 서브 클래스를 작성하지 않으면 이전 스타일의 클래스를 얻습니다. __new__
  2. 장식 __new__할 때 @classmethod로 장식해야하거나 __new__바인딩되지 않은 인스턴스 메소드가됩니다.
  3. 메타 클래스를 사용 the하면 클래스 수준 속성 을 만들 수 있으므로 메타 클래스를 사용하여 향상시킬 수 있습니다.instance

이것은 싱글 톤 패턴에 대한 약간 다른 해석이지만 , 클래스 속성에 순전히 작용하여 잠시 두 번째 인스턴스가되는 것을 막기 때문에 __new__ 대신 __ 을 사용하고 싶을 수도 있지만 여전히 유효하다고 확신합니다 __init__. 이 방법과 방법 2의 차이점은 초기화를 두 번 이상 초기화하려고하면 단일 인스턴스를 반환하는지 아니면 예외가 발생하는지입니다. 나는 싱글 톤 패턴을 만족 시키거나, 하나는 사용하기 쉽고, 다른 하나는 싱글 톤임을 더 분명하게 생각합니다.
theheadofabroom

분명히에서 클래스 이름의 사용 __init__방지는 서브 클래스 만이 쉽게 일을하게하면서, 그럴 필요는 아니에요
theheadofabroom

고마워 ... 아, 예외가 발생하기 전에 순간 두 번째 인스턴스. 내가 수정 한 __init__희망이 subclassable해야한다고 그래서 ...
마이크 설치류

쿨, the아마 비슷한 이유로 수업 방법으로 혜택을받을 수 있습니다
theheadofabroom

네 말이 맞아. 그런 다음 SuperElvis 서브 클래스 싱글 톤과 (예를 들어) ImaginaryElvis 서브 클래스 싱글 톤을 가질 수 있으며 공존 할 수 있습니다. 추가 생각을보십시오. 내 코드를 자유롭게 개선하십시오.
마이크 설치류

0

하나의 라이너 (나는 자랑스럽지 않지만 일을합니다) :

class Myclass:
  def __init__(self):
      # do your stuff
      globals()[type(self).__name__] = lambda: self # singletonify

수업을 다른 모듈로 가져 오지 않는
Aran-Fey

진실. 클래스를 초기화하는 비용을 지불 할 수 있다면 클래스 정의 직후 Myclass ()를 실행하여이를 피할 수 있습니다.
polvoazul

0

Singleton 인스턴스의 지연 초기화가 필요하지 않은 경우 다음이 쉽고 스레드로부터 안전해야합니다.

class A:
    instance = None
    # Methods and variables of the class/object A follow
A.instance = A()

이 방법 A은 모듈 가져 오기에서 초기화 된 단일 항목입니다.


0

아마도 싱글 톤 패턴을 이해하지 못할 수도 있지만 내 해결책은 간단하고 실용적입니다 (pythonic?). 이 코드는 두 가지 목표를 완수합니다

  1. Foo어디서나 액세스 할 수 있는 인스턴스를 만듭니다 (전 세계).
  2. 하나의 인스턴스 만 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!

0

이 문제로 얼마 동안 어려움을 겪은 후 결국 다음을 생각해 냈습니다. 따라서 별도의 모듈에서 호출 될 때 구성 객체가 한 번만로드됩니다. 메타 클래스는 글로벌 클래스 인스턴스가 내장 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>...

-1

이 솔루션을 찾은 곳을 기억할 수 없지만 파이썬이 아닌 전문가 관점에서 가장 '우아한'것으로 나타났습니다.

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__메소드를 삭제하십시오 . 파이썬 (일반적으로 OOP)을 처음 접할 때 누군가 이것이 왜 끔찍한 접근 방식인지에 대해 나에게 직접 설정 할 것으로 기대합니다.


2
왜 이것이 끔찍한 접근입니까? 다른 싱글 톤 클래스를 만들려면을 복사하여 붙여 넣어야합니다 __new__. 자신을 반복하지 마십시오 .
GingerPlusPlus

또한, 왜 새가 소요 *args하고 **kwargs, 다음 그들과 함께 아무것도하지 않는다? 로 전달 dict.__new__이 방법 : dict.__new__(cls, *args, **kwargs).
GingerPlusPlus

__init__클래스가 호출 될 때마다 메소드 를 호출합니다 . 귀하의 경우 __init__방법이 실제로 일을했다, 당신은 문제가 나타날 것입니다. 당신이 할 때마다 SomeSingleton(), 싱글 톤의 상태는 __init__메소드에 의해 재설정됩니다 .
Aran-Fey

-2

이것이 싱글 톤을 구현하는 데 선호되는 방법입니다.

class Test(object):
    obj = None

    def __init__(self):
        if Test.obj is not None:
            raise Exception('A Test Singleton instance already exists')
        # Initialization code here

    @classmethod
    def get_instance(cls):
        if cls.obj is None:
            cls.obj = Test()
        return cls.obj

    @classmethod
    def custom_method(cls):
        obj = cls.get_instance()
        # Custom Code here

1
이것은 클래스의 인스턴스가 둘 이상 존재할 수 있으므로 엄격하게 싱글 톤이 아닙니다. 개선은없는 클래스가 초기화 될 수 있도록, 그리고 모든 클래스 메소드는 클래스 속성에 따라 행동 할 것이다
theheadofabroom

-2

이 답변은 당신이 찾고있는 것이 아닐 것입니다. 나는 그 객체만이 그 정체성을 가지고 있다는 점에서 싱글 톤을 원했습니다. 내 경우에는 Sentinel Value 로 사용되었습니다 . 대답이 매우 간단한 대상을 mything = object()만들고 파이썬의 본질에 따라 그 것만 정체성을 갖습니다.

#!python
MyNone = object()  # The singleton

for item in my_list:
    if item is MyNone:  # An Example identity comparison
        raise StopIteration

모듈을 실제로 여러 번 가져올 수 있다는 것을 배웠습니다.이 경우 이것은 로컬 단일 톤이며 실제로는 단일 용량이 아닙니다.
ThorSummoner

모듈을 여러 번 가져올 수있는 방법에 대해 자세히 설명 할 수 있습니까? 내가 본 유일한 시간은 모듈이로드되는 동안 예외가 발생했을 때 사용자가 나중에 모듈을로드 할 수 있지만 부작용이 이미 발생했기 때문에 일부 작업이 두 번째로 실행될 수 있습니다.
sleblanc 2016 년

모듈이 완전히로드되면 인터프리터가 evalor를 사용하여 모듈을 강제 실행하는 것 외에는이 모듈을 다시 실행할 수있는 방법이 없습니다 importlib.reload.
sleblanc 2016 년

-3

이 솔루션은 모듈 수준에서 일부 네임 스페이스 오염을 유발하지만 (단 하나가 아닌 세 가지 정의) 따르기 쉽습니다.

나는 이와 같은 것을 쓸 수 있기를 원하지만 (지연된 초기화) 불행히도 클래스는 자체 정의 본문에서 사용할 수 없습니다.

# wouldn't it be nice if we could do this?
class Foo(object):
    instance = None

    def __new__(cls):
        if cls.instance is None:
            cls.instance = object()
            cls.instance.__class__ = Foo
        return cls.instance

불가능하기 때문에 초기화와 정적 인스턴스를 분리 할 수 ​​있습니다.

열망 초기화 :

import random


class FooMaker(object):
    def __init__(self, *args):
        self._count = random.random()
        self._args = args


class Foo(object):
    def __new__(self):
        return foo_instance


foo_instance = FooMaker()
foo_instance.__class__ = Foo

지연 초기화 :

열망 초기화 :

import random


class FooMaker(object):
    def __init__(self, *args):
        self._count = random.random()
        self._args = args


class Foo(object):
    def __new__(self):
        global foo_instance
        if foo_instance is None:
            foo_instance = FooMaker()
        return foo_instance


foo_instance = None
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.