在 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())
98986 次浏览

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

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

而不是单独定义一个元类,如果您只使用它一次。

另外一次我使用这样的嵌套类时,我只使用外部类作为名称空间,将一组密切相关的类组合在一起:

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


class cls2(object):
...

然后从另一个模块导入 Group,并将其称为 Group.cls1、 Group.cls2等。然而,有人可能会争辩说,您可以通过使用模块来完成完全相同的操作(也许是以一种不那么令人困惑的方式)。

我不知道 Python,但是你的问题似乎很笼统。如果这是 Python 特有的,请忽略我。

类嵌套完全与范围有关。如果您认为一个类只有在另一个类的上下文中才有意义,那么前者可能是成为嵌套类的一个很好的候选者。

它是作为私有的嵌套类的辅助类的一种常见模式。

您可以使用类作为类生成器

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

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

这样做真的没有什么好处,除非您正在处理元类。

班级: 套房真的不是你想的那样。这是一个奇怪的范围,它做奇怪的事情。这根本就不算什么课!它只是收集一些变量的一种方法——类的名称、基、一个属性小字典和一个元类。

Name、 dictionary 和 base 都被传递给作为元类的函数,然后它被分配给 class: Suite 所在作用域中的变量‘ name’。

你可以通过搞乱元类,实际上通过在你的标准类中嵌套类来获得更难读代码,更难理解代码,以及非常难以理解的奇怪错误,如果你不熟悉为什么“ class”作用域与其他任何 Python 作用域完全不同的话。

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

看这个例子:

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的构造函数中,当构造的对象实际上是 foo对象时,行 self.a = self.bar()将构造一个 foo.bar,而当构造的对象实际上是 foo2对象时,行 foo2.bar将构造一个 foo2.bar对象。

如果类 bar是在类 foo之外定义的,以及它的继承版本(例如称为 bar2) ,那么定义新的类 foo2将会更加痛苦,因为 foo2的构造函数需要用 self.a = bar2()代替它的第一行,这意味着重写整个构造函数。

无论哪种方式,定义在一个类内部或外部,都会起作用。下面是一个员工工资计划程序,其中助手类 EmpInit 嵌入在类 Employee 中:

class   Employee:


def level(self, j):
return j * 5E3


def __init__(self, name, deg, yrs):
self.name = name
self.deg = deg
self.yrs = yrs
self.empInit = Employee.EmpInit(self.deg, self.level)
self.base = Employee.EmpInit(self.deg, self.level).pay


def pay(self):
if self.deg in self.base:
return self.base[self.deg]() + self.level(self.yrs)
print(f"Degree {self.deg} is not in the database {self.base.keys()}")
return 0


class   EmpInit:


def __init__(self, deg, level):
self.level = level
self.j = deg
self.pay = {1: self.t1, 2: self.t2, 3: self.t3}


def t1(self):   return self.level(1*self.j)
def t2(self):   return self.level(2*self.j)
def t3(self):   return self.level(3*self.j)


if  __name__ == '__main__':
for loop in range(10):
lst = [item for item in input(f"Enter name, degree and years : ").split(' ')]
e1 = Employee(lst[0], int(lst[1]), int(lst[2]))
print(f'Employee {e1.name} with degree {e1.deg} and years {e1.yrs} is making {e1.pay()} dollars')
print("EmpInit deg {0}\nlevel {1}\npay[deg]: {2}".format(e1.empInit.j, e1.empInit.level, e1.base[e1.empInit.j]))

要在外部定义它,只需取消 EmpInit 缩进并更改 Employee。EmpInit ()简化为 EmpInit ()作为常规的“ has-a”组合。但是,因为 Employee 是 EmpInit 的控制器,而且用户不直接实例化或接口它,所以在内部定义它是有意义的,因为它不是一个独立的类。还要注意,实例方法 level ()被设计为在这里的两个类中都要调用。因此,它也可以方便地定义为 Employee 中的静态方法,这样我们就不需要将它传递到 EmpInit 中,而只需要使用 Employee.level ()调用它。

这个特性的一个很好的用例是错误/异常处理,例如:

class DownloadManager(object):
class DowndloadException(Exception):
pass


def download(self):
...

现在正在阅读代码的人知道与这个类相关的所有可能的异常。