在Python的另一个类中定义一个类是否有好处?


106

我在这里谈论的是嵌套类。本质上,我有两个正在建模的类。一个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())

Answers:


121

当“内部”类是一次性的时,您可能想要这样做,它将永远不会在外部类的定义之外使用。例如使用元类,有时很方便

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

如果只使用一次,则不必单独定义一个元类。

唯一一次使用这样的嵌套类时,我仅将外部类用作命名空间,以将一堆紧密相关的类组合在一起:

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

    class cls2(object):
       ...

然后,从另一个模块中,可以导入Group并将其称为Group.cls1,Group.cls2等。但是,有人可能会争辩说,使用模块可以完成完全相同的操作(也许以一种不太混乱的方式)。


13
我将争论在第二种情况下,绝对可以使用设计为名称空间的模块或包来更好地服务您。
马修·特雷弗

5
这是一个了不起的答案。简单一点,并提到使用模块的替代方法。+1
CornSmith

5
仅作记录,对于那些顽固拒绝或无法将其代码组织到分层程序包和适当模块中的人,使用类作为名称空间有时可能比不使用任何东西要好。
Acumenus 2014年

19

我不了解Python,但是您的问题似乎很笼统。如果它特定于Python,请忽略我。

类嵌套与作用域有关。如果您认为一个类仅在另一个类的上下文中才有意义,那么前一个类很可能成为嵌套类的一个很好的候选人。

这是使助手类成为私有,嵌套类的常见模式。


9
仅作记录,private类的概念在Python中并没有那么多应用,但是隐式的使用范围仍然肯定适用。
Acumenus 2014年

7

嵌套类还有另一种用法,当一个人想要构造继承的类时,它们的增强功能封装在特定的嵌套类中。

请参阅以下示例:

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(),这意味着要重写整个构造函数。


6

这样做真的没有任何好处,除非您要处理元类。

上课:套房真的不是您想的那样。这是一个奇怪的范围,它做奇怪的事情。它甚至根本没有上课!这只是收集一些变量的一种方法-类的名称,基类,一些属性的小词典和一个元类。

名称,字典和基数都传递给作为元类的函数,然后在class:suite所在的作用域中将其分配给变量“ name”。

通过弄乱元类,甚至通过在股票标准类中嵌套类而获得的东西,更难于阅读代码,更难于理解代码,而如果不熟悉“类”的原因则很难理解的奇数错误。作用域与任何其他python作用域完全不同。


3
不同意:嵌套异常类非常有用,因为类的用户可以检查您的自定义异常,而无需进行任何混乱的导入。EGexcept myInstanceObj.CustomError, e:
ROBM

2
@Jerub,那为什么不好?
罗伯特·西默

5

您可能使用一个类作为类生成器。喜欢(在一些袖口代码中:)

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'''

我觉得当您需要此功能时,您会很清楚。如果您不需要做类似的事情,那可能不是一个好用例。


1

不,组成并不意味着嵌套。如果要在外部类的名称空间中进一步隐藏嵌套类,那将是有意义的。

无论如何,在您的案例中,我看不到嵌套有任何实际用途。这将使代码更难于阅读(理解),并且还将增加缩进量,从而使行更短并且更易于拆分。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.