How to pass instance into decorator function

  • Thread starter Jayakrishnan Damodaran
  • Start date

J

Jayakrishnan Damodaran

I have a class which calculates some salary allowances. Instead of a blind calculation I need to check some conditions before I can return the calculated amount. Like if all the allowances calculated till now plus the one in progress must not exceed the total salary(this may occur since these allowances are a percentage of basic pay). Below is a sample code FYI

class CompanySalaryBreakUpRule(object):
'''Class to calculate the various salary components.
This class is inherited by individual company classes whom implement salary calculations.
Various component calculations are implemented as @property and hence be accessed as class properties.

'''
grossPay = 0.0
remainingAmount = 0.0

def checkValid(self, func):
from functools import wraps

@wraps(func)
def wrapper(self, *args, **kwargs):
allowanceToCheck = func(self, *args, **kwargs)
if allowanceToCheck > self.remainingAmount:
allowanceToCheck = self.remainingAmount
else:
self.remainingAmount = self.remainingAmount - allowanceToCheck
return allowanceToCheck
return wrapper

@property
@checkValid
def dearnessAllowance(self):
return self.basic * 0.2 # we have a function that calculates basic pay

But executing this raises an exception
@checkValid
TypeError: checkValid() takes exactly 2 arguments (0 given)
 
Ad

Advertisements

P

Peter Otten

Jayakrishnan said:
I have a class which calculates some salary allowances. Instead of a blind
calculation I need to check some conditions before I can return the
calculated amount. Like if all the allowances calculated till now plus the
one in progress must not exceed the total salary(this may occur since
these allowances are a percentage of basic pay). Below is a sample code
FYI

class CompanySalaryBreakUpRule(object):
'''Class to calculate the various salary components.
This class is inherited by individual company classes whom implement
salary calculations. Various component calculations are implemented as
@property and hence be accessed as class properties.

'''
grossPay = 0.0
remainingAmount = 0.0

def checkValid(self, func):
from functools import wraps

@wraps(func)
def wrapper(self, *args, **kwargs):
allowanceToCheck = func(self, *args, **kwargs)
if allowanceToCheck > self.remainingAmount:
allowanceToCheck = self.remainingAmount
else:
self.remainingAmount = self.remainingAmount -
allowanceToCheck
return allowanceToCheck
return wrapper

@property
@checkValid
def dearnessAllowance(self):
return self.basic * 0.2 # we have a function that calculates basic
pay

But executing this raises an exception
@checkValid
TypeError: checkValid() takes exactly 2 arguments (0 given)

Remember that

@checkValid
def dearnessAllowance(self):
....

is a shortcut for

def dearnessAllowance(self):
....
dearnessAllowance = checkValid(dearnessAllowance)

The function call happens in the class body, so checkValid() is still normal
function that has knowlegde neither about the class nor (as the self arg
implies) about an instance of that class.
While it would be sufficient to remove its first argument
class CompanySalaryBreakUpRule(object): ...
def checkValid(func): ...

@property
@checkValid
def dearnessAllowance(self):
...

I recommend that you also move it out of the class body:

def checkValid(func):
...
class CompanySalaryBreakUpRule(object): ...
@property
@checkValid
def dearnessAllowance(self):
...
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top