Skip to content

Latest commit

Β 

History

History
327 lines (243 loc) Β· 10 KB

singleton.md

File metadata and controls

327 lines (243 loc) Β· 10 KB

싱글톀 (Singleton) λ””μžμΈ νŒ¨ν„΄

μž‘μ„±μž : μ •ν¬μž¬

λ³Έ μžλ£ŒλŠ” '파이썬 λ””μžμΈ νŒ¨ν„΄ 2/e (Chetan Giridhar)' 책을 ν† λŒ€λ‘œ μž‘μ„±λ˜μ—ˆμŠ΅λ‹ˆλ‹€. λ”°λΌμ„œ λͺ¨λ“  μ˜ˆμ‹œ μ½”λ“œμ—λŠ” μ €μžλ₯Ό ν‘œμ‹œν•˜λŠ” __author__ = 'Chetan' 이 ν¬ν•¨λ©λ‹ˆλ‹€.

Table of Contents

싱글톀 (Singleton) λ””μžμΈ νŒ¨ν„΄μ΄λž€

싱글톀 λ””μžμΈ νŒ¨ν„΄μ€ κΈ€λ‘œλ²Œν•˜κ²Œ μ ‘κ·Ό κ°€λŠ₯ν•œ 단 ν•œ 개의 κ°μ²΄λ§Œμ„ ν—ˆμš©ν•˜λŠ” νŒ¨ν„΄μ΄λ‹€.

싱글톀 λ””μžμΈ νŒ¨ν„΄μ˜ λͺ©μ 

  • ν΄λž˜μŠ€μ— λŒ€ν•œ 단일 객체 생성
  • μ „μ—­ 객체 제곡
  • 곡유된 λ¦¬μ†ŒμŠ€μ— λŒ€ν•œ λ™μ‹œ μ ‘κ·Ό μ œμ–΄

싱글톀 νŒ¨ν„΄ κ΅¬ν˜„

Python

__author__ = 'Chetan'

class Singleton(object):
    def __new__(cls):
      if not hasattr(cls, 'instance'):
        cls.instance = super(Singleton, cls).__new__(cls)
      return cls.instance
    
s = Singleton()
print("Object created", s)

s1 = Singleton()
print("Object created", s1)

''' <μ‹€ν–‰ κ²°κ³Ό>
Object created <__main__.Singleton object at 0x1005c12b0>
Object created <__main__.Singleton object at 0x1005c12b0>
'''
  • ν•œ 개의 instance 클래슀 μΈμŠ€ν„΄μŠ€λ₯Ό μƒμ„±ν•œλ‹€.
  • 이미 μƒμ„±λœ μΈμŠ€ν„΄μŠ€κ°€ μžˆλ‹€λ©΄ μž¬μ‚¬μš©ν•œλ‹€.

게으λ₯Έ μ΄ˆκΈ°ν™”

μΈμŠ€ν„΄μŠ€κ°€ κΌ­ ν•„μš”ν•œ 상황일 λ•Œ μ΄ˆκΈ°ν™”λ₯Ό ν•œλ‹€. μ‚¬μš©ν•  수 μžˆλŠ” λ¦¬μ†ŒμŠ€κ°€ μ œν•œμ μΌ λ•Œ μ‚¬μš©ν•˜λŠ” 방식이닀.

__author__ = 'Chetan'   

class Singleton:

    __instance = None
    
    def __init__(self):
        if not Singleton.__instance:
            print(" __init__ method called..")
        else:
            print("Instance already created:", self.getInstance())
    
    @classmethod
    def getInstance(cls):
        if not cls.__instance:
            cls.__instance = Singleton()
        return cls.__instance

s = Singleton()
## ν΄λž˜μŠ€λŠ” μ΄ˆκΈ°ν™” λ˜μ—ˆμ§€λ§Œ 아직 κ°μ²΄λŠ” μƒμ„±λ˜μ§€ μ•Šμ•˜λ‹€.
print("Object created", Singleton.getInstance())
## 객체λ₯Ό μƒμ„±ν–ˆλ‹€.
s1 = Singleton()
## κ°μ²΄λŠ” 이미 μƒμ„±λ˜μ—ˆλ‹€.

''' <μ‹€ν–‰ κ²°κ³Ό>
__init__ method called..
 __init__ method called..
Object created <__main__.Singleton object at 0x10ca025c0>
Instance already created: <__main__.Singleton object at 0x10ca025c0>
'''
  • getInstance()둜 μ–»μ–΄μ˜€λŠ” μ£Όμ†Œκ°€ μΌμΉ˜ν•˜λŠ” 것을 λ³Ό 수 μžˆλ‹€.

