繁体   English   中英

不知道为什么我卡在 Python 卡住递归循环

[英]Not sure why I'm stuck in a Python stuck recursion loop

这里的 add 和 mul 定义是无意义的,因为它们依赖于返回 self,导致无限循环。 如果他们使用 lambdas 创建一个新的发行版,那么它可以正常工作,如下面我自己的回答所示。

我只是在玩类并试图构建一个小型统计工具。 但是,当我运行此代码时,我陷入了n1.pdf调用中的递归循环,该调用在__mul__调用中运行,我无法弄清楚原因。 I think it has something to do with Python lazily executing the __mul__ instead of doing what I kind of 'wanted' (let's say in the language of CS) which was to create a new pointer to the old function call for pdf that is owned by将新指针指向 pdf,然后将旧指针(main.pdf 指针)设置为新的 function。

我认为这措辞很糟糕,因此如果您理解我的要求,则非常欢迎进行编辑。

import math
import random

class Distribution:
    def __init__(self, pdf, cdf):
        self.pdf = pdf
        self.cdf = cdf

    def pdf(self, x):
        return self.pdf(x)
        
    def cdf(self, x):
        return self.cdf(x)

    def __mul__(self, other):
        if isinstance(other, float) or isinstance(other, int):
            newpdf = lambda x : self.pdf(x) * other
            self.pdf = newpdf
            newcdf = lambda x : self.cdf(x) * other
            self.cdf = newcdf
            return self
        else:
            return NotImplemented

    def __add__(self, other):
        self.pdf = lambda x : self.pdf(x) + other.pdf(x)
        self.cdf = lambda x : self.cdf(x) + other.cdf(x)
        return Distribution(self.pdf, self.cdf)
    
class Normal(Distribution):
    def __init__(self, mean, stdev):
        self.mean = mean
        self.stdev = stdev

    def pdf(self, x):
        return (1.0 / math.sqrt(2 * math.pi * self.stdev ** 2)) * math.exp(-0.5 * (x - self.mean) ** 2 / self.stdev ** 2)

    def cdf(self, x):
        return (1 + math.erf((x - self.mean) / math.sqrt(2) / self.stdev)) / 2

    def sample(self):
        return self.mean + self.stdev * math.sqrt(2) * math.cos(2 * math.pi * random.random())

if __name__ == "__main__":
    n1 = Normal(1,2)
    n1half = n1 * 0.5
    x = n1.pdf(1)
    print(x)

ps 我知道乘以0.5后不再是pdf,这不是问题。

class Distribution:
    ...
    def pdf(self, x):
        return self.pdf(x)

pdf()调用自己,调用自己,调用自己......无限。

cdf()相同。

def pdf(self, x):
    return self.pdf(x)
    
def cdf(self, x):
    return self.cdf(x)

我假设您的意图是委托给属性。 由于它们总是被分配,它们将被找到(假设您在实例上进行查找)而不是 class 方法(如果没有这些属性,这将直接是无限递归); 但这反过来又意味着这些 class 方法只是无用的。 x.cdf(y) ,其中cdf是可调用的实例属性,可以正常工作; 也不需要提供方法。

newpdf = lambda x : self.pdf(x) * other
self.pdf = newpdf

我假设您的意图是创建一个新的 function ,它依赖于self.pdf的现有值。 不幸的是,它不是那样工作的。 问题是 lambda 是后期绑定 当它执行时它会查找self.pdf ... 并找到它自己。

这里有一个单独的问题,因为您正在编写__mul____add__实现 - 即*+运算符,它们应该返回一个新 value ,而不是改变任何一个操作数。 (如果你写a = 3b = 4然后c = a * b ,如果ab的值发生变化,你会非常惊讶,是吗?)

我们可以一次解决这两个问题,只需使用计算的pdfcdf创建一个新实例(无论如何我们都需要):

def __mul__(self, other):
    if isinstance(other, float) or isinstance(other, int):
        newpdf = lambda x : self.pdf(x) * other
        newcdf = lambda x : self.cdf(x) * other
        return Distribution(newpdf, newcdf)
    else:
        return NotImplemented

同样, __add__应该使用局部变量,而不是修改self

def __add__(self, other):
    newpdf = lambda x : self.pdf(x) + other.pdf(x)
    newcdf = lambda x : self.cdf(x) + other.cdf(x)
    return Distribution(newpdf, newcdf)

请注意,实现这些方法还为您提供了增强的赋值运算符*=+= (尽管通过创建新的 object 并重新绑定名称)。

让我们测试一下:

if __name__ == "__main__":
    n1 = Normal(1,2)
    n1half = n1 * 0.5
    print(n1.pdf(1))
    print(n1half.pdf(1))
    n1 += n1 
    print(n1.pdf(1))

我得到:

>py test.py
0.19947114020071635
0.09973557010035818
0.3989422804014327

感谢@John 和@Tom 和@bbbbbb 的帮助......问题是试图返回自我而不是创建一个新的发行版。 如果我将mul的 def'n 更改为

def __mul__(self, other):
        if isinstance(other, float) or isinstance(other, int):
            def newpdf(x):
                return self.pdf(x) * other
            def newcdf(x):
                return self.cdf(x) * other
            return Distribution(newpdf, newcdf)
        else:
            return NotImplemented

那么这就解决了这个问题

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM