What would you choose? Do you put logging routine into caller or callee? My intuitive answer is "callee does the logging, because that's where action takes place", like this:

class Account():
    def transaction(self, amount, target):
        logging.info("Start transaction of %s to %s" % (amount, target))
        ...

if '__name__' == '__main__'
    ....
    account.transaction(amount, target)


Simple and easy. Put logging code to the caller would be tedious - the function is called about 20 times in different places.

So far so good, but we grew up to have 10 different account classes:

class AbsctractAccount():

class CreditAccount(AbstractAccount):
    def transaction(self, amount, target):
        logging.info("Start transaction of %s to %s" % (amount, target))
        ...

class DebitAccount(AbstractAccount):
    def transaction(self, amount, target):
        logging.info("Start transaction of %s to %s" % (amount, target))
        ...

class SomeOtherAccount(...)
    ....

Then letting the callee do the logging is also tedious now.

What is the best practise here?

If, for the convenience, we define transaction function in AbstractAccount to just do the logging, and change inherited classes, like this:

class AbsctractAccount():
    def transaction(self, amount, target):
        logging.info("Start transaction of %s to %s" % (amount, target))

class DebitAccount(AbstractAccount):
    def transaction(self, amount, target):
        super().transaction(amount,target)
        ....

Then we gethered logging code pieces all to one place, but it begets two other problems.

1. It is a "surprise" that super().transaction must be called first, not last, and that it does only the logging.

2. The code used to check whether "transaction" is implemented:

    if hasAttr(DebitAccount, 'transaction'): # clear to read

has to be changed to check whether "transaction" is inherited:

    if not DebitAccount.transaction is AbstractAccount.transaction:

whose purpose is confusing, and whose cause is a little surprise too. Also, the pythonic "boldly calling and watching for exception" stopped working, because instead of getting AttributeError, we would get a line of log and nothing more.

--
https://mail.python.org/mailman/listinfo/python-list

Reply via email to