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

<p>здесь я говорю о вложенных классах. по сути, у меня есть два класса, которые я моделирую. класс downloadmanager и класс downloadthread. очевидная концепция oop здесь - композиция. однако композиция не обязательно означает вложение, верно?</p><p>у меня есть код, который выглядит примерно так:</p><pre><code>class downloadthread: def foo(self): pass class downloadmanager(): def \_\_init\_\_(self): dwld\_threads = [] def create\_new\_thread(): dwld\_threads.append(downloadthread()) </code></pre><p>но теперь мне интересно, есть ли ситуация, когда вложение будет лучше. что-то вроде:</p><pre><code>class downloadmanager(): class downloadthread: def foo(self): pass def \_\_init\_\_(self): dwld\_threads = [] def create\_new\_thread(): dwld\_threads.append(downloadmanager.downloadthread()) </code></pre>

<p>возможно, вы захотите сделать это, когда "внутренний" класс является однократным, который никогда не будет использоваться вне <em>определение</em> внешнего класса. например, чтобы использовать метакласс, иногда удобно</p><pre><code>class foo(object): class \_\_metaclass\_\_(type): .... </code></pre><p>вместо того, чтобы определять метакласс отдельно, если вы используете его только один раз.</p><p>единственный раз, когда я использовал подобные вложенные классы, я использовал внешний класс только как пространство имен для группировки нескольких тесно связанных классов:</p><pre><code>class group(object): class cls1(object): ... class cls2(object): ... </code></pre><p>затем из другого модуля вы можете импортировать group и ссылаться на них как group.cls1, group.cls2 и т.д. однако можно утверждать, что вы можете сделать то же самое (возможно, в менее запутанном виде) с помощью модуля.</p>

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

<p>в этом нет никакой пользы, кроме случаев, когда вы имеете дело с метаклассами.</p><p>класс: набор действительно не то, что вы думаете. это странная сфера, и она делает странные вещи. это действительно даже не делает класс! это просто способ сбора некоторых переменных - имени класса, основ, небольшого словаря атрибутов и метакласса.</p><p>имя, словарь и базы передаются в функцию, которая является метаклассом, а затем присваиваются переменной 'name' в области видимости класса: suite.</p><p>то, что вы можете получить, связавшись с метаклассами и даже вложив классы в стандартные классы, сложнее для чтения, сложнее для понимания кода и странных ошибок, которые ужасно трудно понять, не зная, почему "класс" область видимости полностью отличается от любой другой области видимости python.</p>

<p>вы можете использовать класс в качестве генератора классов. как (в некоторых не манжете код :)</p><pre><code>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''' </code></pre><p>я чувствую, что когда вам понадобится эта функциональность, она будет вам очень понятна. если вам не нужно делать что-то подобное, это, вероятно, не очень хороший вариант использования.</p>

<p>существует еще один способ использования вложенного класса, когда требуется создать унаследованные классы, расширенные функциональные возможности которых заключены в конкретный вложенный класс.</p><p>смотрите этот пример:</p><pre><code>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) </code></pre><p>обратите внимание, что в конструкторе <code>foo</code> строка <code>self.a = self.bar()</code> будет создавать <code>foo.bar</code>, когда конструируемый объект фактически является объектом <code>foo</code>, и объектом <code>foo2.bar</code>, когда конструируемый объект фактически является объектом <code>foo2</code>.</p><p>если бы вместо этого класс <code>bar</code> был определен вне класса <code>foo</code>, а также его унаследованной версии (которая, например, называлась бы <code>bar2</code>), то определение нового класса <code>foo2</code> было бы гораздо более болезненным, поскольку для конструктора <code>foo2</code> требовалось бы иметь его первая строка заменена на <code>self.a = bar2()</code>, что подразумевает переписывание всего конструктора.</p>

<p>нет, композиция не означает вложение. было бы целесообразно иметь вложенный класс, если вы хотите скрыть его больше в пространстве имен внешнего класса.</p><p>во всяком случае, я не вижу практического использования для вложения в вашем случае. это затруднило бы чтение (понимание) кода и увеличило бы отступ, что сделало бы строки более короткими и более склонными к расщеплению.</p>