As far as I understood, the Python module abc should prevent instantiation of classes which have not all @abstractmethod
marked methods of the base class implemented (provided that the base class has __metaclass__ = ABCMeta
set)
However, this seems not to work with the following code:
Abstract base 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 missing a method:
""" 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()
The subclass can be instantiated in the (quite crude) test code. Why is that so?
I'm using Python 2.7.
An abstract method cannot be private. The access modifier of the abstract method should be the same in both the abstract class and its derived class. If you declare an abstract method as protected, it should be protected in its derived class. Otherwise, the compiler will raise an error.
Abstract base classes cannot be instantiated. Instead, they are inherited and extended by the concrete subclasses. Subclasses derived from a specific abstract base class must implement the methods and properties provided in that abstract base class. Otherwise, an error is raised during the object instantiation.
ABCs provide a formal way to define interfaces in Python, while staying true to the spirit of duck-typing. Besides, this works in a way that honours the Open-Closed Principle.
An abstract class cannot be instantiated. It just provides an interface for subclasses to avoid code duplication. It makes no sense to instantiate an abstract class. A derived subclass must implement the abstract methods to create a concrete class that fits the interface defined by the abstract class.
You are overriding __new__
; it is this method (on object.__new__
) that prevents the instantiation.
You are not creating a immutable type here or otherwise are altering new object creation, so use __init__
instead:
def __init__(self):
self._logger = logging.getLogger(__name__)
self._logger.setLevel(logging.INFO)
You were using __new__
wrong in any case; the first argument passed in is the class, not an instance as no instance has been created at that point. By overriding __new__
and not calling the original, you a) are not creating an instance and b) not triggering the code that prevents the instance being created in the first place.
With __init__
instead of __new__
instantiation raises an exception as expected:
>>> 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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With