[python] 싱글 톤을 정의하는 간단하고 우아한 방법이 있습니까? [닫은]



Answers

내 독단의 구현은 다음과 같습니다. 수업을 꾸미기 만하면됩니다. 싱글 톤을 얻으려면 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. Also, the decorated class cannot be
    inherited from. 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.

    """

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

파이썬에서 싱글 톤 을 정의하는 많은 방법이있는 것처럼 보입니다. 에 대한 의견 일치가 있습니까?




데코레이터로 싱글 톤 패턴을 구현하여 PEP318 에서이 구현을 참조하십시오.

def singleton(cls):
    instances = {}
    def getinstance():
        if cls not in instances:
            instances[cls] = cls()
        return instances[cls]
    return getinstance

@singleton
class MyClass:
    ...



나는 클래스 또는 인스턴스를 싱글 톤이되도록 강제 하는 것은 과잉이라고 생각한다. 개인적으로, 나는 정상적인 인스턴스화 가능한 클래스, 준 개인 참조, 그리고 간단한 팩토리 함수를 정의하고 싶다.

class NothingSpecial:
    pass

_the_one_and_only = None

def TheOneAndOnly():
    global _the_one_and_only
    if not _the_one_and_only:
        _the_one_and_only = NothingSpecial()
    return _the_one_and_only

또는 모듈을 처음 가져올 때 인스턴스화에 문제가없는 경우 :

class NothingSpecial:
    pass

THE_ONE_AND_ONLY = NothingSpecial()

그렇게하면 부작용없이 새로운 인스턴스에 대한 테스트를 작성할 수 있으며 전역 명령문을 사용하여 모듈을 뿌릴 필요가 없습니다. 필요한 경우 나중에 변형을 파생시킬 수 있습니다.




파이썬에서 싱글 톤을 구현하는 약간 다른 접근법은 Alex Martelli (Google 직원 및 Python 천재)의 borg 패턴 입니다.

class Borg:
    __shared_state = {}
    def __init__(self):
        self.__dict__ = self.__shared_state

따라서 모든 인스턴스가 동일한 ID를 갖도록 강요하는 대신 상태를 공유합니다.




한 번 파이썬에서 싱글 톤을 썼는데, 모든 멤버 함수에 classmethod 데코레이터가있는 클래스를 사용했습니다.

class foo:
  x = 1

  @classmethod
  def increment(cls, y = 1):
    cls.x += y



위의 메타 클래스 기반 솔루션을 원하지 않고 단순 함수 데코레이터 기반 접근 방식을 선호하지 않는 경우 (예 : 싱글 톤 클래스의 정적 메서드가 작동하지 않기 때문에)이 절충안이 작동합니다.

class singleton(object):
  """Singleton decorator."""

  def __init__(self, cls):
      self.__dict__['cls'] = cls

  instances = {}

  def __call__(self):
      if self.cls not in self.instances:
          self.instances[self.cls] = self.cls()
      return self.instances[self.cls]

  def __getattr__(self, attr):
      return getattr(self.__dict__['cls'], attr)

  def __setattr__(self, attr, value):
      return setattr(self.__dict__['cls'], attr, value)



싱글 톤 데코레이터 (별명이라고도 함)를 만드는 것은 앞으로 클래스를 장식 (주석 달기)하려는 경우 우아한 방법입니다. 그런 다음 클래스 정의 앞에 @singleton을 넣으면됩니다.

def singleton(cls):
    instances = {}
    def getinstance():
        if cls not in instances:
            instances[cls] = cls()
        return instances[cls]
    return getinstance

@singleton
class MyClass:
    ...



비교적 새로운 Python에 익숙하기 때문에 가장 일반적인 관용구가 무엇인지 모르겠지만 가장 간단한 것은 클래스 대신 모듈을 사용하는 것입니다. 클래스의 인스턴스 메소드는 모듈의 함수가되고 모든 데이터는 클래스의 멤버가 아닌 모듈의 변수가됩니다. 나는 이것이 사람들이 싱글 톤을 사용하는 문제 유형을 해결하기위한 파이썬 적 접근이라고 생각한다.

싱글 톤 클래스를 정말로 원한다면 "파이썬 싱글 톤" 에 대한 Google첫 번째 히트에 설명 된 합리적인 구현이있다.

class Singleton:
    __single = None
    def __init__( self ):
        if Singleton.__single:
            raise Singleton.__single
        Singleton.__single = self

그 트릭을 할 것으로 보인다.




싱글턴의 이복 형제

나는 staale에 완전히 동의하고 여기서 singleton half brother를 만드는 샘플을 남긴다.

class void:pass
a = void();
a.__class__ = Singleton

a 는 마치 싱글 톤과 같지 않더라도 싱글 톤과 동일한 클래스로보고합니다. 그래서 복잡한 클래스를 사용하는 싱글 톤은 우리가 그들에게 많은 것을 낭비하지 않는 것에 따라 끝납니다.

그렇기 때문에 우리는 변수 나 모듈과 같은 효과를 내고 더 단순한 것을 사용할 수 있습니다. 여전히 명확한 클래스를 사용 하고 파이썬에서 클래스가 객체 이기 때문에 우리는 이미 객체를 가지고 있습니다 (객체가 아니라 인스턴스입니다).

class Singleton:
    def __new__(cls): raise AssertionError # Singletons can't have instances

인스턴스를 만들려고하면 좋은 어설 션 오류가 발생하고 정적 멤버를 파생 클래스에 저장하고 런타임에 변경 사항을 적용 할 수 있습니다 (저는 Python을 좋아합니다). 이 객체는 다른 형제들과 마찬가지로 (당신이 원한다면 여전히 만들 수 있습니다.) 그러나 단순성으로 인해 더 빠르게 실행되는 경향이 있습니다.




class Singleton(object[,...]):

    staticVar1 = None
    staticVar2 = None

    def __init__(self):
        if self.__class__.staticVar1==None :
            # create class instance variable for instantiation of class
            # assign class instance variable values to class static variables
        else:
            # assign class static variable values to class instance variables



파이썬 문서 는 이것을 다루고 있습니다 :

class Singleton(object):
    def __new__(cls, *args, **kwds):
        it = cls.__dict__.get("__it__")
        if it is not None:
            return it
        cls.__it__ = it = object.__new__(cls)
        it.init(*args, **kwds)
        return it
    def init(self, *args, **kwds):
        pass

아마도 다음과 같이 보이도록 다시 작성합니다.

class Singleton(object):
    """Use to create a singleton"""
    def __new__(cls, *args, **kwds):
        """
        >>> s = Singleton()
        >>> p = Singleton()
        >>> id(s) == id(p)
        True
        """
        self = "__self__"
        if not hasattr(cls, self):
            instance = object.__new__(cls)
            instance.init(*args, **kwds)
            setattr(cls, self, instance)
        return getattr(cls, self)

    def init(self, *args, **kwds):
        pass

이것을 확장하려면 비교적 깨끗해야합니다.

class Bus(Singleton):
    def init(self, label=None, *args, **kwds):
        self.label = label
        self.channels = [Channel("system"), Channel("app")]
        ...



Links