简单地说是用Python
赋值语句可以是普通语句,也可以是扩展语句。 对变量(例如,name=value )的简单赋值是如何创建新变量或将现有变量重新绑定到新值的方法。对对象属性(例如,x.attr=value )的简单赋值是对对象x的请求,以创建或重新绑定属性'attr‘。对容器中的项(例如,xk=value )的简单赋值是对容器x的请求,目的是用索引或键k创建或重新绑定项。 增广赋值(例如name+=value )本身不能创建新的引用。增广赋值可以重新绑定变量,要求对象重新绑定其现有属性或项之一,或者请求目标对象修改自身。当您向对象提出请求时,由对象来决定是否和如何满足请求,以及是否引发异常。 ..。 在增广赋值中,就像在普通赋值中一样,Python首先计算RHS表达式。然后,当LHS引用一个对象,该对象具有适合于适当的操作符就地版本的特殊方法时,Python将使用RHS值作为其参数调用该方法。这取决于适当修改LHS对象并返回修改后的对象的方法(第123页中的“特殊方法”涵盖了特殊的meth- ods)。当LHS对象没有适当的就地特殊方法时,Python将相应的二进制运算符应用于LHS和RHS对象,然后将目标引用重新绑定到运算符的结果。例如,当x有用于就地加法的特殊方法x+=y时,
x=x.__iadd__(y)就像x=x.__iadd__(y).否则,x+=y就像x=x+y。 增广赋值从不创建其目标引用;在执行增广赋值时,目标必须已被绑定。增广赋值可以将目标引用重新绑定到新对象,或者修改目标引用已经绑定的相同对象。相比之下,普通赋值可以创建或重新绑定LHS目标引用,但它从不修改以前绑定目标参考的对象(如果有的话)。在这里,对象和对象引用之间的区别是至关重要的。例如,x=x+y不修改名称x最初绑定到的对象。相反,它重新绑定名称x以引用新对象。相反,x+=y修改名称x所绑定的对象,当该对象具有特殊方法__iadd__时;否则,x+=y将名称x重新绑定到一个新对象,就像x=x+y一样。
助力是否执行就地修改和非原地赋值(例如,由增广赋值和普通赋值所使用)、Python的一些实现细节(这是Python中的程序员不需要知道的),还是属于程序员需要知道的语义的东西?注意:就地修改意味着改变内存区域中的值,而非就地分配则分配一个新的内存区域。
如果答案是否定的,为什么Python中的程序员需要知道区别呢?在任何情况下,Python中的程序员都需要意识到这种区别吗?
我怀疑不同之处在于实现细节,Python中的程序员不需要知道差异,而只需要知道赋值的语义。
谢谢。
发布于 2020-04-09 18:27:53
文档说,关于__i<method>__的特殊方法:
这些方法被调用以实现增强算术赋值(
+=、-=、*=、@=、/=、//=、%=、**=、<<=、>>=、&=、^=、|=)。这些方法应该尝试执行就地操作(修改self)并返回结果(可以是,但不必是self)。如果未定义特定方法,则增广分配返回到正常方法。例如,如果x是具有__iadd__()方法的类的实例,则x += y等同于x = x.__iadd__(y)。否则,就会考虑x.__add__(y)和y.__radd__(x),就像x + y的评估一样。在某些情况下,增广赋值可能导致意外错误(请参阅在加法生效时引发异常?),但这种行为实际上是数据模型的一部分。
要回答你提出的问题:
就地修改和不修改(例如由增广赋值和普通赋值所使用)之间的区别是,Python的一些实现细节,Python中的程序员不需要知道这些细节吗?
是的,在为自定义对象实现数据模型时,您需要了解这一点。
作为这样的对象的用户,如果您理解了这一点,您也会更好地理解在使用增广赋值时所做的事情。
为什么?如果不实现就地行为,则在执行增广赋值时,名称或查找将重新分配给操作的标准实现结果的对象。
作为实现者和用户,您需要知道这一点。
以下是提问者的问题:
我的问题是,赋值是否执行就地修改和不就地分配,而不是调用哪种方法。就地修改意味着更改内存区域中的值,而非就地赋值则会创建新的内存区域。我想知道这种区别是否是程序员不需要知道的实现细节,还是属于程序员需要知道的语义的东西。
在Python中,一切都是对象。每个对象都有一个包含一些细节的标题。任何包含其他对象的对象实际上并不包含对象,而是有一个指针或引用,指向它所持有的对象在内存中的位置。对象的突变将引用更改为新的引用。
只有当对该对象的非弱引用的计数变为零时,旧对象的旧位置才会被覆盖。您可以认为这是一个实现细节,但这方面的知识有助于一个人成为一个更加自信的语言用户。
用户很少需要关注这些细节,但当您这样做时,您会很高兴您理解它。
同样,你的问题是:
我的问题是,赋值是否执行就地修改和不就地分配,而不是调用哪种方法。
调用哪种方法将决定行为。因此,您需要知道调用哪个方法--或者从您正在使用的对象的文档的语义,或者从您自己对Python数据模型的知识--来回答您的问题。
发布于 2020-04-09 19:03:15
在任何情况下,Python中的程序员都需要意识到这种区别吗?
Python是一种动态语言,它为您提供了许多免费的多态性(鸭型)。如果一个函数是用来处理列表的,它很可能会在许多类似列表的东西上工作。扩大分配会给这件事带来麻烦。假设函数将数据添加到集合中:
>>> def add_data(collection):
... collection += ('tuple',)
...
>>> l = []
>>> add_data(l)
>>> l
['tuple']
>>> t = tuple()
>>> add_data(t)
>>> t
()在第二种情况下,它无声地失败了。如果对一个对象有多个引用,并且对其中一个对象应用了增广的赋值,这通常是一种风险。这就像一盒巧克力,但很糟糕。
https://stackoverflow.com/questions/61127552
复制相似问题