Python Abstract Base 类: 为什么 abc 不阻止实例化?
Python Abstract Base Classes: Why doesn't abc prevent instantiation?
据我所知,Python 模块 abc 应该阻止 classes 的实例化,这些 classes 没有实现基础 class 的所有 @abstractmethod
标记方法(假设基础 class 设置了 __metaclass__ = ABCMeta
)
但是,这似乎不适用于以下代码:
摘要基础class:
""" 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
subclass 缺少一个方法:
""" 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()
子class可以在(相当粗糙的)测试代码中实例化。为什么会这样?
我正在使用 Python 2.7.
你正在覆盖__new__
;正是这种方法(在 object.__new__
上)阻止了实例化。
您不是在此处创建不可变类型或以其他方式更改新对象的创建,因此请改用 __init__
:
def __init__(self):
self._logger = logging.getLogger(__name__)
self._logger.setLevel(logging.INFO)
无论如何你都用错了__new__
;传入的第一个参数是 class,不是实例,因为此时尚未创建实例。通过覆盖 __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 模块 abc 应该阻止 classes 的实例化,这些 classes 没有实现基础 class 的所有 @abstractmethod
标记方法(假设基础 class 设置了 __metaclass__ = ABCMeta
)
但是,这似乎不适用于以下代码:
摘要基础class:
""" 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
subclass 缺少一个方法:
""" 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()
子class可以在(相当粗糙的)测试代码中实例化。为什么会这样?
我正在使用 Python 2.7.
你正在覆盖__new__
;正是这种方法(在 object.__new__
上)阻止了实例化。
您不是在此处创建不可变类型或以其他方式更改新对象的创建,因此请改用 __init__
:
def __init__(self):
self._logger = logging.getLogger(__name__)
self._logger.setLevel(logging.INFO)
无论如何你都用错了__new__
;传入的第一个参数是 class,不是实例,因为此时尚未创建实例。通过覆盖 __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