类型,其中;是";关键字可能等效于Python中的相等运算符

类型,其中;是";关键字可能等效于Python中的相等运算符,python,reference,identity,variable-assignment,immutability,Python,Reference,Identity,Variable Assignment,Immutability,对于Python中的某些类型,is运算符似乎等同于=运算符。例如: >>> 1 is 1 True >>> "a spoon" is "a spoon" True >>> (1 == 1) is (2 == 2) True 然而,情况并非总是如此: >>> [] == [] True >>> [] is [] False 这对于列表之类的可变类型是有意义的。但是,元组等不可变类型似乎显示相同的行为: &

对于Python中的某些类型,
is
运算符似乎等同于
=
运算符。例如:

>>> 1 is 1
True
>>> "a spoon" is "a spoon"
True
>>> (1 == 1) is (2 == 2)
True
然而,情况并非总是如此:

>>> [] == []
True
>>> [] is []
False
这对于列表之类的可变类型是有意义的。但是,元组等不可变类型似乎显示相同的行为:

>>> (1, 2) == (1, 2)
True
>>> (1, 2) is (1, 2)
False
这引发了几个问题:

  • =
    /
    等价性是否与不变性相关
    
  • 上述行为是指定的,还是实现细节
  • 最重要的是(基本上),我如何知道一个赋值是否会产生一个对象的副本,或者对它的引用?
  • 更新: 如果分配总是通过引用,为什么下面不打印
    2

    >>> a = 1
    >>> b = a
    >>> a = 2
    >>> b
    1
    
    为什么这不等同于以下C代码段:

    int a = 1;
    int *b = &a;
    a = 2;
    printf("%d\n", *b);
    
    很抱歉这个问题太生疏,但我是Python新手,觉得理解这一点很重要。你有没有什么可以推荐的读物来理解这类问题

    等价性是否与不变性有关

    没有

    请参阅为什么它对字符串有效,以及为什么它对整数有效(因此bools也是出于同样的原因)

    上述行为是指定的,还是实现细节

    实施细节

    我如何知道赋值是否会导致生成对象的副本或引用

    赋值总是通过引用。仅当您明确使用
    copy.copy
    (或类似内容)时,才可以进行复制

    编辑:通过引用,我并不意味着C++中的引用。Python的赋值将重新绑定变量。更像是

    // int* a, *b;
    a = new int(1);
    b = a;
    a = new int(2);
    printf("%d\n", *b);
    
     int *a = getFromCacheOrCreateNewInteger(1);
    

    is
    操作符测试两个对象在物理上是否相同,也就是说它们在内存中的地址是否相同。这也可以使用
    id()
    函数进行测试:

    >>> a = 1
    >>> b = 1
    >>> a is b
    True
    >>> id(a) == id(b)
    True
    
    另一方面,
    =
    操作符测试语义平等性。这也可以通过实现
    \uuu eq\uuu()
    函数被自定义类覆盖。在语义上,如果两个不同的列表的元素都相等,那么它们是相等的,但在物理上它们是不同的对象

    Python实现可能会将字符串和元组等不可变类型合并在一起,这样两个文本字符串对象实际上在物理上是相同的。但这并不意味着您可以始终使用
    is
    来比较这些类型,如下例所示:

    >>> "foobar" is "foobar"   # The interpreter knows that the string literals are
    True                       # equal and creates only one shared object.
    >>> a = "foobar"
    >>> b = "foobar"
    >>> a is b        # "foobar" comes from the pool, so it is still the same object.
    True
    >>> b = "foo"     # Here, we construct another string "foobar" dynamically that is
    >>> b += "bar"    # physically not the same as the pooled "foobar".
    >>> a == b
    True
    >>> a is b
    False
    
    Python中的赋值总是将对对象的引用绑定到变量名上,并且从不表示副本

    更新

    与C类似,请考虑Python变量始终是指针:

    >>> a = 1
    >>> b = a
    >>> a = 2
    >>> b
    1
    
    大致相当于:

    const int ONE = 1;
    const int TWO = 2;
    
    int *a = &ONE;
    int *b = a;  /* b points to 1 */
    a = &TWO;    /* a points to 2, b still points to 1 */
    

    如果你来自C或C++背景,那么很可能简单地解释Python中的所有变量都是指针。所以声明

     a = 1
    
    确实大致与

     Object *a = new Integer(1);
    

    is
    运算符检查指针是否相等,而
    =
    运算符涉及的计算取决于对象的类型

    该方案的一点复杂之处在于,如果对象是不可变的(例如整数),那么出于效率原因,上面的代码确实有点类似

    // int* a, *b;
    a = new int(1);
    b = a;
    a = new int(2);
    printf("%d\n", *b);
    
     int *a = getFromCacheOrCreateNewInteger(1);
    
    因此,有时(但这是一个实现细节)不可变对象可能是
    is
    的同一对象,即使它们是从逻辑角度独立创建的(例如,
    1+1是2-1
    ,但不保证):

    更让人困惑的是,即使Python中的alla变量确实是指针,但令人惊讶的是,Python中没有指针概念,换句话说,没有办法传递一个函数,该函数应该存储哪些变量

    为此,您需要传递一个名称(如果变量是全局变量)或传递一个要调用的setter函数(如果变量是局部变量)。这并不是什么大麻烦,因为在大多数情况下,您只需要多个返回值,Python已经很好地处理了这一点:

    def foo(x):
        return x+1, x-1
    
    a, b = foo(12)
    
    另一个额外的麻烦是,如果您真的需要为没有名称的局部变量(例如列表的元素)传递setter,它不能是匿名
    lambda
    ,因为赋值是语句,并且
    lambda
    只允许一个表达式。但是,您可以为此定义本地函数

    def foo(x, setter):
        setter(x + 1)
    
    def bar():
        mylocal = [1,2,3]
    
        def setFirst(value):
            mylocal[0] = value
    
        foo(32, setFirst)
    
    (好吧,我撒谎了……确实可以使用
    lambda值:mylocal.\uuuuSetItem\uuuuu(0,value)
    但这或多或少是一个不必要的事件;
    lambda在Python中是如此令人讨厌,以至于一旦他们发现这是可能的,可能会在语言中添加另一个限制来禁止它;-))

    如果您想改为更改命名的本地,这在Python2.x中是不可能的(但在Python3.x和
    非本地
    中也是可能的)

    关于何时执行复制以及何时只复制指针的问题,答案非常简单。Python从来不会自动复制。。。如果您想复制,您必须自己明确地复制。这就是为什么例如常见的代码如下:

    class Polygon:
        def __init__(pointlist):
            self.pointlist = pointlist[:]
    

    [:]
    符号在这里表示类实例希望存储传递的列表的副本,这样,如果您创建一个带有点列表的
    多边形的实例,并且稍后修改此列表,则几何体不会更改。

    更新了问题作为响应,如果可以,请更新答案。啊哈,我想我现在明白多了,谢谢。你能推荐什么读物吗?过于简单化:python中没有变量,只有名称“python中没有变量,只有名称”是一个误导性的、没有帮助的口号。