使用“新”样式类(我在python 3.2中)有没有办法将类拆分为多个文件?我有一个大类(从面向对象的设计角度来看,它应该是一个单独的类,考虑耦合等等,但是为了便于编辑类,分割几个文件会很好。
答案 0 :(得分:38)
如果您的问题确实只是在编辑器中使用大型类,那么我实际寻找的第一个解决方案是解决问题的更好方法。第二种解决方案是更好的编辑器,最好是具有代码折叠的编辑器。
也就是说,有几种方法可以将一个类分解为多个文件。 Python允许您通过在其中放置__init__.py
将文件夹用作模块,然后可以从其他文件导入内容。我们将在每个解决方案中使用此功能。首先创建一个名为bigclass
的文件夹。
在文件夹中放入最终构成您班级的各种.py
文件。每个应包含最终类的函数和变量定义, not 类。在同一文件夹的__init__.py
中,写下以下内容将它们连接在一起。
class Bigclass(object):
from classdef1 import foo, bar, baz, quux
from classdef2 import thing1, thing2
from classdef3 import magic, moremagic
# unfortunately, "from classdefn import *" is an error or warning
num = 42 # add more members here if you like
这样做的好处是你最终会得到一个直接来自object
的单个类,它在你的继承图中会很好看。
您可以使用多重继承来组合类的各个部分。在单个模块中,您将为类Bigclass
编写类定义。然后在你的__init__.py
写:
import classdef1, classdef2, classdef3
class Bigclass(classdef1.Bigclass, classdef2.Bigclass, classdef3.Bigclass):
num = 42 # add more members if desired
如果多重继承成为问题,可以使用单一继承:只需让每个类以链方式从另一个继承。假设您没有在多个类中定义任何内容,则顺序无关紧要。例如,classdef2.py
就像:
import classdef1
class Bigclass(classdef1.Bigclass):
# more member defs here
classdef3
会从Bigclass
导入classdef2
并添加到其中,依此类推。您的__init__.py
只会导入最后一个:
from classdef42 import Bigclass
我通常更喜欢#1,因为它更明确地指出您从哪些文件导入的成员,但这些解决方案中的任何一个都可以为您服务。
要在任何这些场景中使用该类,您只需使用文件夹名称作为模块名称导入它:from bigclass import Bigclass
答案 1 :(得分:7)
包含数百行的类定义确实“在野外”发生(我在流行的基于Python的开源框架中看到了一些),但我相信如果你思考这些方法正在做什么,它将有可能将大多数类的长度减少到可管理的点。一些例子:
要直接解决您的问题,可以拆分类的定义。一种方法是通过定义类,然后将外部函数作为方法添加到类中来“修补”类。另一种方法是使用内置的type
函数“手动”创建类,在字典中提供其名称,任何基类及其方法和属性。但我不建议这样做只是因为定义会很长。在我看来,这种治疗比疾病更糟糕。
答案 2 :(得分:6)
我之前玩弄过类似的东西。我的用例是抽象语法树中节点的类层次结构,然后我想把所有节点都放在prettyprinting函数在一个单独的prettyprint.py文件中,但仍然将它们作为类中的方法。
我尝试过的一件事是使用装饰器将装饰函数作为属性放在指定的类上。就我而言,这意味着prettyprint.py包含许多def prettyprint(self)
,所有@inclass(...)
都装饰有不同的def inclass(kls):
"""
Decorator that adds the decorated function
as a method in specified class
"""
def _(func):
setattr(kls,func.__name__, func)
return func
return _
## exampe usage
class C:
def __init__(self, d):
self.d = d
# this would be in a separate file.
@inclass(C)
def meth(self, a):
"""Some method"""
print "attribute: %s - argument: %s" % (self.d, a)
i = C(10)
print i.meth.__doc__
i.meth(20)
这个问题是必须确保总是导入子文件,并且它们依赖于主类,这会产生循环依赖,这可能很麻烦。
{{1}}
答案 3 :(得分:4)
您可以使用像这样的装饰器来执行此操作:
class Car(object):
def start(self):
print 'Car has started'
def extends(klass):
def decorator(func):
setattr(klass, func.__name__, func)
return func
return decorator
#this can go in a different module/file
@extends(Car)
def do_start(self):
self.start()
#so can this
car = Car()
car.do_start()
#=> Car has started
答案 4 :(得分:2)
我没有使用它,但this package called partial声称要添加对部分类的支持。
似乎还有其他几种方法可以自己实现。
你可以在单独的文件中将mixin的不同部分实现为mixin,然后将它们全部导入并继承它们。
或者,您可以在某个地方实现类的每个方法,然后在中心文件中导入它们并将它们作为属性分配给类,以创建整个对象。像这样:
a.py:
def AFunc( self, something ):
# Do something
pass
b.py:
def BFunc( self, something ):
# Do something else
pass
c.py:
import a, b
class C:
AFunc = a.AFunc
BFunc = b.BFunc
如果你真的想要,你甚至可以自动化这个过程 - 循环遍历模块a
和b
提供的所有功能,然后将它们作为属性添加到C
。虽然这可能完全矫枉过正。
可能还有其他(可能更好的)方法可以解决这个问题,但是这些方法可能会出现在脑海中。
答案 5 :(得分:1)
我遇到了同样的情况 - 我想把我的班级翻到2个档案。 原因是 - 我希望第1部分用于GUI布局,只需布局 和另一个文件保持所有功能。 比如c#的Partial class。一个用于XAML,另一个用于功能。
答案 6 :(得分:0)
首先,我没有看到如何将类拆分成多个文件使编辑变得更容易。一个体面的IDE应该能够轻松找到任何方法,无论是在一个文件还是多个文件中;如果您没有使用体面的IDE,拆分类意味着维护者必须猜测给定方法所处的文件,这听起来更难而不是更容易。
更基本的是,这个类 - 如此之大,以至于你想要一个特殊的语言功能来支持它的重量 - 听起来从根本上被打破了。我们谈论了多少行代码?几乎可以肯定,做一个更好的主意是:
答案 7 :(得分:0)
我想补充一点,这样做的pythonic方法是通过多重继承,而不必使用mixins。可以在super().__init__(*args, **kwargs)
调用中使用__init__
来添加实例属性,以将参数传递给基类(请参见Raymond Hettinger 1的“超级考虑到的超级”演示)。这还使依赖项注入和某种考虑力可以使您考虑基类的组织(如果只有一个基类在__init__
中设置一个属性,并且所有使用该属性的类都从基类继承,则效果最好。)
这通常需要您控制基类(或者为该模式编写基类)。
另一种选择是使用描述符通过__get__
返回函数,以分离的方式向类添加功能。
您还可以查看__init_subclass__
添加例如类生成期间的类的方法(我认为是在python 3.6中添加的,但要检查)
答案 8 :(得分:-1)
首先,我想说一些复杂的事情可能不是一个好主意,只是为了让你在课堂上找到你的位置更容易 - 最好添加评论,突出部分等等。但是,我看到两种方式你可以做到这一点:
将该类写入多个文件中,然后将其作为文本读取,将它们连接起来并exec
生成的字符串。
在每个文件中创建一个单独的类,然后将它们全部作为mixins继承到主类中。但是,如果你已经继承了另一个类,这可能会导致MRO问题。您可以通过为您的主类创建一个手动解析MRO的元类来解决这个问题,但这可能会变得混乱。
最简单的是第一个选择。