소위 싱글톤이란 클래스의 인스턴스가 처음부터 끝까지 한 번만 생성될 수 있음을 의미합니다.
방법 1
클래스의 인스턴스가 처음부터 끝까지 하나만 있도록 하려면 __new__ 메서드를 사용하면 매우 간단합니다. Python의 클래스는 __new__를 통해 인스턴스를 생성합니다.
class Singleton(object): def __new__(cls,*args,**kwargs): if not hasattr(cls,'_inst'): cls._inst=super(Singleton,cls).__new__(cls,*args,**kwargs) return cls._inst if __name__=='__main__': class A(Singleton): def __init__(self,s): self.s=s a=A('apple') b=A('banana') print id(a),a.s print id(b),b.s
결과:
29922256 바나나
29922256 바나나
클래스 인스턴스가 생성될 때 클래스 속성 _inst에 바인딩하려면 __new__ 메서드를 사용하세요. cls._inst가 None이면 클래스가 인스턴스화되지 않았음을 의미합니다. 인스턴스를 인스턴스화하고 cls._inst에 바인딩합니다. 첫 번째 인스턴스화로 생성된 인스턴스는 나중에 인스턴스화될 때마다 반환됩니다. Singleton에서 하위 클래스를 파생할 때 __new__를 오버로드하지 마세요.
방법 2:
생성된 인스턴스가 동일한 ID를 가지고 있는지 여부는 신경 쓰지 않고 상태와 동작에만 관심이 있는 경우가 있습니다. 많은 인스턴스가 생성되도록 허용할 수 있지만 모든
class Borg(object): _shared_state={} def __new__(cls,*args,**kwargs): obj=super(Borg,cls).__new__(cls,*args,**kwargs) obj.__dict__=cls._shared_state return obj
은 모든 인스턴스의 __dict__가 동일한 사전을 가리키므로 인스턴스가 동일하게 공유합니다. 메소드와 속성. __init__에서 수정했든 직접 수정했든 모든 인스턴스의 name 속성 설정은 모든 인스턴스에 영향을 미칩니다. 그러나 인스턴스 ID는 다릅니다. 클래스 인스턴스가 속성을 공유할 수 있지만 하위 클래스와는 공유할 수 없도록 하려면 Borg._shared_state 대신 cls._shared_state를 사용해야 합니다.
인스턴스마다 ID가 다르기 때문에 각 인스턴스를 사전 키로 사용할 수 있습니다.
if __name__=='__main__': class Example(Borg): pass a=Example() b=Example() c=Example() adict={} j=0 for i in a,b,c: adict[i]=j j+=1 for i in a,b,c: print adict[i]
결과:
0
1
2
이 동작이 원하는 것이 아니라면 Borg 클래스에 __eq__ 및 __hash__ 메서드를 추가하여 싱글톤에 가까운 동작으로 만들 수 있습니다. 패턴:
class Borg(object): _shared_state={} def __new__(cls,*args,**kwargs): obj=super(Borg,cls).__new__(cls,*args,**kwargs) obj.__dict__=cls._shared_state return obj def __hash__(self): return 1 def __eq__(self,other): try: return self.__dict__ is other.__dict__ except: return False if __name__=='__main__': class Example(Borg): pass a=Example() b=Example() c=Example() adict={} j=0 for i in a,b,c: adict[i]=j j+=1 for i in a,b,c: print adict[i]
결과:
2
2
2
모든 인스턴스를 키로 사용할 수 있습니다.
방법 3
클래스를 작성할 때 일부 메커니즘은 클래스 이름, 기본 클래스 튜플 및 클래스 사전을 사용하여 클래스 객체를 생성합니다. 새 클래스의 이 메커니즘은 기본적으로 유형이며 이 메커니즘은 프로그래밍 가능하며 메타클래스 __metaclass__라고 합니다.
class Singleton(type): def __init__(self,name,bases,class_dict): super(Singleton,self).__init__(name,bases,class_dict) self._instance=None def __call__(self,*args,**kwargs): if self._instance is None: self._instance=super(Singleton,self).__call__(*args,**kwargs) return self._instance if __name__=='__main__': class A(object): __metaclass__=Singleton a=A() b=A() print id(a),id(b)
결과:
34248016
id가 동일합니다.
이 예에서는 Singleton 메타클래스를 생성하고 __call__ 메서드를 사용하여 함수 동작을 시뮬레이션합니다. 클래스 A를 생성할 때 해당 메타클래스를 싱글톤으로 설정한 다음 클래스 객체 A를 생성할 때 동작은 다음과 같습니다.
A=Singleton(name, bases, class_dict), A는 실제로 싱글톤 클래스의 인스턴스입니다. .
A의 인스턴스를 생성할 때 A()=Singleton(name,bases,class_dict)()=Singleton(name,bases,class_dict).__call__(), 따라서 A의 모든 인스턴스를 가리킵니다. A의 _instance 속성, 이 메소드는 실제로 메소드 1과 동일합니다.
방법 4
파이썬의 모듈 모듈은 프로그램에서 한 번만 로드되며 싱글톤 그 자체입니다. 모듈을 직접 작성하고 모듈에 필요한 메소드와 속성을 모듈 범위의 함수 및 전역 변수로 작성할 수 있습니다. 클래스를 작성할 필요가 전혀 없습니다.
그리고 모듈과 클래스의 장점을 결합하는 몇 가지 방법이 있습니다.
class _singleton(object): class ConstError(TypeError): pass def __setattr__(self,name,value): if name in self.__dict__: raise self.ConstError self.__dict__[name]=value def __delattr__(self,name): if name in self.__dict__: raise self.ConstError raise NameError import sys sys.modules[__name__]=_singleton()
Python은 sys.modules를 확인하지 않습니다. 모듈 개체이므로 이를 사용하여 모듈을 클래스 개체에 바인딩하고 나중에 동일한 개체에 바인딩할 것입니다.
Single.py에 코드를 저장합니다:
>>> import single >>> single.a=1 >>> single.a=2
ConstError
>>> del Single.a
ConstError
방법 5
가장 간단한 방법:
class singleton(object): pass singleton=singleton()
싱글톤이라는 이름을 인스턴스에 바인딩합니다. 싱글톤은 해당 클래스의 유일한 개체입니다.