λͺ¨λ“ˆ 싱글톀

νŒŒμ΄μ¬μ—μ„œ λͺ¨λ“  λͺ¨λ“ˆμ€ 기본적으둜 싱글톀이닀. ν•œ 개의 객체만 μœ μ§€ν•˜κ³  λ°˜ν™˜ν•˜λŠ” 싱글톀 방식이닀. 파이썬의 λͺ¨λ“ˆ μž„ν¬νŠΈ 방식은 λ‹€μŒκ³Ό κ°™λ‹€.

  • 파이썬 λͺ¨λ“ˆμ΄ μž„ν¬νŠΈλλŠ”μ§€ ν™•μΈν•œλ‹€.
  • μž„ν¬νŠΈ 됐닀면 ν•΄λ‹Ή 객체λ₯Ό λ°˜ν™˜ν•œλ‹€.
  • μž„ν¬νŠΈλ˜μ§€ μ•Šμ•˜λ‹€λ©΄ μž„ν¬νŠΈν•˜κ³  μΈμŠ€ν„΄μŠ€ν™” ν•œλ‹€.
  • λͺ¨λ“ˆμ€ μž„ν¬νŠΈμ™€ λ™μ‹œμ— μ΄ˆκΈ°ν™”λœλ‹€. ν•˜μ§€λ§Œ 같은 λͺ¨λ“ˆμ„ λ‹€μ‹œ μž„ν¬νŠΈν•˜λ©΄ μ΄ˆκΈ°ν™”ν•˜μ§€ μ•ŠλŠ”λ‹€.
import sys
import sys

이처럼 같은 λͺ¨λ“ˆμ„ μ€‘λ³΅ν•΄μ„œ μž„ν¬νŠΈν•΄λ„ sysκ°μ²΄λŠ” ν•˜λ‚˜λ§Œ μƒμ„±λœλ‹€.

λͺ¨λ…ΈμŠ€ν…Œμ΄νŠΈ 싱글톀 νŒ¨ν„΄

싱글톀 νŒ¨ν„΄κ³Ό 달리 두 개 μ΄μƒμ˜ 객체가 생성될 수 μžˆμ§€λ§Œ λͺ¨λ“  객체가 μƒνƒœλ₯Ό κ³΅μœ ν•œλ‹€.

λͺ¨λ…ΈμŠ€ν…Œμ΄νŠΈ 싱글톀 μ˜ˆμ‹œ

__author__ = 'Chetan'   

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

b = Borg()
b1 = Borg()
b.x = 3

print("Borg Object 'b': ", b)
print("Borg Object 'b1': ", b1)
## b와 b1은 μ„œλ‘œ λ‹€λ₯Έ 객체닀.
print("Object State 'b':", b.__dict__)
print("Object State 'b1':", b1.__dict__)
## κ·ΈλŸ¬λ‚˜ μ„œλ‘œ stateλ₯Ό κ³΅μœ ν•œλ‹€.

''' <μ‹€ν–‰ κ²°κ³Ό>
Borg Object 'b':  <__main__.Borg object at 0x10d6d95c0>
Borg Object 'b1':  <__main__.Borg object at 0x10d6d95f8>
Object State 'b': {'x': 3}
Object State 'b1': {'x': 3}
'''

싱글톀과 λ©”νƒ€ν΄λž˜μŠ€

λ©”νƒ€ν΄λž˜μŠ€λŠ” 클래슀의 ν΄λž˜μŠ€λ‹€. 즉 ν΄λž˜μŠ€λŠ” μžμ‹ μ˜ λ©”νƒ€ν΄λž˜μŠ€μ˜ μΈμŠ€ν„΄μŠ€λ‹€. ν΄λž˜μŠ€λŠ” λ©”νƒ€ν΄λž˜μŠ€κ°€ μ •μ˜ν•œλ‹€.

class A ꡬ문으둜 클래슀λ₯Ό μƒμ„±ν•˜λ©΄ νŒŒμ΄μ¬μ€ A = type(name, bases, dict) λ₯Ό μ‹€ν–‰ν•œλ‹€. 이미 μ •μ˜λœ λ©”νƒ€ν΄λž˜μŠ€κ°€ μžˆλ‹€λ©΄ νŒŒμ΄μ¬μ€ A = MetaKls(name, bases, dict) λ₯Ό μ‹€ν–‰ν•΄ 클래슀λ₯Ό μƒμ„±ν•œλ‹€.

  • name : 클래슀λͺ…
  • base : 베이슀 클래슀
  • dict : 속성 κ°’

λ©”νƒ€ν΄λž˜μŠ€ κ΅¬ν˜„μ½”λ“œ

