【问题标题】:Class method calling twice类方法调用两次
【发布时间】:2017-01-08 17:24:20
【问题描述】:

我有以下代码。

class DobleTSim():
    def __init__(self, bf, hw, tf, tw):
        self.bf = bf
        self.hw = hw  
        self.tf = tf
        self.tw = tw

    def m_in_maj(self):
        print('foo')
        return 2 * (self.bf * self.tf * (self.tf / 2 + self.hw / 2))


    def m_est_maj(self):
        return self.m_in_maj() / ((self.hw + 2 * self.tf) / 2)

A = DobleTSim(200, 500, 12, 12)

print(A.m_in_maj(), A.m_est_maj())

当我执行代码时,输​​出是:

foo
foo
1228800.0 4690.076335877862

如何避免两次执行“m_in_maj”方法?

-----编辑-----

另一个解决方案是使用 propertylru_cache 装饰器。使用这个有什么缺点吗?

import functools

class DobleTSim():
    def __init__(self, bf, hw, tf, tw):
        self.bf = bf
        self.hw = hw  
        self.tf = tf
        self.tw = tw

    @property
    @functools.lru_cache()
    def m_in_maj(self):
        print('foo')
        self.a = 2 * (self.bf * self.tf * (self.tf / 2 + self.hw / 2))
        return self.a

    def m_est_maj(self):
        return self.m_in_maj / ((self.hw + 2 * self.tf) / 2)

【问题讨论】:

  • m_in_maj()m_est_maj() 函数中被调用
  • 不要在m_est_maj中调用它
  • 是的,但我需要这个值才能在 m_est_maj 上使用它。
  • print(A.m_est_maj()) 不适合你吗?

标签: python methods call


【解决方案1】:

调用它两次。一次在print() 结束,一次在调用m_est_maj

6 数学运算是相当便宜的运算。通过缓存结果,您可能不会获得有意义的性能提升。但如果你愿意,你可以这样做。您可以从 __init__ 调用 m_in_maj 并将结果保存到实例属性中,并引用该属性而不是函数调用。

或者您可以让函数检查实例属性是否已定义,在第一次调用时计算,并在后续调用时返回。

这是我看到的一种非常常见的通用方法:

class DobleTSim():
    def __init__(self, bf, hw, tf, tw):
        self.bf = bf
        self.hw = hw
        self.tf = tf
        self.tw = tw

    def m_in_maj(self):
        if not hasattr( self, '_m_in_maj_result'):
            print('foo')
            self._m_in_maj_result =  \
                2 * (self.bf * self.tf * (self.tf / 2 + self.hw / 2))
        return self._m_in_maj_result


    def m_est_maj(self):
        return self.m_in_maj() / ((self.hw + 2 * self.tf) / 2)

A = DobleTSim(200, 500, 12, 12)

print(A.m_in_maj(), A.m_est_maj())

基于How to know if an object has an attribute in Python,做这样的事情可能更pythonic:

def m_in_maj(self):
    try:
        return self._m_in_maj_result
    except AttributeError:
        print('foo')
        self._m_in_maj_result =  \
            2 * (self.bf * self.tf * (self.tf / 2 + self.hw / 2))
        return self._m_in_maj_result

【讨论】:

  • 谢谢丹。也许我可以使用变量来存储结果?还是直接调用方法获取返回值?
  • 非常感谢丹。对不起,我的无知,但是,'hasattr' 做什么?检查属性是否已经实例化?
  • 哇,这非常有用。再次感谢您的帮助。
  • 我看到了你提到的那个帖子。我不得不问。 'getattr' 在这种情况下有效吗?
  • 这是一个很好的问题——随着你作为程序员的学习和成长,你只会遇到更多的事情。这可能是您开始对这些事情进行自己研究的好机会。为什么不尝试阅读链接,进行一些搜索并自己进行一些实验呢?您会发现这是最快的学习方式。
【解决方案2】:

您的m_in_maj 方法在m_est_maj 方法中被调用:

def m_est_maj(self):
    return self.m_in_maj() / ((self.hw + 2 * self.tf) / 2)

相反,给它一个可选参数,并仅在未传递此参数时调用m_in_maj

def m_est_maj(self, x=None):
    if x is None:
        x = self.m_in_maj()
    return x / ((self.hw + 2 * self.tf) / 2)

那么,当调用m_est_maj

x = A.m_in_maj()
print(x, A.m_est_maj(x))

【讨论】:

  • 谢谢,我试试这个方法。
  • 我认为这样的逻辑属于类内部。您已从类中取出逻辑 并将其委托给 caller,这破坏了您在类中获得的封装。
  • @DanFarrell 在另一种情况下我会同意,但 Python 中没有封装。您的解决方案强制进行封装,这可能很好,但通常不需要。我的解决方案允许对调用者进行更多控制。这是两种不同的方法,但我认为没有一种比另一种更好,这取决于具体情况。
猜你喜欢
  • 1970-01-01
  • 2021-11-04
  • 1970-01-01
  • 1970-01-01
  • 2017-10-15
  • 2011-02-09
  • 2013-12-31
  • 2016-09-29
  • 1970-01-01
相关资源
最近更新 更多