Python - 如何更改模块的实现?

3
我希望使用python-twitter,但需要扩展Status类以添加一些新的方法和属性。那么最符合Python风格的方式是什么?
目前,我有一些函数可以向Status添加属性和新功能,例如:
process_status(status):
    status.datetime = ...
    status.phrase = ...

prettyprint_status(status):
    # do something...

自然地,我只想将额外的方法添加到Status构造函数中。我发现了一个stackoverflow问题讨论,建议创建一个名为ext-twitter的新模块,其中包含每个类的新实现,如下所示:
# ext_twitter.py
import twitter

class Api(twitter.Api):
    pass

class Status(twitter.Status):
    def __init__(self, *args):
        twitter.Status.__init__(self, *args)
        self.args = args
        self.time = parseTime(self.created_at)
        self.phrase = ...

    def prettyprint(self):
        # something

然而,这并不起作用,因为Status类是由Twitter API对象生成的,在这里ext-twitter.Api()调用python-twitter.Api(),后者没有对我的扩展Status类的引用。

有没有办法将我的功能添加到python-twitter模块中,而不必分叉它并制作自己的版本?

2个回答

2

试试这个:

# patch_twitter.py
import twitter

TwitterStatus = twitter.Status

class Status(TwitterStatus):
     def __init__(self, *args, **kwargs):
        TwitterStatus.__init__(self, *args, **kwargs)
        self.args = args
        self.time = parseTime(self.created_at)
        self.phrase = ...

    def prettyprint(self):
        # something

twitter.Status = Status

# use api

这应该可以工作,至少对于一些“工作”的值。如果还有其他任何东西捕获了最初存储在twitter.Status中的类对象的引用,则这些引用不会被更新。这种情况并不经常发生,但可能是细微错误的来源。

您需要在导入twitter.py之后立即导入此代码,并在进行任何其他操作之前完成。


谢谢,一旦我将构造函数改为接受*kwargs和args,这就起作用了。 Status(TwitterStatus)构造函数需要调用TwitterStatus而不是twitter.Status,以避免循环自引用。 我编辑了您的答案以反映这一点。 - dandelion
啊,好发现。请注意,使用super更好地执行超类构造函数的调用。谷歌搜索“Python super considered super”以获取良好的指南。如果您正在使用Py3k,则更好。 - Marcin

1

不必使用继承,可以使用组合来为Status对象添加功能:

# ext_twitter.py
import twitter

class Api(twitter.Api):
    def method_that_returns_status(self, *args, **kwargs):
        status = super(Api, self).methot_that_returns_status(*args, **kwargs)

        # wrap the original status with your custom status
        return Status(status)


class Status(object):        
    def __init__(self, status):
        self._internal = status

    def __getattr__(self, attr):
        return getattr(self._internal, attr)

    def __setattr__(self, attr, value):
        if attr == '_internal':
            super(Status, self).__setattr__(attr, value)
        else:
            setattr(self._internal, attr, value)

    def prettyprint(self):
        # something

我尝试实现了这个简单的例子。当我调用SpottedDog组合构造函数时,它导致了无限递归。 - dandelion
对不起,我是凭空想象写的,忘记在__setattr__方法中为_internal属性添加异常。这种方法唯一的问题是,除非你确定一个属性白名单并修改__setattr__方法以尊重它,否则你的装饰器类不能拥有自己的属性。 - asermax

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