开发者

object inheritance and nested cmd

开发者 https://www.devze.com 2023-03-01 03:55 出处:网络
This is probably a basic OO question: I\'m trying to do a nested console menu with cmd which has gone well.

This is probably a basic OO question: I'm trying to do a nested console menu with cmd which has gone well. I also want all my开发者_Python百科 sub-consoles to have access to the same objects. This has not gone well.

My simple Example:

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()

When I run this I get

>
>menu1
1>info
AttributeError: SubConsole1 instance has no attribute 'obj1'

Try again.

>
>menu2
2>info
NameError: global name 'obj1' is not defined

I'm not sure if the SubConsoles should be sub-classes of MainConsole. I also tried nesting the SubConsoles inside of MainConsole.


EDIT Okay, I misunderstood what you're doing.

You are right, SubConsole1 and 2 do not need to inherit from MainConsole. But they should have a reference to the main console.

Something like:

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

Then you can access the objects you want by accessing self.maincon.obj1 and self.maincon.obj2

The other option, and probably a better one from a design point of view, is to pull out all the objects you want to access into a Context container object, and have all the various Cmd objects maintain their own reference to that Context container.

Something like this:

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()

Hope I was clear enough.


You don't need multiple inheritance, but you need to give obj1 and obj2 to the inherited objects, except if you give some default values to obj1 and 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

instanciated by :

sub1 = SubConsole1(object1, object2)


The other answer is correct insofar as you should not be using multiple inherritance, as the following is true:

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

It would also be wise to create a method of your main class wich creates subcmds, passing their reference to the subcmd's __init__ function. This way you have your object spawn its children more naturally.

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

Then you can access the objects you want by accessing self.maincon.obj1 and self.maincon.obj2 and get the sub-cmd by running maincon.spawnsubconsole() assuming maincon is an instance of the main console class.

0

精彩评论

暂无评论...
验证码 换一张
取 消