Класи Python лише з одним екземпляром: Коли створити (єдиний) екземпляр класу і коли замість цього працювати з класом?


11

Дано клас Python, який буде інстанціюватися лише один раз, тобто буде лише один об'єкт класу. Мені було цікаво, в яких випадках має сенс створити один екземпляр класу, а не працювати безпосередньо з класом.

Існує подібне питання , але воно має іншу спрямованість:

  1. йдеться про групування глобальних змінних та функцій у клас та
  2. Це не специфічно для Python. Останнє означає, що він не враховує той факт, що (в Python) класи теж є об'єктами.

ОНОВЛЕННЯ:

У Python я можу робити наступні дії як для класів, так і для об'єктів:

class A(object):
    pass

A.some_state_var = True
# Then later
A.some_state_var = False


my_a = A()

my_a.some_state_var = True
# Then later
my_a.some_state_var = False

Тому я не бачу, як вибір між класом та екземпляром цього класу залежить від стану (в Python). Я можу підтримувати стан з будь-яким із двох.

Крім того, мотивація створити мій екземпляр класу / класу не полягає у виконанні вимоги Singleton.

Крім того, справа не стільки в створенні нового типу.

Мотивація полягає в групуванні пов'язаних коду та даних та наявності інтерфейсу до нього. Ось чому я спочатку моделював це як клас на діаграмі класів. Лише коли мова зайшла про реалізацію, я почав цікавитись, чи інстанціювати цей клас чи ні.

Відповіді:


16

Дано клас Python, який буде інстанціюватися лише один раз, тобто буде лише один об'єкт класу. Мені було цікаво, в яких випадках має сенс створити один екземпляр класу, а не працювати безпосередньо з класом.

Так ось це:

class Singleton:
    '''don't bother instantiating me'''
    clsvar1 = 'foo'

    @classmethod
    def foobar(cls, *args, **kwargs):
        if condition():
            cls.clsvar1 = 'bar'

проти цього?

class Singleton:
    '''instantiate and use me'''
    def __init__(self):
        self.var1 = 'foo'

    def foobar(self, *args, **kwargs):
        if condition():
            self.var1 = 'bar'

Рекомендація

Я, безумовно, вважаю за краще той, який призначений для примірника. Коли ви створюєте "тип речі", що означає, що ви створюєте речі такого типу.

Мотивація полягає в групуванні пов'язаних коду та даних та наявності інтерфейсу до нього.

Це означає, чому б не просто використовувати модуль, оскільки все, що вам потрібно, - це область імен? Модулі - одинаки, пов'язані з груповим кодом і даними, і це трохи простіше, і, ймовірно, вважалося б більш пітонічним:

var1 ='foo'

def foobar(*args, **kwargs):
    global var1
    if condition():
        var1 = 'bar'

Тож використання було б замість:

from modules.singleton import Singleton
Singleton.foobar()

або

from modules.singleton import Singleton
the_singleton = Singleton()
the_singleton.foobar()

зробити це:

from modules import singleton
singleton.foobar()

3
Дякую за вашу відповідь. Ви б дійсно запропонували створити новий модуль (новий .py файл) для кожної функції (включаючи змінні)? Це може призвести до появи багатьох невеликих .py-файлів. Або ви б згрупували всі (принаймні так чи інакше пов’язані) функції "без класу" та змінні в одному модулі?
langlauf.io

Ще одне зауваження: ви пишете "оскільки все, що вам потрібно, це простір імен". Що я хочу - це групувати пов'язаний код, тобто функції та дані, в одному місці та мати до нього інтерфейс. Справа не стільки в тому, щоб створити "Тип". Під час проектування це все одно призведе до класу в діаграмі класів, чи не так?
langlauf.io

2

Мені було цікаво, в яких випадках має сенс створити один екземпляр класу, а не працювати безпосередньо з класом.

Це одна з тих речей, яка спричинить релігійну війну, якщо ви багато в неї потрапите.

Але загалом практика, яку я бачив багато разів, полягає в тому, що методи класу повинні стосуватися лише створення примірників цього класу.

Якщо ви думаєте про те, що таке клас, яка його мета / поведінка, то це має сенс. Мета класу - створити екземпляри об'єктів, які базуються на собі . Це план, який також може будувати будівлю. Клас "Користувач" створює об'єкти "користувача". Клас "Собака" створює "собачі" об'єкти тощо тощо

Зазначте, що це поведінка класу, то є сенс, що методи, які ви додаєте до класу "X", стосуватимуться створення об'єктів "x".

Тож навіть якщо вам знадобиться лише один "х" об'єкт, ви все одно можете його інстанціювати.

Додавання методів до класу X, які не пов'язані зі створенням екземплярів об'єктів "x", може призвести до заплутування несподіваного коду. Звичайно, у реальному світі є багато прикладів, де люди так чи інакше зробили, але, як я сказав, цей шлях веде до релігійної війни.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.