Python 抽象基类 : Why doesn't abc prevent instantiation?

标签 python abc abstract-base-class

据我所知,Python 模块 abc 应该阻止实例化那些没有实现基类的所有 @abstractmethod 标记方法的类(前提是基类有 __metaclass__ = ABCMeta 集)

但是,这似乎不适用于以下代码:

抽象基类:

""" Contains payment processors for executing payments """

from abc import ABCMeta, abstractmethod

class AbstractPaymentProcessor:
    """ Abstract class for executing faucet Payments
    Implement this at your own. Possible implementations include
    online wallets and RPC calls to running dogecoin wallets """

    __metaclass__ = ABCMeta

    @abstractmethod
    def execute_payment(self, destination_address, amount):
        """ Execute a payment to one receiving single address

        return the transaction id or None """
        pass

    @abstractmethod
    def execute_multi_payment(self, destination_addresses, amounts):
        """ Execute a payment to multiple receiving addresses

        return the transaction id or None """
        pass

    @abstractmethod
    def get_transaction_status(self):
        """ Get the status of the transaction

        Indicate if transaction is already confirmed. Return
         - True if confirmed
         - False if unconfirmed
         - None if transaction doesn't exist (or raise exception?)"""
        pass

    @abstractmethod
    def get_available_balance(self):
        """ Get the available balance
        i.e. how much "cash" is in the faucet """
        pass

子类缺少一个方法:

""" Contains a logging payment processor """

import logging
import random

from AbstractPaymentProcessor import AbstractPaymentProcessor

class DummyLoggingPaymentProcessor (AbstractPaymentProcessor):
    """ Payment processor that does nothing, just logs """

    def __new__(self):
        self._logger = logging.getLogger(__name__)
        self._logger.setLevel(logging.INFO)

    def execute_payment(self, destination_address, amount):
        """ Execute a payment to one receiving single address

        return the transaction id or None """
        raise NotImplementedError("Not implemented yet")

    def execute_multi_payment(self, destination_addresses, amounts):
        """ Execute a payment to multiple receiving addresses

        return the transaction id or None """
        raise NotImplementedError("Not implemented yet")

    def get_transaction_status(self):
        """ Get the status of the transaction

        Indicate if transaction is already confirmed. Return
         - True if confirmed
         - False if unconfirmed
         - None if transaction doesn't exist """
        raise NotImplementedError("Not implemented yet")


if __name__ == '__main__':
    # can instanciate, although get_available_balance is not defined. Why? abc should prevent this!?
    c = DummyLoggingPaymentProcessor()
    c.get_available_balance()

可以在(相当粗糙的)测试代码中实例化子类。为什么会这样?

我正在使用 Python 2.7。

最佳答案

您正在覆盖 __new__;正是这种方法(在 object.__new__ 上)阻止了实例化。

您不是在此处创建不可变类型或以其他方式更改新对象的创建,因此请改用 __init__:

def __init__(self):
    self._logger = logging.getLogger(__name__)
    self._logger.setLevel(logging.INFO)

无论如何,你使用的 __new__ 是错误的;传入的第一个参数是,而不是实例,因为此时还没有创建实例。通过覆盖 __new__ 而不调用原始代码,您 a) 没有创建实例并且 b) 没有触发阻止创建实例的代码。

使用 __init__ 而不是 __new__ 实例化会按预期引发异常:

>>> class DummyLoggingPaymentProcessor (AbstractPaymentProcessor):
...     """ Payment processor that does nothing, just logs """
...     def __init__(self):
...         self._logger = logging.getLogger(__name__)
...         self._logger.setLevel(logging.INFO)
...     def execute_payment(self, destination_address, amount):
...         """ Execute a payment to one receiving single address
... 
...         return the transaction id or None """
...         raise NotImplementedError("Not implemented yet")
...     def execute_multi_payment(self, destination_addresses, amounts):
...         """ Execute a payment to multiple receiving addresses
... 
...         return the transaction id or None """
...         raise NotImplementedError("Not implemented yet")
...     def get_transaction_status(self):
...         """ Get the status of the transaction
... 
...         Indicate if transaction is already confirmed. Return
...          - True if confirmed
...          - False if unconfirmed
...          - None if transaction doesn't exist """
...         raise NotImplementedError("Not implemented yet")
... 
>>> c = DummyLoggingPaymentProcessor()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: Can't instantiate abstract class DummyLoggingPaymentProcessor with abstract methods get_available_balance

关于Python 抽象基类 : Why doesn't abc prevent instantiation?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28053773/

相关文章:

c++ - 由于多个抽象基类,实现两个同名但不同的非协变返回类型的函数

c++ - STL映射和纯虚基类

python - 需要将字符串列表转换为普通数字列表,字符串以10为底

xml - music21格式流为ABC+并保存为文件

可听写类的 Python 习语?

python : subclass `type` to create specialized types (e. g。一个 "list of int")

c++ - 以自身为参数的抽象基类虚纯方法

python - django - 防止用户重复

python - 使用Python从第二个文件的列表中搜索一个文件

python - 我的功能需要负时间才能完成。到底发生了什么事?