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

发布于 2024-09-24 20:48:32 字数 1217 浏览 6 评论 0原文

我在 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_offense 属性。它们也恰好有一个 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 的做事方式。

谢谢!

I'm using duck typing in 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()

Where different objects are passed in as object_to_flag, all of which have is_active, is_spam, is_offensive attributes. They also happen to have a cleanup() method.

The objects I'm passing in all have the same base class (they're db objects in Google App Engine):

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

How can I make the cleanup() method abstract so that I can have the same parent class for all these objects that requires the children provide implementation?

Perhaps more importantly, is this 'pythonic'? Should I go this route, or should I just rely on the duck typing? My background is in Java and I'm trying to learn the Python way of doing things.

Thanks!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

吾性傲以野 2024-10-01 20:48:32

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

关于这是否是“Pythonic”的争论存在分歧。 PEP 3119 描述了该标准,列出了一些优点和缺点(但显然更喜欢 ABC)。它已被纳入标准库,这很好地表明许多人认为它在某些情况下很有用。对于你的情况,我认为是合适的。

Use the abc module. Specifically, set your base class's metaclass to ABCMeta and use the @abstractmethod decorator on your cleanup method.

The debate on whether this is "pythonic" is split. PEP 3119, which describes the standard, lists some of the pros and cons (but obviously favors ABCs). It made it into the standard library, which is a pretty good indication that many people consider it useful in some circumstances. In your case, I think it is appropriate.

剩余の解释 2024-10-01 20:48:32

如果你想确保 cleanup 方法被实现,你可以用 @abc.virtualmethod 装饰器包装。这将导致在实例化任何未重写虚拟方法的对象时出现错误。这还要求您将 abc.ABCMeta 设为类的 __metaclass__

有关详细信息和一些示例,请参阅 abc 模块

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

If you want to ensure that the cleanup method is implemented, you can wrap with the @abc.virtualmethod decorator. This will cause an error on instantiation of any object that hasn't overridden the virtualmethod. This also requires that you make abc.ABCMeta your class's __metaclass__.

See the abc module for more info and some examples.

This is not commonly done: usually there will just be docs to the effect that implementers must override the given method. However this may be more due to the newness of the abc module (new in Python 2.6) than a perceived unpythonicness of this approach.

昨迟人 2024-10-01 20:48:32

为什么不让 cleanup 方法在调用时引发 NotImplementedError 呢?如果他们希望你的孩子的课程能够正常进行,他们就必须采取某种实施措施。

Why not have the cleanup method just raise an NotImplementedError when it is called? If they want your children classes to work they'll have to put some sort of implementation in place.

那些过往 2024-10-01 20:48:32

由于您没有可用的 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 的任何元类,因此我们不践踏谷歌的代码。另外,在将 _abstract_methods_ 传递给 google 的 __new__ 方法之前,我们将其从类字典中弹出,这样我们就不会破坏任何内容。如果 db.Model 已经有一个具有该名称的属性,那么您需要将其更改为其他名称。

Since you don't have abc available, you can do this with a simple metaclass

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

the expression type(db.Model) resolves to whatever metaclass gets used for db.Model so we don't step on google's code. Also, we pop _abstract_methods_ out of the class dictionary before it get's passed to google's __new__ method so that we don't break anything. If db.Model already has an attribute with that name, then you will need to change it to something else.

我也只是我 2024-10-01 20:48:32

虽然我个人从未使用过它,但我见过很多对 Zope 的引用接口。这对于您的任务来说可能有些过头了,但它可能会给您一些方向。对于具有 Java 背景的人来说可能会感觉很舒服。

Although I've never used it personally, I've seen many references to Zope interfaces. This may be overkill for your task, but it may give you some direction. And it may feel comfortable to someone with a Java background.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文