栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 面试经验 > 面试问答

如何在python中重新分配变量而不更改其ID?

面试问答 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

如何在python中重新分配变量而不更改其ID?

我不确定您是否对Python中的变量或不可变值感到困惑。因此,我将对两者进行解释,答案的一半可能看起来像“不,我已经知道了”,但另一半应该是有用的。


在Python中(与C不同),变量不是值所在的位置。这只是一个名字。价值观生活在他们想要的任何地方。1因此,当您执行此操作时:

a = 10b = a

您没有

b
提及
a
。这个想法在Python中甚至没有意义。您正在
a
为命名
10
,然后
b
为命名
10
。如果以后再执行此操作:

a = 11

…您已经

a
为命名
11
,但这对并没有影响
b
-它仍然只是的名字
10


这也意味着,

id(a)
是不是给你的变量的ID
a
,因为那里
没有这样的事情。
a
只是在某个名称空间中查找的名称(例如,模块的全局变量)。它的 价值
11
(或者,如果你运行它更早的版本,不同的值
10
),有一个ID。(虽然我们正在这样做:它也是键入的值,而不是变量。在这里不相关,但值得了解。)


关于可变性,事情变得有些棘手。例如:

a = [1, 2, 3]b = a

这仍然使

a
b
两个名称的列表。

a[0] = 0

这不分配

a
,所以
a
b
仍然是相同的列表名称。它 确实
分配给
a[0]
,这是该列表的一部分。因此,列表
a
b
两个名字现在持有
[0, 2, 3]

a.extend([4, 5])

这显然做同样的事情:

a
b
现在的名字列表
[0, 2, 3, 4, 5]


这是令人困惑的地方:

a += [6]

是重新绑定的分配

a
,还是只是对
a
作为其名称的值进行了变异?实际上,两者都是。在幕后的意思是:

a = a.__iadd__([6])

…或大致来说:

_tmp = a_tmp.extend([6])a = _tmp

因此,我们 正在 分配给

a
,但我们正在为其分配与已经命名的相同的值。同时,我们也正在对该值进行突变,该值仍然是
b
命名的值。


所以现在:

a = 10b = 10a += 1

您可能会猜到最后一行是这样的:

a = a.__iadd__(1)

这不是很正确,因为

a
没有定义
__iadd__
方法,所以可以归结为:

a = a.__add__(1)

但这不是重要的部分。2重要的一点是,因为整数与列表不同,是不可变的。您无法像在INTERCAL或Fortran(或类似的Fortran)中那样将数字10转换为11,或者您曾经是最奇怪的X-
Man的那个奇怪的梦想。而且没有可以设置为11的“保持数字10的变量”,因为它不是C ++。因此,这 必须 返回一个新值,即value

11

因此,

a
成为该新产品的名称
11
。同时,
b
仍然是的名称
10
。就像第一个例子一样。


但是,在所有这些告诉您要做您想做的事情是多么不可能之后,我将告诉您做您想做的事情是多么容易。

还记得以前,当我提到您可以对列表进行突变时,该列表的所有名称都会看到新值吗?因此,如果您这样做:

a = [10]b = aa[0] += 1

现在

b[0]
将会是
11


或者您可以创建一个类:

class Num:    passa = Num()a.num = 10b = aa.num += 1

现在

b.num
11


或者你甚至可以创建一个类,工具

__add__
__iadd__
和所有其他数字方法,所以它可以容纳数(几乎)透明的,但这样做的性情不定地。

class Num:    def __init__(self, num):        self.num = num    def __repr__(self):        return f'{type(self).__name__}({self.num})'    def __str__(self):        return str(self.num)    def __add__(self, other):        return type(self)(self.num + other)    def __radd__(self, other):        return type(self)(other + self.num)    def __iadd__(self, other):        self.num += other        return self    # etc.

现在:

a = Num(10)b = aa += 1

而且

b
是相同的名称
Num(11)
作为
a

但是,如果您确实想执行此操作,则应考虑制作特定的东西(

Integer
而不是泛型的
Num
东西)来保存像数字一样的内容,并在
numbers
模块中使用适当的ABC来验证您是否涵盖了所有关键方法,从而获得大量可选方法的免费实现,并能够通过
isinstance
类型检查。(并且可能
num.__int__
以这种方式调用它的构造函数
int
,或者至少是特殊情况,
isinstance(num,Integer)
这样您就不会最终得到对引用的引用……除非您要这样。)


好吧,他们住在口译员想要他们住的地方,就像在齐奥塞斯库统治下的罗马尼亚人一样。但是,如果您是用C编写的内置/扩展类型并且是Party的付费成员,则可以

__new__
使用不依赖于
super
分配的构造函数来覆盖它,否则您别无选择。

2.但这并不是完全不重要的。按照约定(当然,在所有内置类型和stdlib类型中都遵循约定),

__add__
不进行更改,而是进行更改
__iadd__
。因此,像这样的可变类型
list
定义了两者,这意味着它们对都具有就地行为,
a+= b
但对却具有复制行为
a +b
,而不可变类型像对
tuple
和都
int
定义了
__add__
,因此它们对两者都有复制行为。Python不会强迫您以这种方式执行操作,但是如果您的类型没有选择这两种类型之一,您的类型将非常奇怪。如果您熟悉C
++,则是一样的-
通常
operator+=
通过就地变异并返回的引用
this
,然后
operator+
复制然后返回来实现
+=
在副本上,但是语言不会强迫您这样做,如果不这样做,只会令人感到困惑。



转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/669267.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号