【问题标题】:How to set an instance variable within a decorator?如何在装饰器中设置实例变量?
【发布时间】:2013-06-14 19:39:03
【问题描述】:

我有一个计算工资组成部分的类,如下所示。

def normalize(func):
    from functools import wraps

    @wraps(func)
    def wrapper(instance, *args, **kwargs):
        allowanceToCheck = func(instance)
        if instance.remainingAmount <= 0:
            allowanceToCheck = 0.0
        elif allowanceToCheck > instance.remainingAmount:
            allowanceToCheck = instance.remainingAmount
        instance.remainingAmount = instance.remainingAmount - allowanceToCheck
        return allowanceToCheck
    return wrapper

class SalaryBreakUpRule(object):
    grossPay = 0.0
    remainingAmount = 0.0

    @property
    def basic(self):
     # calculates the basic pay according to predefined salary slabs.
     basic = 6600 # Defaulting to 6600 for now.
     self.remainingAmount = self.grossPay - basic
     return basic

    @property
    @normalize
    def dearnessAllowance(self):
      return self.basic * 0.2

    @property
    @normalize
    def houseRentAllowance(self):
      return self.basic * 0.4

   def calculateBreakUps(self, value = 0.0):
    self.grossPay = value
    return {
        'basic' : self.basic,
        'da' : self.dearnessAllowance,
        'hra' : self.houseRentAllowance
    }

在计算每个津贴之前,我需要检查所有津贴的总和是否不超过 GrossPay 即我的总工资。我写了一个装饰器,它包装了每个津贴计算方法并完成了上述要求。例如,

* an employee having a salary of Rs.6700
* basic = 6,600 (according to slab)
* dearnessAllowance = 100 (cos 20% of basic is more than remaining amount)
* houseRentAllowance = 0.0 (cos 40% of basic is more than remaining amount)

但不幸的是,它不起作用。第一津贴计算正确,但所有其他津贴的值与第一津贴相同。即 houseRentAllowance 将有 100 而不是上面给出的 0.0。

我发现的问题是,代码行

instance.remainingAmount = instance.remainingAmount - allowanceToCheck

在我试图设置类变量的装饰器中不起作用。

有什么办法可以解决这个问题吗?

【问题讨论】:

  • 很奇怪,它对我有用。您真的尝试设置类的变量或实例变量吗?
  • 嗨@oleg。我相信它是一个实例变量。
  • 这不是您的实际代码。 (Class 代表class)。请发布一个说明问题的可运行示例。
  • 嗨@JanneKarila 对不起那个错字。我已经纠正了。现在你可以像 SalaryBreakUpRule().calculateBreakUps(value = 6700) 一样运行。

标签: python python-decorators


【解决方案1】:

您已将Salary.basic 设为属性,而Salary.basic() 有副作用!因此,每次您的其他函数引用 self.basic 时,它都会重新计算 self.RemainingAmount 并将其重置为其原始值 self.grossPay - basic

具有这种副作用的属性是糟糕的设计。我希望你现在明白为什么。即使您解决了这个问题,以不同的顺序访问您的其他属性也会给您带来不同的结果。属性访问器不应该有持久的副作用。更一般地说:Setter 必须设置,getter 必须获取。属性看起来像简单的变量,因此它们必须相应地运行,否则您将永远无法再次理解或调试您的代码.

【讨论】:

  • 是的,我猜这应该是问题所在。让我看一下并随时通知您。感谢您的时间和帮助。
  • basic 变成一个常规变量应该可以修复这个错误,但您也应该放弃其余的属性。将它们更改为操作(deductHouseRentAllowance() 等)
猜你喜欢
  • 2020-07-08
  • 2021-08-20
  • 2011-07-17
  • 2021-05-15
  • 2021-08-22
  • 1970-01-01
  • 1970-01-01
  • 2019-02-03
相关资源
最近更新 更多