【问题标题】:How do I make a boolean attribute go back to a default value in a Python class?如何使布尔属性回到 Python 类中的默认值?
【发布时间】:2020-05-12 09:22:55
【问题描述】:

我正在尝试创建一个类来处理逻辑文字,我想通过重载 __neg__() 运算符来解释否定文字:

class Literal():

def __init__(self,n):
    self.name = n
    self.sign = True

def __neg__(self):
    self.sign = False
    return self

def __repr__(self):
    return self.name

没有什么太复杂的;当我定义实例A=Literal('A') 并运行命令(-A).sign 时,我现在成功地将sign 属性更改为False。但是,如果我稍后运行A.sign,则该属性仍设置为False,这是我不想要的。我希望A.sign 的值始终返回True(-A).sign 的值始终返回False

注意:我不能只创建一个辅助实例other 并设置other.sign = False,因为不管它的sign 值如何,对A 的任何调用都应该引用A 而不是副本。

我一直在尝试不同的想法,例如设置@property,但似乎无法弄清楚,所以我求助于互联网。提前致谢,如果您想了解更多信息,请告诉我!

编辑:

我让它返回一个新实例,就像我之前所做的那样,因为似乎每个人都同意这是最好的选择。我添加了一个由此产生的问题的示例案例,以便更清楚:

class Literal():

def __init__(self,n,s=True):
    self.name = n
    self.sign = s

def __neg__(self):
    result = Literal(self.name, not self.sign)
    return result

def __repr__(self):
    return self.name

A = Literal('A')
B = Literal('B')
C = Literal('C')

print((-A).sign)
>>> False
print(B.sign)
>>> True
print((-B).sign)
>>> False
print(A.sign)
>>> True
print(B.sign)
>>> False

这行得通。但是,稍后我需要在集合列表(这代表 CNF)中收集文字​​列表,并且拥有单独的实例会导致问题,因为我最终会得到重复的文字:

test = [{A,-B},{B,C},{-A,C}]
lits = []


for x in test:
    for i in x:
        print(x,i,i.sign)
        if i not in lits:
            lits.append(i)

print(f'\n{test}')
print(lits)

>>> {B, A} B False
>>> {B, A} A True
>>> {B, C} B True
>>> {B, C} C True
>>> {C, A} C True
>>> {C, A} A False

>>> test: [{B, A}, {B, C}, {C, A}]
>>> lits: [B, A, B, C, A]

由于 sign 的这种实现,被否定的文字 BA 被重复。

希望这能澄清我之前的笔记。

【问题讨论】:

  • 不应该 __neg__ 返回一个 new 实例,sign 设置为 False
  • "注意:我不能只将第二个实例设为 other 并设置 other.sign = False,因为无论其符号值如何,对 A 的任何调用都应引用 A 而不是副本。"但是A 仍然会引用原始的A,除非您手动重新分配新对象到A...。试试看。
  • 我会,但我澄清说我不能这样做,因为这会给我留下基本上两个不同值的同名实例。我可以看到这不是问题的场景,但我只需要一个具有任何相同名称的实例。如果我按照您的建议进行操作(我已经尝试过),我最终会得到两个具有不同符号值的 A 文字,这不是我想要的。
  • 在这种情况下你不能使用__neg__。我想您不想使用not A.sign 是有原因的?这可能是XY problem
  • 要缓解多个实例的问题,您可以简单地检查名称是否在列表中,而不是对象本身。 if i.name not in lits: lits.append(i.name)

标签: python python-3.x class attributes


【解决方案1】:

如果您不想更改原始实例,则必须创建一个新实例。

class Literal():
    def __init__(self, n):
        self.name = n
        self.sign = True

    def __neg__(self):
        result = Literal(self.name)
        result.sign = False
        return result

    def __repr__(self):
        return self.name

a = Literal('A')
print((-a).sign)
print(a.sign)

但是您的代码有问题。您总是返回 False 以获取该标志。这意味着(-a).sign(--a).sign 是相同的。您应该将__neg__ 更改为以下代码。

    def __neg__(self):
        result = Literal(self.name)
        result.sign = not result.sign
        return result

如果您将符号作为可选参数添加到__init__,代码可能如下所示。

class Literal():
    def __init__(self, n, sign=True):
        self.name = n
        self.sign = sign

    def __neg__(self):
        return Literal(self.name, not self.sign)

    def __repr__(self):
        return self.name

为了获得最大的灵活性,您可以将return Literal(self.name, not self.sign) 替换为return self.__class__(self.name, not self.sign)

【讨论】:

  • 感谢not self.sign 提示,尽管我不会指定双重否定,但它很有用。我想我并没有很好地表达自己,因为我已经尝试返回一个新实例,但问题是我最终得到了两个同名但 sign 值不同的实例,而我真正需要的是同一实例具有不同的属性,具体取决于操作员。
  • 我忽略了那部分。目前我正在考虑创建一种代理包装器。
【解决方案2】:

@jonrsharpe 是正确的:__neg__ 应该返回一个新实例:

class Literal():

    def __init__(self,n, sign=True):
        self.name = n
        self.sign = sign

    def __neg__(self):
        return Literal(self.name, sign=False)

    def __repr__(self):
        return self.name


a = Literal('a')
print((-a).sign)
>>> False
print((a).sign)
>>> True
a = -a
print((a).sign)
>>> False

【讨论】:

    猜你喜欢
    • 2015-09-19
    • 2019-10-21
    • 2019-04-08
    • 2021-09-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多