'''
Паттерн Singleton
Паттерн гарантирует, что класс имеет только один экземпляр, 
предоставляет глобальную точку доступа к этому экзеемпляру.
Этот экземпляр обычно предоставляет доступ к определенным 
ресурсам или слажбам, таким как база данных, файловая система
или любая другая общая ресурсоемкая операция.
'''

class Singleton:
    _instance = None

    def __new__(cls):
        if not cls._instance:
            cls.instance = super(Singleton, cls).__new__(cls)
        return cls._instance

def test_1():
    instance_1 = Singleton()
    instance_2 = Singleton()

    print(id(instance_1))
    print(id(instance_2))

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

class AppSettings:
    __instance = None

    def __new__(cls):
        if not cls.__instance:
            cls.__instance = super(AppSettings, cls).__new__(cls)
            # Логика инициализации настроек (может быть сложной)
            cls.__instance.initialize_settings()
        return cls.__instance

    def initialize_settings(self):
        # Логика инициализации настроек
        self.app_name = 'MyApp 1.0'
        self.debug_mode = False
        self.log_level = 'INFO'

    @staticmethod
    def get_app():
        if not AppSettings.__instance:
            AppSettings.__new__(AppSettings)
        return AppSettings.__instance


def test_2():
    app_settings_1 = AppSettings.get_app()
    app_settings_2 = AppSettings()

    print(app_settings_1 is app_settings_2) # Выдает True

    print(app_settings_1.app_name)
    print(app_settings_2.app_name)
    print(app_settings_1.debug_mode)
    print(app_settings_2.debug_mode)

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

class Logger:
    __instance = None

    def __new__(cls):
        if not cls.__instance:
            cls.__instance = super(Logger, cls).__new__(cls)
            cls.log_level = 'INFO'
        return cls.__instance

    @staticmethod
    def set_level(level):
        if not Logger.__instance:
            raise ValueError('The instance has not created')
        Logger.log_level = level

    def new_method(self, level):
        return level

    @staticmethod
    def get_logger():
        if not Logger.__instance:
            Logger.__new__(Logger)
        return Logger.__instance

def test_3():
    logger_1 = Logger.get_logger()
    print(logger_1.log_level)  # Выведет "INFO"
    Logger.set_level("DEBUG")
    print(logger_1.log_level)  # Выведет "DEBUG"

    logger_2 = Logger.get_logger()
    print(logger_2.log_level)  # Выведет "DEBUG"
    print(logger_2 is logger_1)

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

'''
def singleton(func):
    def wrapper():
        original_result = func()
        modified_result = original_result + 1
        return modified_result
    return wrapper
'''

def singleton(cls):
    foo = None
    def wrapper():
        nonlocal foo
        if foo is None:
            foo = cls()
        return foo
    return wrapper

@singleton
class Logger:
    pass


@singleton
class AppConfig:
    pass


@singleton
class SMTPServerConfig:
    pass

def test_4():
    log = Logger()
    app_conf = AppConfig()
    app_conf_2 = AppConfig()
    smtp_conf = SMTPServerConfig()
    assert log is Logger()
    assert app_conf is app_conf_2
    assert smtp_conf is SMTPServerConfig()
    assert log is not app_conf
    assert log is not smtp_conf
    assert app_conf is not smtp_conf
    print('Good')




def main():
    # test_1()
    # test_2()
    # test_3()
    test_4()

if __name__ == '__main__':
    main()