我在这里讨论的是嵌套类。基本上,我有两个我正在建模的类。 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())
答案 0 :(得分:106)
当“内部”类是一次性时,你可能想要这样做,它永远不会在外部类的定义之外使用。例如,要使用元类,有时候很方便
class Foo(object):
class __metaclass__(type):
....
而不是单独定义元类,如果你只使用它一次。
我唯一一次使用这样的嵌套类,我只使用外部类作为命名空间将一堆密切相关的类组合在一起:
class Group(object):
class cls1(object):
...
class cls2(object):
...
然后从另一个模块,你可以导入Group并将它们称为Group.cls1,Group.cls2等。但是有人可能会说你可以通过使用模块完成相同的操作(可能以一种不那么令人困惑的方式)。
答案 1 :(得分:19)
我不懂Python,但你的问题似乎很笼统。如果它特定于Python,请忽略我。
类嵌套完全是关于范围的。如果你认为一个类只在另一个类的上下文中有意义,那么前者可能是成为嵌套类的好选择。
这是一个常见的模式,将辅助类作为私有的嵌套类。
答案 2 :(得分:6)
这样做没有任何好处,除非你正在处理元类。
课堂:套房真的不是你想象的那样。这是一个奇怪的范围,它做了奇怪的事情。它真的甚至不上课!它只是收集一些变量的一种方式 - 类的名称,基础,属性的小字典和元类。名称,字典和基数都传递给元类的函数,然后将它分配给类:suite所在范围内的变量“name”。
通过弄乱元类,以及在库存标准类中嵌套类,你可以获得什么,更难以阅读代码,更难理解代码,以及奇怪的错误,这些错误非常难以理解,而不是非常熟悉为什么'class'范围与任何其他python范围完全不同。
答案 3 :(得分: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'''
我觉得当你需要这个功能时,你会非常清楚。如果你不需要做类似的事情,那可能不是一个好的用例。
答案 4 :(得分:4)
嵌套类有另一种用法,当想要构造其增强功能封装在特定嵌套类中的继承类时。
见这个例子:
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()
对象和{{1}时,行foo.bar
将构造foo
正在构造的对象实际上是一个foo2.bar
对象时的对象。
如果类foo2
在类bar
之外定义,以及它的继承版本(例如,将被称为foo
),则定义新类{{ 1}}会更痛苦,因为bar2
的构造函数需要将第一行替换为foo2
,这意味着重写整个构造函数。
答案 5 :(得分:1)
不,构图并不意味着嵌套。 如果你想在外层类的命名空间中隐藏它,那么拥有一个嵌套类是有意义的。
无论如何,我认为在您的情况下嵌套没有任何实际用途。它会使代码更难阅读(理解),并且还会增加缩进,这会使行更短,更容易分裂。
答案 6 :(得分:0)
无论是在类内部还是外部定义,都可以。这是一个员工薪酬计划程序,其中帮助类 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() 调用它即可。