14

我在尝试学习python时遇到了这个问题。考虑以下函数:

def swap0(s1, s2):
    assert type(s1) == list and type(s2) == list
    tmp = s1[:]
    s1 = s2[:]
    s2 = tmp
return

s1 = [1]
s2 = [2]
swap0(s1, s2)
print s1, s2

s1 和 s2 会打印什么?

运行问题后发现print语句会打印1 2。从函数上看s1和s2的值好像没有变化swap0。我能想到的唯一解释是因为这条线。

tmp = s1[:]

由于 s1[:] 是一个副本,因此 s1 的值在函数调用中不会改变是有道理的。但是因为参数swap0是(s1,s2),所以我不确定是否在做tmp = s1[:]之后。任何时候我做

s1 = something...

它将是对 s1 副本的引用,而不是 s1 本身。有人可以提供更好的解释吗?谢谢。

4

8 回答 8

31

s1这是因为它为函数和函数s2内部分配了新值swap0。这些分配不会传播到函数之外。如果您只是将函数体复制并粘贴到函数调用的位置,您会发现它是有效的。

您可以通过修改参数引用的对象而不是参数本身来解决此问题:

def swap0(s1, s2):
    assert type(s1) == list and type(s2) == list
    tmp = s1[:]
    s1[:] = s2
    s2[:] = tmp

然而,在 Python 中进行交换的更简单更好的方法是:

s1, s2 = s2, s1

这也只会交换那些对列表的特定引用,而不是列表内容本身。

于 2012-10-31T21:00:25.010 回答
13

实际上,您的最终print结果将打印出 和 的原始s1s2。这是因为您只是在函数范围内交换它们。这样做不会影响它们在函数外的值(即在调用函数后它们的值之后)

如果它们是可变类型(listsetdict等),那么您可以在内部就地修改它们swap。但是,这仅限swap于对可变类型起作用。

因此,您最好以相反的顺序返回输入:

def swap(s1, s2):
    return s2, s1

s1 = 'a'
s2 = 'b'
s1, s2 = swap(s1, s2)
print s1, s2 # prints 'b a'

当然,您可以在一行中完成所有操作,如下所示:

s1, s2 = s2, s1

干杯!

于 2012-10-31T21:02:09.353 回答
6

其他答案解释了出了什么问题。这是一个可以满足您要求的版本:

def swap(s1, s2):
    assert isinstance(s1, list) and isinstance(s2, list)
    s1[:], s2[:] = s2[:], s1[:]

另请参阅:isinstance 与类型

于 2012-10-31T21:09:29.230 回答
4

在函数内部,您将重新绑定局部变量s1s2使用右侧的值(这也是本地的,因为您使用切片来制作副本)。即使您更改了这些局部变量的内容,也不会更改调用范围内列表的内容,因为它们不再引用相同的列表。

于 2012-10-31T21:00:33.697 回答
2

这是实现您的目标的单行函数:

swap = lambda x: (x[1], x[0])
于 2016-06-08T14:32:59.757 回答
2

如果两个列表的长度相同,您也可以通过使用索引和循环的旧交换方法来执行此操作。这是一种老派,但有助于理解索引

a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0]
b = [0, 9, 8, 7, 6, 5, 4, 3, 2, 1]

for i in range(0, len(a)):
    a[i] = a[i] + b[i]
    b[i] = a[i] - b[i]
    a[i] = a[i] - b[i]

print(a)
print(b)

这将使输出为:

 [0,9,8,7,6,5,4,3,2,1]
 [1,2,3,4,5,6,7,8,9,0]

或者也可以使用 Xor 来完成。Xor 运算符是按位运算符,例如在操作数之间进行 Xor 运算。

a = 5 #0b101
b = 4 #0b100
c = a ^ b #0b001

0b101是 50b100的二进制表示,是 4 的二进制表示,当您对这些进行异或运算时,您将输出0b001即 1 。如果一个且只有一个输入为 1,则异或返回 1 个输出结果。如果两个输入为 0 或两者均为 1,则输出 0 个结果。我们可以使用 Xor 交换两个变量,例如:

a = 5        # 0b0101
b = 9        # 0b1001
a = a ^ b    # Xor (0b0101, 0b1001) = 0b1100 (12)
b = a ^ b    # Xor (0b1100, 0b1001) = 0b0101 (5)
a = a ^ b    # Xor (0b1100, 0b0101) = 0b1001 (9)
print("a = {} and b = {}".format(a, b))

输出将是a = 9 and b = 5

同样,我们也可以通过对其中的项目进行异或操作来交换两个列表,例如:

a = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 ]
b = [ 0, 9, 8, 7, 6, 5, 4, 3, 2, 1 ] 

for i in range(0, len(a)) :
     a[i] = a[i] ^ b[i] 
     b[i] = a[i] ^ b[i] 
     a[i] = a[i] ^ b[i] 

print(a)
print(b)

输出:

[0, 9, 8, 7, 6, 5, 4, 3, 2, 1]
[1, 2, 3, 4, 5, 6, 7, 8, 9, 0]

让我们看另一个场景,如果我们需要交换列表中的项目,例如:我们有一个这样的列表x = [ 13, 3, 7, 5, 11, 1 ],我们需要像这样交换它的项目x = [ 1, 3, 5, 7 , 11, 13 ] 所以我们可以通过使用两个按位运算符 Xor^和 Compliments来做到这一点~

代码 :

# List of items 
a = [ 13, 3, 7, 5, 11, 1 ]

# Calculated the length of list using len() and
# then calulated the middle index of that list a 

half = len(a) // 2

# Loop from 0 to middle index
for i in range(0, half) :

# This is to prevent index 1 and index 4 values to get swap 
# because they are in their right place.
if (i+1) % 2 is not 0 :

    #Here ~i means the compliment of i and ^ is Xor,
    # if i = 0 then ~i will be -1 
    # As we know -ve values index the list from right to left 
    # so a [-1] = 1 

    a[i] = a[i] ^ a[~i] 
    a[~i] = a[i] ^ a[~i] 
    a[i] = a[i] ^ a[~i]

print(a)

所以输出将是[1, 3, 5, 7, 11, 13]

于 2017-07-18T18:37:46.797 回答
2

你可以有这个:

def swap(x , y):
  x , y = y , x
  return x , y

x  = 5
y = 10

print ('x is {0} and y is {1}'.format(x,y))    # x is 5 and y is 10
x , y = swap(x,y)                              # doing swap 
print ('x is {0} and y is {1}'.format(x,y))    # x is 10 and y is 5
于 2018-03-18T21:21:28.127 回答
-1

根本不需要功能。a,b=b,a 可以解决问题。

    >>> a,b=1,2
    >>> print (a,b)
    (1, 2)
    >>> a,b=b,a
    >>> print (a,b)
    (2, 1)
    >>>

它也适用于数组。但是,如果您非常想要这里的功能,那就是

    def swap(a,b)
       return b,a
于 2019-04-16T15:27:03.047 回答