如何扩展类实例?

0 投票
3 回答
4851 浏览
提问于 2025-04-17 17:05

我有以下这段代码,这是一个命令行测试

from cmd2 import Cmd
class App(Cmd, object):
    def __init__(self, *args, **kwargs):
            pass

    def do_test(self, line):
        'test'
        print "parent test"


class App2():
    def __init__(self, *args, **kwargs):
            pass

    def do_test2(self, line):
        print "Test2"           


app = App()
app.cmdloop()

请问有没有办法给App类增加一些额外的功能?我知道有以下的解决方案

class App2(App):
     ....   

app = App2()
app.cmdloop()

但是在我的情况下,我只想运行App,如果可以的话,希望能扩展它。

3 个回答

0

这不是一个完全准确的解决办法,但它可以让你通过应用的名字随时访问它。

把应用的类名改成 _App。

然后在你想用它的地方,

from blah import _App as App

当你要扩展它的时候,

from blah import App2 as App
6

一般来说,这样做不是个好主意,因为当人们(包括你自己在六个月后)阅读代码时,他们会期待App是他们熟悉的那个类,而扩展版本的类应该有个不同的名字。不过,实际上你是可以把子类命名为和原类一样的名字的:

class App(App):
    # etc.

Python很聪明,它知道括号里的App指的是它已经认识的那个类,然后因为新类和原来的名字相同,它就用新类替换了原来的类。别担心,新类里有对旧类的引用,所以旧类并不会完全消失(如果真的消失了,子类继承的东西就都不管用了)。

如果这个类是从你导入的某个模块来的,你甚至可以把替换后的类“补丁”回原来的模块,这样所有导入那个模块的代码就会使用你的替换类。(不过我不推荐这样做!)

import appmodule

class App(appmodule.App):
    # etc.

appmodule.App = App

当然,这样做会变得复杂,因为有些模块可能已经导入了原类的引用,如果你不在脚本的第一时间做这个操作。而且如果其他模块也在尝试修改同一个类,那就会引发一堆麻烦。不过,如果你想让自己和将来维护你代码的人感到困惑,Python会让你这么做!

1

值得注意的是,你可以随时增加类字典的内容,这样就可以在运行时扩展它。

class App(...):
  def __init__(self, a, b):
    pass

  def do_something(self, a):
    pass


app_instance = App()


def do_something_else(self, b):
  pass

App.do_something_else = do_something_else


app_instance.do_something_else('b')

你需要理解Python在运行时是如何查找的。首先,它会查看你创建的yourclass实例,然后查看__mro__(从type(yourclass)开始),一直向上查找,直到找到object

因为类本身就是对象,所以你可以通过添加属性来扩展它们,这样在查找属性时就能找到这些新加的内容。记得只做一次这个操作(比如在导入其他文件的时候)。

下面是一个真实的例子:

>>> class foo():
...     pass
...
>>> x = foo()
>>>
>>> # Define a function and attach it
>>>
>>> def bar(self, a):
...     print(a)
...
>>> foo.bar = bar
>>>
>>> x.bar('a')
a

撰写回答