Наследование объектов и вложенный cmd
Вероятно, это основной вопрос ОО: я пытаюсь создать вложенное консольное меню с помощью cmd, которое прошло хорошо. Я также хочу, чтобы все мои подчиненные консоли имели доступ к одним и тем же объектам. Это не прошло хорошо.
Мой простой пример:
import cmd
class MainConsole(cmd.Cmd):
def __init__(self,obj1,obj2):
cmd.Cmd.__init__(self)
self.prompt = ">"
self.obj1 = obj1 # The objects I want access to in all my consoles.
self.obj2 = obj2
self.menu1 = SubConsole1() # I could pass in the objects here as arguments
self.menu2 = SubConsole2() # but there should be a better way.
def do_menu1(self,args):
self.menu1.cmdloop()
def do_menu2(self,args):
self.menu2.cmdloop()
def do_info(self,args):
self.menu1.do_info(args)
self.menu2.do_info(args)
def do_exit(self,args):
return -1
class SubConsole1(cmd.Cmd,MainConsole):
def __init__(self):
cmd.Cmd.__init__(self)
self.prompt = "1>"
def do_action(self,args):
print self.obj1.someattr1 # Doesn't work
class SubConsole2(cmd.Cmd,MainConsole):
def __init__(self):
cmd.Cmd.__init__(self)
self.prompt = "2>"
def do_action(self,args):
print obj1.someattr2 # Doesn't work
class anobject(object):
def __init__(self,init_value):
self.someattr1 = init_value
self.someattr2 = init_value * 2
object1 = anobject(1)
object2 = anobject(2)
c=MainConsole(object1,object2)
c.cmdloop()
Когда я запускаю это, я получаю
>
>menu1
1>info
AttributeError: SubConsole1 instance has no attribute 'obj1'
Попробуйте снова.
>
>menu2
2>info
NameError: global name 'obj1' is not defined
Я не уверен, должны ли SubConsoles быть подклассами MainConsole
, Я также попытался вложить SubConsoles внутри MainConsole
,
3 ответа
Вам не нужно множественное наследование, но вам нужно предоставить obj1 и obj2 унаследованным объектам, за исключением случаев, когда вы предоставляете некоторые значения по умолчанию для obj1 и obj2.
class SubConsole1(MainConsole):
def __init__(self, obb1, obj2):
MainConsole.__init__(self, obj1, obj2)
self.prompt = "1>"
def do_action(self,args):
print self.obj1.someattr1 # Doesn't work
инстанцируется:
sub1 = SubConsole1(object1, object2)
РЕДАКТИРОВАТЬ Хорошо, я неправильно понял, что вы делаете.
Вы правы, SubConsole1 и 2 не нужно наследовать от MainConsole. Но они должны иметь ссылку на основную консоль.
Что-то вроде:
class MainConsole(cmd.Cmd):
def __init__(self):
cmd.Cmd.__init__(self, obj1, obj2)
self.obj1 = obj2
self.obj2 = obj2
class SubConsole1(cmd.Cmd):
def __init__(self, maincon):
cmd.Cmd.__init__(self)
self.maincon = maincon
Затем вы можете получить доступ к нужным объектам, открыв self.maincon.obj1
а также self.maincon.obj2
Другой вариант, и, возможно, лучший с точки зрения дизайна, состоит в том, чтобы вытянуть все объекты, к которым вы хотите получить доступ, в объект контейнера Context, и иметь все различные Cmd
объекты поддерживают свою собственную ссылку на этот контейнер контекста.
Что-то вроде этого:
import cmd
from collections import namedtuple
class MyConsole(cmd.Cmd):
def __init__(self, context):
cmd.Cmd.__init__(self)
self.context = context
class ConsoleContext(object):
def __init__(self, **kwargs):
self.__dict__ = kwargs
class MainConsole(MyConsole):
def __init__(self, context):
MyConsole.__init__(self, context)
self.menu1 = SubConsole1(context)
self.menu2 = SubConsole2(context)
self.prompt = '>'
def do_menu1(self, args):
self.menu1.cmdloop()
def do_menu2(self, args):
self.menu2.cmdloop()
def do_quit(self, args):
return True
class SubConsole1(MyConsole):
def __init__(self, context):
MyConsole.__init__(self, context)
self.prompt = '1>'
def do_action(self, args):
print self.context.message1
def do_quit(self, args):
return True
class SubConsole2(MyConsole):
def __init__(self, context):
MyConsole.__init__(self, context)
self.prompt = '2>'
def do_action(self, args):
print self.context.message2
def do_quit(self, args):
return True
if __name__ == '__main__':
context = ConsoleContext(message1='Message 1', message2='Message 2')
con = MainConsole(context)
con.cmdloop()
Надеюсь, я был достаточно ясен.
Другой ответ является правильным, поскольку вы не должны использовать множественное наследование, поскольку верно следующее:
class A(object):
pass
class B(A):
pass
class C(A):
pass
class D(B):
pass
a = A()
b = B()
c = C()
d = D()
isTrue = isinstance(a,A) and isinstance(b,A) and isinstance(c,A) and isinstance(d,A)
isTrue = isTrue and isinstance(b,B)and isinstance(d,B)
isTrue = isTrue and isinstance(c,C)
isTrue = isTrue and isinstance(d,D)
>>> print isTrue
True
Также было бы целесообразно создать метод вашего основного класса, который создает subcmds, передавая их ссылку на subcmd __init__
функция. Таким образом, ваш объект порождает своих детей более естественно.
class MainConsole(cmd.Cmd):
def spawnsubconsole(self):
return SubConsole1(self)
def __init__(self):
cmd.Cmd.__init__(self, obj1, obj2)
self.obj1 = obj2
self.obj2 = obj2
class SubConsole1(cmd.Cmd):
def __init__(self, maincon):
cmd.Cmd.__init__(self)
self.maincon = maincon
Затем вы можете получить доступ к нужным объектам, открыв self.maincon.obj1
а также self.maincon.obj2
и получить суб-cmd, запустив maincon.spawnsubconsole()
предполагая, что maincon является экземпляром основного класса консоли.