Python内存别名(简单)

时间:2018-06-16 15:22:50

标签: python memory memory-address

我想知道这是怎么发生以及为什么会这样。有人可以解释一下吗?

enter image description here

联系方式是我在编辑器中创建的课程。

如果我想让它们指向相同的内存地址,我该怎么办?

3 个答案:

答案 0 :(得分:2)

每次调用Contact()时,即使您传递了相同的args,也会创建一个新实例。 Python如何知道您希望具有相同args的联系人实际上是同一个对象?一般来说,这是不可取的。如果您想为同一个实例使用两个名称,只需执行一个简单的赋值,例如

c1 = Contact('647-000-000', 'Andy')
c2 = c1

如果确实希望对具有相同args的Contact()进行两次(或更多次)调用以返回相同的对象,则可以为__new__构造函数提供缓存,例如{ {3}}。这是一个简短的演示。

from functools import lru_cache

class Contact:
    @lru_cache(None)
    def __new__(cls, *args):
        return super().__new__(cls)

    def __init__(self, phone, name):
        self.phone = phone
        self.name = name

    def __str__(self):
        return f'Contact({self.phone}, {self.name})'

c1 = Contact('647-000-000', 'Andy')
c2 = Contact('647-000-001', 'Amos')
c3 = Contact('647-000-000', 'Andy')
for c in (c1, c2, c3):
    print(c, repr(c))

<强>输出

Contact(647-000-000, Andy) <__main__.Contact object at 0xb7285d4c>
Contact(647-000-001, Amos) <__main__.Contact object at 0xb7285dac>
Contact(647-000-000, Andy) <__main__.Contact object at 0xb7285d4c>

当您调用Contact时,将调用其__new__方法来构造新的实例对象。然后将该对象传递给__init__以进行初始化。在大多数类中,__new__方法尚未定义,因此调用父类的__new__方法,通常是从{继承的默认__new__方法。 {1}}基类。

在上面的代码中,我们定义object并使用__new__进行装饰。因此,当我们调用lru_cache Contact()类型时,Contact会处理任何其他args,它会维护我们创建的所有lru_cache个实例的不可见字典,并通过args键入到Contact(包括__new__类型)。如果该密钥在dict中,则Contact返回相应的实例。否则,会分配一个新的__new__并将其添加到Contact。在任何一种情况下,实例都会传递给dict进行初始化。

以上代码是概念证明。我建议在实际代码中执行此操作。由__init__维护的不可见dict会保留对您创建的每个联系人的引用,因此当它们(似乎)超出范围时,即使您将它们传递给{{1},它们也不会被删除直到程序终止。要强制删除联系人,您需要从缓存中清除它,您可以使用:

lru_cache

但当然会清除整个缓存。

答案 1 :(得分:-1)

通过实施__eq__(文档链接)来定义对象的等效性(<div class="container"> <div class="row"> <div id="content" class="col-lg-4 col-lg-push-4 col-sm-12 "> <h2></h2> <p></p> </div> <div id="sidebar-left" class="col-lg-4 col-sm-6 col-lg-pull-4"> <h2></h2> <p></p> </div> <div id="sidebar-right" class="col-lg-4 col-sm-6"> <h2></h2> <p></p> </div> </div> </div> )非常简单:

==

这里,class Contact: def __init__(self, phone, name): self.phone = phone self.name = name def __eq__(self, other): return (self.phone == other.phone) and (self.name == other.name) c1 = Contact('647-000-000', 'Andy') print(c1 == Contact('647-000-000', 'Andy')) # True 是一个接受一个参数的方法(它与之比较的东西)并且应该返回__eq__True(或者可以强制转换为布尔值的东西)。这是一个非常简单和“脆弱”的实现,因为False之类的东西会引发错误,但它证明了这个想法。

但是,您无法实现定义引用相等性(c1 == "string")的魔术方法。通常,您应该考虑使用is来测试它们是否完全相同的对象,并使用is来测试这两个对象是否等效

[1]是的,尽管如此,它仍然可以缓存并使用元类或==

答案 2 :(得分:-1)

好吧基本上Python有别名。并检查两个对象是否是您编写的别名

obj1 is obj2 

如果返回True,则它们是别名。好吧,基本上Python检查两个对象id。以上陈述相当于:

id(obj1) == id(obj2)

id(object)用于评估内存中对象的地址。

写作时b is Contact('647-000-000', 'Andy') b已经在内存中找到了一个地址但是当你将它与Contact('647-000-000', 'Andy')进行比较时,Contact('647-000-000', 'Andy')在内存中有一个不同的地址。

我不明白为什么要比较整个班级而不是属性。

b.number == '647-000-000'b.name == 'Andy'将解决您的问题。