__author__ = 'Chetan'

class MyInt(type):
    
    def __call__(cls, *args, **kwds):
        print("***** Here's My int *****", args)
        print("Now do whatever you want with these objects...")
        return type.__call__(cls, *args, **kwds)

class int(metaclass=MyInt):
    
    def __init__(self, x, y):
        self.x = x
        self.y = y
        pass

i = int(4,5)
i = int(7,8)

''' <μ‹€ν–‰ κ²°κ³Ό>
***** Here's My int ***** (4, 5)
Now do whatever you want with these objects...
***** Here's My int ***** (7, 8)
Now do whatever you want with these objects...
'''
  • __call__ λ©”μ†Œλ“œλŠ” 이미 μ‘΄μž¬ν•˜λŠ” 클래슀의 객체λ₯Ό 생성할 λ•Œ ν˜ΈμΆœλ˜λŠ” 파이썬의 특수 λ©”μ†Œλ“œλ‹€.
  • 객체 생성을 λ©”νƒ€ν΄λž˜μŠ€κ°€ μ œμ–΄ν•œλ‹€.
  • λ©”νƒ€ν΄λž˜μŠ€κ°€ ν΄λž˜μŠ€μ™€ 객체 생성을 μ œμ–΄ν•˜κΈ° λ•Œλ¬Έμ— 싱글톀을 μƒμ„±ν•˜λŠ” μš©λ„λ‘œ μ‚¬μš©ν•  수 μžˆλ‹€.

λ©”νƒ€ν΄λž˜μŠ€λ₯Ό μ‚¬μš©ν•œ 싱글톀 νŒ¨ν„΄ κ΅¬ν˜„

__author__ = 'Chetan'

class MetaSingleton(type):
    
    _instances = {}
    def __call__(cls, *args, **kwargs):
        if cls not in cls._instances:
            cls._instances[cls] = super(MetaSingleton, cls).__call__(*args, **kwargs)
        return cls._instances[cls]

class Logger(metaclass=MetaSingleton):
    pass

logger1 = Logger()
logger2 = Logger()
print(logger1)
print(logger2)

''' <μ‹€ν–‰ κ²°κ³Ό>
<__main__.Logger object at 0x1059635c0>
<__main__.Logger object at 0x1059635c0>
'''

싱글톀 νŒ¨ν„΄ μ‚¬μš© 사둀 1

ν•œ 개의 DBλ₯Ό κ³΅μœ ν•˜λŠ” ν΄λΌμš°λ“œ μ„œλΉ„μŠ€μ˜ 예.

  • λ°μ΄ν„°λ² μ΄μŠ€μ˜ 일관성을 보쑴해야 ν•œλ‹€. μ—°μ‚° κ°„μ˜ 좩돌이 μ—†μ–΄μ•Ό ν•œλ‹€.
  • λ‹€μˆ˜μ˜ DB 연산을 μ²˜λ¦¬ν•˜λ €λ©΄ λ©”λͺ¨λ¦¬μ™€ CPUλ₯Ό 효율적으둜 μ‚¬μš©ν•΄μ•Ό ν•œλ‹€.
__author__ = 'Chetan'

import sqlite3
class MetaSingleton(type):
    
    _instances = {}
    def __call__(cls, *args, **kwargs):
        if cls not in cls._instances:
            cls._instances[cls] = super(MetaSingleton, cls).__call__(*args, **kwargs)
        return cls._instances[cls]

class Database(metaclass=MetaSingleton):
    connection = None
    def connect(self):
        if self.connection is None:
            self.connection = sqlite3.connect("db.sqlite3")
            self.cursorobj = self.connection.cursor()
        return self.cursorobj

db1 = Database().connect()
db2 = Database().connect()

print ("Database Objects DB1", db1)
print ("Database Objects DB2", db2)

''' <μ‹€ν–‰ κ²°κ³Ό>
Database Objects DB1 <sqlite3.Cursor object at 0x1005d9c00>
Database Objects DB2 <sqlite3.Cursor object at 0x1005d9c00>
'''
  • Database ν΄λž˜μŠ€λŠ” MetaSingleton λ©”νƒ€ν΄λž˜μŠ€μ˜ λ„μ›€μœΌλ‘œ 싱글톀 역할을 ν•œλ‹€. 단 ν•œ 개의 Database 클래슀 객체만 μƒμ„±λœλ‹€.
  • μ›Ή 앱이 DB 연산을 μš”μ²­ν•  λ•Œλ§ˆλ‹€ Database 클래슀λ₯Ό μƒμ„±ν•˜μ§€λ§Œ λ‚΄λΆ€μ μœΌλ‘œ ν•œ 개의 객체만 μƒμ„±λœλ‹€. λ”°λΌμ„œ λ°μ΄ν„°λ² μ΄μŠ€μ˜ 동기화가 보μž₯λœλ‹€. λ¦¬μ†ŒμŠ€λ₯Ό 적게 μ‚¬μš©ν•΄ λ©”λͺ¨λ¦¬μ™€ CPUμ‚¬μš©λŸ‰μ„ μ΅œμ ν™”ν•  수 μžˆλ‹€.

