自定义类的pythonic方法

自定义类的pythonic方法,python,python-2.7,Python,Python 2.7,我正试图找出一种干净的方法来为自定义类使用继承。我有以下目录结构 inheritTest.py Level1 __init__.py t_Generic.py Level2 __init__.py t_Custom.py 目标:我希望通过导入t_自定义模块可以访问t_通用类的所有类,并允许在t_自定义模块中进行所需的自定义 上面的两个init.py文件中没有任何内容 t_Generic.py包含以下一些泛型类: class A(object): def

我正试图找出一种干净的方法来为自定义类使用继承。我有以下目录结构

inheritTest.py
Level1
    __init__.py
    t_Generic.py
Level2
    __init__.py
    t_Custom.py
目标:我希望通过导入t_自定义模块可以访问t_通用类的所有类,并允许在t_自定义模块中进行所需的自定义

上面的两个init.py文件中没有任何内容

t_Generic.py包含以下一些泛型类:

class A(object):
    def __init__(self):
        self.hello = "Hello! I am Mr.A from t_generic"
    def someOtherMethod(self):
        pass

class B(object):
    def __init__(self):
        self.hello = "Hello! I am Mr.B from t_generic"
    def someOtherMethod(self):
        pass

class C(object):
    def __init__(self):
        self.hello = "Hello! I am Mr.C from t_generic"
    def changeHello(self):
        pass
实验t_Custom.py如下所示:

import Level1.t_Generic

#Override any Generic classes in this module.

#Option 1: Let's get Generic A so it lives in this scope as A
from Level1.t_Generic import A

#Option 2: Let's create B and inherit from Generic, make future custom changes here
class B(Level1.t_Generic.B):
    def __init__(self):
        super(B,self).__init__()


#I really want to inherit from C and change it's behavior
class C(Level1.t_Generic.C):
    def __init__(self):
        super(C,self).__init__()
    def changeHello(self):
        self.hello = "Hello! I am Mr.C modified in t_Custom"
问题:像这样做的蟒蛇式方法是什么?我应该像选项1那样导入自定义模块中的所有泛型类,还是像选项2那样在自定义模块中创建一个继承类并修改我要从中继承的类

inheritTest.py中的示例用例:

import Level2.t_Custom

a = Level2.t_Custom.A()
b = Level2.t_Custom.B()
c = Level2.t_Custom.C()

print a.hello
print b.hello
print c.hello
c.changeHello()
print c.hello
输出:

Hello! I am Mr.A from t_generic
Hello! I am Mr.B from t_generic
Hello! I am Mr.C from t_generic
Hello! I am Mr.C modified in t_Custom

这个问题的答案取决于
Level2.t\u Custom
范围内需要多少类。通常,最好只将对象导入到实际要使用的模块范围中。这样可以保持范围的整洁和组织

但是,如果该模块打算在其他地方使用,则可能需要将
Level1.t_Generic
中的所有对象导入范围并添加自定义类。例如,如果其他人(或您自己)只从
Level2.t\u Custom
导入,那么这实际上取决于您希望在那里公开什么。

我没有测试过这一点,但我认为它应该满足您的要求。考虑白板代码

首先,需要在t_Custom.py中使用相对导入,然后导入泛型类

from ..Level1 import t_Generic
from t_Generic import A as GenericA
from t_Generic import B as GenericB
from t_Generic import C as GenericC
我重命名这些类以避免模块名称空间中的任何冲突

现在,为了获得所需的输出,在t_Custom.py中(复制原始代码)

然后,尝试避免从模块中导出t_Generic.A等

__all__ = ["A","B","C"]
正如Alex在评论中提到的,无意义地重写基类的方法通常被认为是一件“坏事”(TM)。仅当您要修改或添加行为时才执行此操作。然后t_Custom.py变得更像这样:

from ..Level1 import t_Generic
from t_Generic import A as GenericA
from t_Generic import B as GenericB
from t_Generic import C as GenericC

A = GenericA # Just re-export the generic A class
B = GenericB # I'll subclass when I know what I want to do to it

#I really want to inherit from C and change it's behavior
class C(GenericC):
    def changeHello(self):
        self.hello = "Hello! I am Mr.C modified in t_Custom"

__all__ = ["A","B","C"]

您打算如何使用此设置?以您提供的玩具为例,很难判断是否有更好的方法。自定义类必须与泛型类具有相同的名称吗?是否会有多个“自定义”覆盖模块?您如何决定何时使用通用与自定义?mix-ins可以作为一种替代方案吗?@tzaman,(1)是的,generic和custom必须具有相同的名称。(2) 将有多个自定义覆盖模块,但它们都将从泛型继承,并且不会相互重叠。(3) 自定义通常基于某些参数使用,如果参数没有匹配的自定义模块,它将直接导入通用模块并使用它们。因此,在本例中,我将在条件或try/catch中包装导入。是的,我也可以从Level2.t_Custom导入,并且我希望在Level2.t_Custom中公开Level1.t_Generic的所有类。在这种情况下,您的建议是“从Level1.t_Generic import*”然后自定义所需的类吗?然后您真的需要在t_Custom.py中使用不同的类名。我认为@kdopen的答案最有效,因为它使用不同的名称导入泛型类,所以您可以决定如何公开它们。请丢失完全无用的
def_uinit__(self):超级(B,self)
。永远不要覆盖任何方法,包括
\uuuu init\uuuuu
,除了委托给超类之外什么都不做——这有什么意义?!我自己不会这么做的,我只是复制OP的结构以清晰明了。我完全同意你在那种情况下不覆盖,所以请编辑你的A以给出一个好的示例(可能还要加上解释)?请加上樱桃糖?如果我们加上“B级(1.t.U.B级):及格”我们不需要麻烦重新命名,然后再像你的回答那样指出它的旧名称。有没有任何已知的python推理来选择一个而不是另一个?重命名意味着t_Custom在其
\u dict\u
中从来没有
t_Generic.A
A
,只是避免了任何不愉快的打字意外。至于
A=GenericA
A类(GenericA):pass
,我认为前者(A)的效率略高,而(b)更清楚地表达了等价性。
from ..Level1 import t_Generic
from t_Generic import A as GenericA
from t_Generic import B as GenericB
from t_Generic import C as GenericC

A = GenericA # Just re-export the generic A class
B = GenericB # I'll subclass when I know what I want to do to it

#I really want to inherit from C and change it's behavior
class C(GenericC):
    def changeHello(self):
        self.hello = "Hello! I am Mr.C modified in t_Custom"

__all__ = ["A","B","C"]