it-swarm-ru.tech

Есть ли преимущество в определении класса внутри другого класса в Python?

Здесь я говорю о вложенных классах. По сути, у меня есть два класса, которые я моделирую. Класс DownloadManager и класс DownloadThread. Очевидная концепция OOP здесь - композиция. Однако композиция не обязательно означает вложение, верно?

У меня есть код, который выглядит примерно так:

class DownloadThread:
    def foo(self):
        pass

class DownloadManager():
    def __init__(self):
        dwld_threads = []
    def create_new_thread():
        dwld_threads.append(DownloadThread())

Но теперь мне интересно, есть ли ситуация, когда вложение будет лучше. Что-то вроде:

class DownloadManager():
    class DownloadThread:
        def foo(self):
            pass
    def __init__(self):
        dwld_threads = []
    def create_new_thread():
        dwld_threads.append(DownloadManager.DownloadThread())
88
fuentesjr

Возможно, вы захотите сделать это, когда "внутренний" класс является однократным, который никогда не будет использоваться вне определение внешнего класса. Например, чтобы использовать метакласс, иногда удобно

class Foo(object):
    class __metaclass__(type):
        .... 

вместо того, чтобы определять метакласс отдельно, если вы используете его только один раз.

Единственный раз, когда я использовал подобные вложенные классы, я использовал внешний класс только как пространство имен для группировки нескольких тесно связанных классов:

class Group(object):
    class cls1(object):
       ...

    class cls2(object):
       ...

Затем из другого модуля вы можете импортировать Group и ссылаться на них как Group.cls1, Group.cls2 и т.д. Однако можно утверждать, что вы можете сделать то же самое (возможно, в менее запутанном виде) с помощью модуля.

107
dF.

Я не знаю Python, но ваш вопрос кажется очень общим. Не обращайте на меня внимания, если это специфично для Python.

Вложение классов - все о сфере действия. Если вы думаете, что один класс будет иметь смысл только в контексте другого, то первый, вероятно, является хорошим кандидатом на то, чтобы стать вложенным классом.

Это общий шаблон создания вспомогательных классов как частных, вложенных классов.

19
André Chalella

В этом нет никакой пользы, кроме случаев, когда вы имеете дело с метаклассами.

класс: набор действительно не то, что вы думаете. Это странная сфера, и она делает странные вещи. Это действительно даже не делает класс! Это просто способ сбора некоторых переменных - имени класса, основ, небольшого словаря атрибутов и метакласса.

Имя, словарь и базы передаются в функцию, которая является метаклассом, а затем присваиваются переменной 'name' в области видимости класса: suite.

То, что вы можете получить, связавшись с метаклассами и даже вложив классы в стандартные классы, сложнее для чтения, сложнее для понимания кода и странных ошибок, которые ужасно трудно понять, не зная, почему "класс" область видимости полностью отличается от любой другой области видимости python.

6
Jerub

Вы можете использовать класс в качестве генератора классов. Как (в некоторых не манжете код :)

class gen(object):
    class base_1(object): pass
    ...
    class base_n(object): pass

    def __init__(self, ...):
        ...
    def mk_cls(self, ..., type):
        '''makes a class based on the type passed in, the current state of
           the class, and the other inputs to the method'''

Я чувствую, что когда вам понадобится эта функциональность, она будет вам очень понятна. Если вам не нужно делать что-то подобное, это, вероятно, не очень хороший вариант использования.

5
tim.tadh

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

Смотрите этот пример:

class foo:

  class bar:
    ...  # functionalities of a specific sub-feature of foo

  def __init__(self):
    self.a = self.bar()
    ...

  ...  # other features of foo


class foo2(foo):

  class bar(foo.bar):
    ... # enhanced functionalities for this specific feature

  def __init__(self):
    foo.__init__(self)

Обратите внимание, что в конструкторе foo строка self.a = self.bar() будет создавать foo.bar, когда конструируемый объект фактически является объектом foo, и объектом foo2.bar, когда конструируемый объект фактически является объектом foo2.

Если бы вместо этого класс bar был определен вне класса foo, а также его унаследованной версии (которая, например, называлась бы bar2), то определение нового класса foo2 было бы гораздо более болезненным, поскольку для конструктора foo2 требовалось бы иметь его первая строка заменена на self.a = bar2(), что подразумевает переписывание всего конструктора.

4
Thomas

Нет, композиция не означает вложение. Было бы целесообразно иметь вложенный класс, если вы хотите скрыть его больше в пространстве имен внешнего класса.

Во всяком случае, я не вижу практического использования для вложения в вашем случае. Это затруднило бы чтение (понимание) кода и увеличило бы отступ, что сделало бы строки более короткими и более склонными к расщеплению.

1
Cristian Ciupitu