对象继承和嵌套命令行

3
这可能是一个基本的面向对象问题: 我正在尝试使用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内部。


1
你不应该在这里使用多重继承。 - Sven Marnach
增加了另一种做法,请查看。 - rossipedia
这些答案有帮助吗?如果没有,请提供更多的澄清。 - theheadofabroom
3个回答

5

编辑 好的,我误解了你的做法。

你是对的,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.obj1self.maincon.obj2来访问你想要的对象。

另一个选择,从设计角度来看可能更好的选择是将所有要访问的对象提取到一个上下文容器对象中,并且让所有各种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()

希望我表达得足够清晰。


谢谢,我花了一分钟才弄清楚ConsoleContext,但现在我认为它是共享对象的好方法。我仍然不完全清楚一个对象实例如何从另一个对象实例继承方法和属性(甚至不确定我的术语是否正确)。我希望我在学校时上过一些计算机科学课程。 - RyanN
这是维基百科关于继承的简易英文页面:http://simple.wikipedia.org/wiki/Inheritance_(computer_science) 希望对您有所帮助。 - rossipedia

2

您不需要多重继承,但您需要将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)

2

另一个回答的正确之处在于您不应该使用多重继承,因为以下是真实的:

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

创建一个主类的方法来创建子命令,并将它们的引用传递给子命令的__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.obj1self.maincon.obj2来访问所需的对象,并通过运行maincon.spawnsubconsole()获取子命令,假设maincon是主控制台类的实例。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接