Python:自定义类上的ueq_uu和uu contains_uu的奇怪行为

2024-10-02 14:28:32 发布

您现在位置:Python中文网/ 问答频道 /正文

我有以下自定义类(剥离了一些),实现了一个表达式树:

from abc import ABC, abstractmethod


class Operator:
    def __init__(self, str_reps):
        self.str_reps = str_reps

    def __str__(self):
        return self.str_reps[0]

    def __eq__(self, other):
        return self is other

    def __ne__(self, other):
        return self is not other

    def __hash__(self):
        return hash(str(self))


NOT = Operator(["¬", "~", "not", "!"])
AND = Operator(["∧", "&", "and"])
OR = Operator(["∨", "|", "or"])


class Node(ABC):
    @abstractmethod
    def __eq__(self, other):
        pass

    @abstractmethod
    def __hash__(self):
        pass

    def __ne__(self, other):
        return not self == other

    @abstractmethod
    def __str__(self):
        pass

    @abstractmethod
    def __invert__(self):
        pass

    def bracket_if_necessary(self):
        return str(self)


class Leaf(Node):
    def __init__(self, v):
        self.val = v

    def __eq__(self, other):
        if not isinstance(other, Leaf):
            return False
        return self.val == other.val

    def __hash__(self):
        return hash(self.val)

    def __str__(self):
        return str(self.val)

    def __invert__(self):
        return UnaryNode(self)


class UnaryNode(Node):
    def __init__(self, child):
        self.child = child
        self.hash = hash(NOT) + hash(self.child)

    def __eq__(self, other):
        if not isinstance(other, UnaryNode):
            return False
        return self.child == other.child

    def __hash__(self):
        return self.hash

    def __str__(self):
        return str(NOT) + self.child.bracket_if_necessary()

    def __invert__(self):
        return self.child


class VariadicNode(Node):
    def __init__(self, op, children):
        self.op = op
        self.children = children
        self.hash = hash(self.op) + sum(hash(child) for child in self.children)

    def __eq__(self, other):
        if not isinstance(other, VariadicNode):
            return False
        return self.op is other.op and set(self.children) == set(other.children)

    def __hash__(self):
        return self.hash

    def __str__(self):
        return (" " + str(self.op) + " ").join(child.bracket_if_necessary() for child in self)

    def __invert__(self):
        return VariadicNode(AND if self.op is OR else OR, tuple(~c for c in self))

    def bracket_if_necessary(self):
        return "(" + str(self) + ")"

    def __iter__(self):
        return iter(self.children)

    def __contains__(self, item):
        return item in self.children

如果我运行这个并尝试

^{pr2}$

正如预期的那样,它们都返回真值。在

但是,我在使用这些节点的代码中遇到了错误:

# Simplify procedure in DPLL Algorithm
def _simplify(cnf, l):
    # print for debugging
    for c in cnf:
        print("b", l, ~l, type(l), "B", c, type(c), l in c)

    return VariadicNode(AND, tuple(_filter(c, ~l) for c in cnf if l not in c))


# Removes the chosen unit literal (negated above) from clause c
def _filter(c, l):
    # print for debugging
    for x in c:
        print("a", l, type(l), "A", x, type(x), x==l)

    return VariadicNode(c.op, tuple(x for x in c if x != l))

这里cnf是一个VariadicNode(AND),所有子元素都是VariadicNode(OR)VariadicNode的子元素总是以元组的形式给出。在

这两张照片的结果是:

a ¬25 <class 'operators.UnaryNode'> A ¬25 <class 'operators.UnaryNode'> False
b ¬25 25 <class 'operators.UnaryNode'> B ¬25 ∨ ¬36 <class 'operators.VariadicNode'> False

这不应该发生(第一行中的¬25 == ¬25和第二行的¬25 in (¬25 ∨ ¬36)都应该返回True)。但是,输出中还有一行:

b ¬25 25 <class 'operators.UnaryNode'> B ¬25 <class 'operators.VariadicNode'> True

所以检查¬25 in (¬25)实际上确实返回了True。在

有人能告诉我发生了什么事吗?在

如果需要更多的信息,其余的代码可以在[deleted]上找到(希望它是公开的,我对github还是个新手,所以我不知道他们的政策)。请注意,它仍然是一个WIP。在

这些类位于operators.py中,其余(相关的)代码位于SAT_solver.py,而{}则允许轻松运行整个项目,前提是安装了networkx库。在

编辑

我现在已经将一个示例dimacs.txt文件推送到github存储库中,这导致了所描述的问题。只需将hamilton.txtSAT_solver.py和{}从存储库下载到同一个文件夹中,运行SAT_solver.py(它有一个main()方法),并在提示输入问题文件名时将hamilton或{}输入到命令行(当提示阻止程序写入任何文件时,只需将解决方案文件名留空)。这将导致大量输出,包括上面描述的有问题的行。在


Tags: inselfchildforreturnifdefnot
1条回答
网友
1楼 · 发布于 2024-10-02 14:28:32

您发布的代码不是github repo中的代码。您的代码有UnaryNode.__eq__

def __eq__(self, other):
    if not isinstance(other, UnaryNode):
        return False
    return self.child == other.child

回购代码有

^{pr2}$

这也要求运算符是相同的。检测代码并在失败时中断显示您正在某处生成两个不同的NOT运算符:

>>> str(x)
'¬24'
>>> str(l)
'¬24'
>>> x == l
False
>>> x.child == l.child
True
>>> str(x.op)
'¬'
>>> str(l.op)
'¬'
>>> x.op == l.op
False
>>> id(x.op)
2975964300
>>> id(l.op)
2976527276

追查发生在哪里,想怎么解决就怎么解决,不管是避免拥有不止一个,还是不在乎是否有不止一个(我的偏好)。我知道你在一条删除的评论中写道:“操作符是单个对象,我希望根据它们的引用比较它们是否相等”,但是(1)它们不是单个对象,(2)如果你不想这样一个不必要的东西,你就不会有麻烦了。。在

如果我不得不猜测的话,当您调用copy.deepcopy时,会引入其他运算符,但您肯定不会使用单例。在

相关问题 更多 >