问题:
Современные шоколадные фабрики имеют шоколадные котлы с компьютерным управлением. Что делает котел, так это плавит шоколад и молоко вместе и отправляет их на следующую стадию для изготовления шоколадных батончиков. Ниже приведен код контроллера котла шоколадной компании, посмотрите внимательнее, что не так с этим кодом?
class ChocolateBoiler(object):
def __init__(self):
self.empty = True
self.boiled = False
def fill(self):
# 向锅炉填充巧克力和牛奶混合物
# 在锅炉内填充原料时,锅炉必须是空的。
# 一旦填入原料,就要把empty 和 boiled 标志设置好
if self.empty:
self.empty = False
self.boiled = False
def drain(self):
# 排出煮沸的巧克力和牛奶
# 锅炉排出时,必须是满的且煮沸的。
# 排出完毕empty 设置为 true
if not self.empty and self.boiled:
self.empty = True
def boil(self):
# 将颅内物煮沸
# 煮混合物时,锅炉内必须是满的且没有煮沸过
# 一旦煮沸,就把 boiled 设置为 true
if not self.empty and not self.boiled:
self.boiled = True
Как видно из кода, они добавляют несколько суждений, чтобы предотвратить плохие вещи. Если есть дваChocolateBoiler
Например, так много суждений бесполезны. Так как же изменить это требование? Суть этой проблемы в том, что мы должны сначала определить, существует ли уже экземпляр, и если да, то он не будет создан.
_chocolate_boiler_instance = None # 声明实例
def chocolate_boiler():
global _chocolate_boiler_instance # 使用全局变量
if _chocolate_boiler_instance is not None: # 判断是否存在,如果存在,直接返回
return _chocolate_boiler_instance
else:
# 如果不存在,创建一个新的
_chocolate_boiler_instance = ChocolateBoiler()
return _chocolate_boiler_instance
Теперь нам нужно получитьChocolateBoiler
Когда вы используете экземпляр, вам нужно только вызвать метод Chocolate_boiler, чтобы получить экземпляр, чтобы убедиться, что в одно и то же время существует только один экземпляр.ChocolateBoiler
пример.
эта гарантияChocolateBoiler
Шаблон, который имеет только один экземпляр класса и предоставляет глобальную точку доступа, т.单例模式
.
одноэлементный шаблон
определение
单例模式:
Убедитесь, что существует только один экземпляр класса, и предоставьте глобальную точку доступа.
- Другими словами, мы используем шаблон singleton для разработки класса как отдельного экземпляра, управляемого самим собой, и в то же время избегаем того, чтобы другие классы генерировали экземпляры сами по себе. И получить экземпляр синглтона можно только через класс синглтона.
- Мы также предоставляем глобальную точку доступа к этому экземпляру: когда вам нужен экземпляр, например запрос класса, он возвращает один экземпляр.
выполнить
Есть несколько вариантов реализации рисунка Singleton в Python:
использовать метакласс
"поваренная книга Python" предоставляет очень простой в использованииSingleton
Класс, пока он наследуется от него, становится синглтоном.
# python 3 代码实现
class Singleton(type):
def __init__(self, *args, **kwargs):
self.__instance = None
super().__init__(*args, **kwargs)
def __call__(self, *args, **kwargs):
if self.__instance is None:
# 如果 __instance 不存在,创建新的实例
self.__instance = super().__call__(*args, **kwargs)
return self.__instance
else:
# 如果存在,直接返回
return self.__instance
class Spam(metaclass=Singleton):
def __init__(self):
print('Creating Spam')
a = Spam()
b = Spam()
print(a is b) # 这里输出为 True
Метакласс (metaclass) может управлять процессом создания класса, в основном он делает три вещи:
- Создание класса перехвата
- Изменить определение класса
- Возвращает измененный класс
В примере мы создаем метакласс Singleton и используемcallМетоды позволяют моделировать поведение функции. Когда создается класс Spam, его метакласс устанавливается в Singleton, затем при создании объекта класса Spam поведение происходит следующим образом:
Spam = Singleton(name, bases, class_dict), Спам на самом деле является экземпляром класса Singleton.
При создании экземпляра Spam Spam()=Singleton(name,bases,class_dict)()=Singleton(name,bases,class_dict).call(), который указывает всем экземплярам спама атрибут __instance спама.
использоватьnew
мы можем использоватьnewДля управления процессом создания экземпляра используется следующий код:
class Singleton(object):
__instance = None
def __new__(cls, *args, **kw):
if not cls.__instance:
cls.__instance = super().__new__(cls, *args, **kw)
return cls.__instance
class Foo(Singleton):
a = 1
one = Foo()
two = Foo()
assert one == two
assert one is two
assert id(one) == id(two)
пройти черезnewметод, который привязывает экземпляр класса к свойству класса при его созданииэкземпляр на. если клс.instance имеет значение None, что указывает на то, что экземпляр класса не был создан, создайте экземпляр и привяжите экземпляр к cls.instance возвращает экземпляр, созданный первым экземпляром, каждый раз, когда он создается. Будьте осторожны, чтобы не перегружаться при создании подклассов Singleton.новый__.
Используйте декоратор
import functools
def singleton(cls):
''' Use class as singleton. '''
# 首先将 __new__ 方法赋值给 __new_original__
cls.__new_original__ = cls.__new__
@functools.wraps(cls.__new__)
def singleton_new(cls, *args, **kw):
# 尝试从 __dict__ 取 __it__
it = cls.__dict__.get('__it__')
if it is not None: # 如果有值,说明实例已经创建,返回实例
return it
# 如果实例不存在,使用 __new_original__ 创建实例,并将实例赋值给 __it__
cls.__it__ = it = cls.__new_original__(cls, *args, **kw)
it.__init_original__(*args, **kw)
return it
# class 将原有__new__ 方法用 singleton_new 替换
cls.__new__ = singleton_new
cls.__init_original__ = cls.__init__
cls.__init__ = object.__init__
return cls
#
# 使用示例
#
@singleton
class Foo:
def __new__(cls):
cls.x = 10
return object.__new__(cls)
def __init__(self):
assert self.x == 10
self.x = 15
assert Foo().x == 15
Foo().x = 20
assert Foo().x == 20
Внутренняя реализация и использование этого метода__new__
аналогичный:
- Во-первых, поставитьnewметод, назначенныйnew_original,оригиналnewЗамена метода на Singleton_Newinit_originalи установить клс.initназначить наinit_original
- Внутри метода singleton_new попробуйте начать сdictВыбиратьit(пример)
- Если экземпляр не существует, используйтеnew_originalСоздайте экземпляр и назначьте экземплярit, затем верните экземпляр
самый простой способ
Привяжите имя singleton к экземпляру, и singleton станет единственным объектом своего собственного класса.
class singleton(object):
pass
singleton = singleton()
GitHub.com/cousby/me упоминает…Это способ получить глобальный запрос
Модуль Python является естественным одноэлементным режимом, потому что при первом импорте модуля будет создан файл .pyc, а при повторном импорте файл .pyc будет загружен напрямую, без выполнения кода модуля. опять таки. Поэтому нам нужно только определить связанные функции и данные в модуле, чтобы получить одноэлементный объект.
Ссылка на ссылку
- Creating a singleton in Python
- Одноэлементный шаблон Python
- Why is init() always called after new()?
Наконец, поблагодарите мою подругу за ее поддержку.
Добро пожаловать в подписку (April_Louisa) | купи мне фанту |
---|---|