싱글톀 νŒ¨ν„΄ μ‚¬μš© 사둀 2

인프라 μƒνƒœλ₯Ό ν™•μΈν•˜λŠ” μ„œλΉ„μŠ€μ˜ 예.

  • HealthCheck 클래슀λ₯Ό μ‹±κΈ€ν†€μœΌλ‘œ κ΅¬ν˜„ν•œλ‹€.
  • μƒνƒœλ₯Ό 확인해야 ν•˜λŠ” μ„œλ²„μ˜ λͺ©λ‘μ„ λ§Œλ“€κ³  λͺ©λ‘μ—μ„œ 제거된 μ„œλ²„μ˜ μƒνƒœλŠ” ν™•μΈν•˜μ§€ μ•Šμ•„μ•Ό ν•œλ‹€.
__author__ = 'Chetan'

class HealthCheck:
    
    _instance = None
    def __new__(cls, *args, **kwargs):
        if not HealthCheck._instance:
            HealthCheck._instance = super(HealthCheck, cls).__new__(cls, *args, **kwargs)
        return HealthCheck._instance
    
    def __init__(self):
        self._servers = []
    
    def addServer(self):
        self._servers.append("Server 1")
        self._servers.append("Server 2")
        self._servers.append("Server 3")
        self._servers.append("Server 4")
    
    def changeServer(self):
        self._servers.pop()
        self._servers.append("Server 5")

hc1 = HealthCheck()
hc2 = HealthCheck()

hc1.addServer()
print("Schedule health check for servers (1)..")
for i in range(4):
    print("Checking ", hc1._servers[i])


hc2.changeServer()
print("Schedule health check for servers (2)..")
for i in range(4):
    print("Checking ", hc2._servers[i])

''' <μ‹€ν–‰ κ²°κ³Ό>
Schedule health check for servers (1)..
Checking  Server 1
Checking  Server 2
Checking  Server 3
Checking  Server 4
Schedule health check for servers (2)..
Checking  Server 1
Checking  Server 2
Checking  Server 3
Checking  Server 5
'''
  • addServer() λ©”μ†Œλ“œλŠ” μ„œλ²„λ₯Ό λͺ©λ‘μ— μΆ”κ°€ν•œλ‹€.
  • changeServer() λ©”μ†Œλ“œλŠ” μ„œλ²„λ₯Ό λͺ©λ‘μ—μ„œ μ œκ±°ν•˜κ³  μƒˆλ‘œμš΄ μ„œλ²„λ₯Ό μΆ”κ°€ν•œλ‹€.
  • h1κ³Ό h2λŠ” μ‹±κΈ€ν†€μœΌλ‘œ μƒμ„±λœ κ°μ²΄μ΄λ―€λ‘œ λ™μΌν•œ 객체닀.

싱글톀 νŒ¨ν„΄μ˜ 단점

  • μ „μ—­ λ³€μˆ˜μ˜ 값이 μ‹€μˆ˜λ‘œ λ³€κ²½λœ 것을 λͺ¨λ₯΄κ³  μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ—μ„œ μ‚¬μš©λ  수 μžˆλ‹€.
  • 같은 객체에 λŒ€ν•œ μ—¬λŸ¬ μ°Έμ‘°μžκ°€ 생길 수 μžˆλ‹€. 싱글톀은 ν•œ 개의 κ°μ²΄λ§Œμ„ λ§Œλ“€κΈ° λ•Œλ¬Έμ— 같은 객체에 λŒ€ν•œ μ—¬λŸ¬ 개의 μ°Έμ‘°μžκ°€ 생긴닀.
  • μ „μ—­ λ³€μˆ˜μ— 쒅속적인 λͺ¨λ“  클래슀 κ°„ μƒν˜Έκ΄€κ³„κ°€ λ³΅μž‘ν•΄μ§„λ‹€. μ „μ—­ λ³€μˆ˜ μˆ˜μ •μ΄ μ˜λ„μΉ˜ μ•Šκ²Œ λ‹€λ₯Έ ν΄λž˜μŠ€μ—λ„ 영ν–₯을 쀄 수 μžˆλ‹€.