2015-01-12 4 views
2

Я пытаюсь найти чистый способ использования наследования для пользовательских классов. У меня есть следующая структура каталогов.pythonic способ настройки классов

inheritTest.py 
Level1 
    __init__.py 
    t_Generic.py 
Level2 
    __init__.py 
    t_Custom.py 

Цель: Я хочу, чтобы все классы t_Generic доступны путем импортирования модуля t_Custom и позволяют необходимую настройку в t_Custom.

Нет ничего в двух из 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, или мне нужно создать унаследованный класс в Custom, как в Варианте 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 
+0

Как именно вы собираетесь использовать эту настройку? С примером игрушек, который вы предоставили, трудно сказать, есть ли лучший способ. Должны ли пользовательские классы иметь то же имя, что и общие? Будет ли множество «настраиваемых» модулей переопределения? Как вы решаете, когда использовать общие и пользовательские? Можно ли рассматривать смесь как альтернативу? – tzaman

+0

@tzaman, (1) Да, общие и пользовательские должны иметь одинаковые имена. (2) Будет создано несколько настраиваемых модулей переопределения, но все они будут наследоваться от родовых и не наступать друг на друга. (3) Пользовательский обычно используется на основе некоторых аргументов, если нет соответствующего настраиваемого модуля для аргументов, он будет напрямую импортировать общие модули и использовать их. Таким образом, в этом случае я буду обернуть импорт в состоянии или попытаться/поймать. – user3885927

ответ

2

Я не проверял это, но я думаю, что он должен делать то, что вы хотите. Считают доски код

Во-первых, вам нужно использовать относительные импорта в 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 (копирование исходного кода)

A = GenericA # Just re-export the generic A class 

class B(GenericB): 
    def __init__(self): 
     super(B,self).__init__() 

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

, а затем, чтобы попытаться избежать экспорта t_Generic.A и т.д. из вашего модуля

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

Как сказал Алекс в своем комментарии, он обычно считается «Плохой вещью» (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"] 
+5

** Пожалуйста, ** потеряйте абсолютно бесполезный 'def __init __ (self): super (B, self) .__ init __()'. ** НИКОГДА не переопределять какой-либо метод, включенный __init__', ничего не делать, кроме делегирования в суперкласс - ** в чем смысл ** ?! –

+0

Не сделал бы это сам, я просто копировал структуру OP для ясности. Я полностью согласен с вами в том, чтобы не переопределять в этом случае – kdopen

+0

Итак, пожалуйста, отредактируйте свой А, чтобы дать хороший пример (и, возможно, добавить объяснение)? Довольно мило с CherryPy сверху? –

0

Ответ на этот вопрос зависит от того, сколько классов вы хотите в рамках Level2.t_Custom. В общем, лучше всего импортировать объекты в область видимости модуля, которую вы собираетесь использовать. Это сохраняет чистоту и организованность.

Но если модуль предназначен для использования в другом месте, может потребоваться импортировать все объекты из Level1.t_Generic в область действия и добавить свои пользовательские классы. Например, если кто-то другой (или вы сам) будет импортировать только с Level2.t_Custom, тогда это действительно зависит от того, что вы хотите открыть там.

+0

Да, я могу импортировать и с Level2.t_Custom, и я хотел бы показать все классы Level1.t_Generic в Level2.t_Custom. Учитывая этот случай, ваше предложение «от Level1.t_Generic import *», а затем настроить нужные? – user3885927

+0

Тогда вам действительно нужно использовать разные имена классов в t_Custom.py. – kdopen

+0

Я думаю, что ответ @ kdopen работает лучше всего, поскольку он импортирует родовые классы с другим именем, поэтому вы решаете, как вы их раскрываете. –

Смежные вопросы