0

我希望当一个对象被另一个对象引用时,引用者的自身对象或其中一个属性在引用者对象上有所不同

这就是我想要做的:

class MyClass:
    .
    .
    .
    .

a = MyClass()
b = a
print(b is a) #must print false
print(b == a) #must print true

#or
a = MyClass()
b = a
print(b.attr is a.attr) #must print false
print(b.attr == a.attr) #must print true

我怎样才能实现这一点,通常在进行分配时,例如a = bbaba

从现在开始感谢回答问题的人

注意:我使用的是 CPython(Python 的官方实现)版本 Python 3.8

我愿意使用黑魔法

4

3 回答 3

4

你不应该尝试对重载赋值做任何事情,因为这不是很pythonic。使用该deepcopy功能或​​制作副本“构造函数”。然后重写该__eq__函数,使两个变量测试相等。

于 2020-09-28T16:53:28.067 回答
0

以您建议的方式重载赋值运算符并不是很pythonic。

Python 中的赋值运算符旨在引用相同的变量,而不是创建副本。

因此,这样的对象在某些情况下可能不会像预期的那样表现,例如在这样的对象上hash(object.attr)使用pickle模块的结果。

然而,如果你想要一些黑暗魔法......


需要明确的是,我提供这个答案只是为了表明 Python 确实提供了执行此类操作的能力。


一种方法是在访问__getattribute__()时使用该函数创建任何属性的副本。

import copy

class MyClass:
    def __init__(self):
        self.attr = ["foo", "bar"]
        
    def __getattribute__(self, name):
        """Access an attribute of this class"""
        attr = object.__getattribute__(self, name)
        return copy.copy(attr)

a = MyClass()
b = a
print(b.attr is a.attr) # prints False
print(b.attr == a.attr) # prints True

更多信息__getattribute__()可以在这里找到:https ://docs.python.org/3/reference/datamodel.html


或者,property()可用于仅对类上的单个属性执行此操作。

class MyClass:
def __init__(self):
    self.__attr = ["foo", "bar"]

@property
def attr(self):
    """Get the attribute."""
    # Copy could be used instead
    # This works too, if we assume the attribute supports slicing
    return self.__attr[:]

@attr.setter
def attr(self, value):
    """Setting the attribute."""
    # Makes assignment work on this attribute
    # a.attr = []
    # a.attr is a.attr (False)
    self.__attr = value

a = MyClass()
b = a
print(b.attr is a.attr) # prints False
print(b.attr == a.attr) # prints True

这些解决方案适用于大多数对象类型。但这在某些情况下实际上会失败。这是因为一些字符串和一些整数将被标记为具有相同的标识。

比如4 is 2*2which will be True, 但是

a = -6
b = -6
print(a is b) # Will print False

这称为“实习”,并在sys模块中简要讨论:https ://docs.python.org/3/library/sys.html?highlight=intern#sys.intern

根据 Real Python:https ://realpython.com/lessons/intern-objects/

在 CPython 3.7 中,-5 到 256 之间的整数被保留,与少于 20 个字符且仅包含 ASCII 字母、数字或下划线的字符串一样。

例如,如果attr = 5上述attr = 'foo'两种方法都失败了。

a = MyClass()
a.attr = 5
b = a
print(b.attr is a.attr) # prints True
print(b.attr == a.attr) # prints True

这可以通过将这些类型包装在子类中来规避。根据 RealPython,只有字符串和一些整数需要修改。这种方法的问题是类型比较会失败:

print(type(b.attr) is type(a.attr)) # prints False

所以如果你想包装对象,确保is操作总是失败,你可以这样做:

import copy
from collections import UserString # Because of course Python has this built in

class UserInt(int): pass

class MyClass:
    def __init__(self, attr = ["foo", "bar"]):
        self.attr = attr
        
    def __getattribute__(self, name):
        """Access an attribute of this class"""
        attr = object.__getattribute__(self, name)

        if isinstance(attr, int) and -5 <= attr <= 256:
            return UserInt(attr) # Prevent a.attr is b.attr if this is an int
        elif isinstance(attr, str):
            return UserString(attr) # Prevent a.attr is b.attr for strings
        #else
        return copy.copy(attr)

a = MyClass()
b = a
print(b.attr is a.attr) # prints False
print(b.attr == a.attr) # prints True

a.attr = 7
b = a
print(b.attr is a.attr) # prints False
print(b.attr == a.attr) # prints True

a.attr = "Hello"
print(b.attr is a.attr) # prints False
print(b.attr == a.attr) # prints True
于 2020-10-04T03:36:17.133 回答
0

可用于 ex:copy.copy 和 copy.deepcopy ...

对于python3:

print(MyClass() == MyClass())
print(MyClass() is MyClass())

出局:

False
False
>>> 

和其他萨满方法将是类似的......

于 2020-10-04T11:03:58.140 回答