繁体   English   中英

如何要求在Python中实现方法?

[英]How to require implementation of method in Python?

我在Python中使用鸭子输入。

def flagItem(object_to_flag, account_flagging, flag_type, is_flagged):
    if flag_type == Flags.OFFENSIVE:
        object_to_flag.is_offensive=is_flagged
    elif flag_type == Flags.SPAM:
        object_to_flag.is_spam=is_flagged
    object_to_flag.is_active=(not is_flagged)
    object_to_flag.cleanup()
    return object_to_flag.put()

在其中将不同的对象作为object_to_flag传入时,所有对象均具有is_activeis_spamis_offensive属性。 它们也碰巧具有cleanup()方法。

我要传递的对象都具有相同的基类(它们是Google App Engine中的db对象):

class User(db.Model):
    ...
    is_active = db.BooleanProperty(default = True)
    is_spam = db.BooleanProperty(default=False)
    is_offensive = db.BooleanProperty(default=False)
    def cleanup():
        pass

class Post(db.Model):
    ...
    is_active = db.BooleanProperty(default = True)
    is_spam = db.BooleanProperty(default=False)
    is_offensive = db.BooleanProperty(default=False)
    def cleanup():
        pass

如何使cleanup()方法抽象化,以便可以为所有需要孩子提供实现的对象提供相同的父类?

也许更重要的是,这是“ pythonic”吗? 我应该走这条路,还是只依靠鸭子的打字? 我的背景是Java,我正在尝试学习Python的做事方式。

谢谢!

使用abc 模块 具体来说,将基类的元类设置为ABCMeta并在cleanup方法上使用@abstractmethod装饰器。

关于这是否是“ pythonic”的争论分歧很大。 描述该标准的PEP 3119列出了一些优点和缺点(但显然赞成ABC)。 它进入标准库,这很好地表明了很多人认为它在某些情况下很有用。 对于您而言,我认为这是适当的。

如果要确保实现清除方法,则可以使用@abc.virtualmethod装饰器进行包装。 这将在实例化尚未覆盖虚拟方法的任何对象时导致错误。 这还要求您将abc.ABCMeta类的__metaclass__

有关更多信息和一些示例,请参见abc模块

这通常不做:通常只有文档说明实现者必须重写给定的方法。 但是,这可能更多是由于abc模块(Python 2.6中的新增功能)的新颖性,而不是这种方法的非Python性。

为什么没有在调用cleanup方法时引发NotImplementedError 如果他们想让您的孩子上课,他们将不得不采取某种实施措施。

由于您没有可用的abc,因此可以使用简单的元类来完成此操作

class Abstract(type(db.Model)):
    def __new__(metacls, clsname, bases, clsdict):
        for methodname in clsdict.pop('_abstract_methods_', []):
            try:
                if not callable(clsdict[methodname]):
                    raise TypeError("{0} must implement {1}".format(clcname, methodname))
            except KeyError:
                raise TypeError("{0} must implement {1}".format(clcname, methodname))
       return super(Abstract, metacls).__new__(metacls, clsname, bases, clsdict)


class RequireCleanup(db.Model):
    __metaclass__ = Abstract
    _abstract_methods_ = ['cleanup']

    def cleanup(self):
        pass

表达式type(db.Model)解析为用于db.Model任何元类,因此我们不会踩Google的代码。 此外,我们弹出_abstract_methods_出类字典之前得到它的传递给谷歌的__new__方法,这样我们就不会破坏任何东西。 如果db.Model已经具有使用该名称的属性,则需要将其更改为其他名称。

尽管我从未亲自使用过它,但我已经看到了许多有关Zope接口的参考。 这对于您的任务来说可能是多余的,但可能会为您提供一些指导。 对于具有Java背景的人来说可能会感到很舒服。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM