наследование объектов и вложенный cmd - PullRequest
2 голосов
/ 28 апреля 2011

Это, вероятно, основной вопрос ОО: я пытаюсь создать вложенное консольное меню с помощью 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 ]

4 голосов
/ 28 апреля 2011

РЕДАКТИРОВАТЬ Хорошо, я неправильно понял, что вы делаете.

Вы правы, 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()

Надеюсь, я достаточно ясно.

2 голосов
/ 28 апреля 2011

Другой ответ верен, поскольку вы не должны использовать множественное наследование, поскольку верно следующее:

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,передавая их ссылку на функцию __init__ subcmd.Таким образом, ваш объект порождает своих потомков более естественно.

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, и получить подкоманду, выполнив maincon.spawnsubconsole(), предполагаяmaincon является экземпляром класса главной консоли.

2 голосов
/ 28 апреля 2011

Вам не нужно множественное наследование, но вам нужно предоставить 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)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...