Apakah ada metode standar untuk menukar dua variabel dengan Python?

345

Dalam Python, saya telah melihat dua nilai variabel bertukar menggunakan sintaks ini:

left, right = right, left

Apakah ini dianggap sebagai cara standar untuk menukar dua nilai variabel atau apakah ada cara lain yang dengannya dua variabel biasanya ditukar?

WilliamKF
sumber
1
@eyquem: hanya turun ke apakah urutan-evaluasi- didefinisikan oleh bahasa untuk tugas tuple / daftar. Python melakukannya, sebagian besar bahasa lama tidak.
smci
Hrmm C ++ memiliki swap (a [i], a [k]) mengapa kita tidak dapat memiliki sesuatu seperti ini untuk Python.
Nils

Jawaban:

389

Python mengevaluasi ekspresi dari kiri ke kanan. Perhatikan bahwa saat mengevaluasi suatu tugas, sisi kanan dievaluasi sebelum sisi kiri.

http://docs.python.org/3/reference/expressions.html#evaluation-order

Itu berarti yang berikut untuk ekspresi a,b = b,a:

  • sisi kanan b,adievaluasi, artinya dua elemen dibuat dalam memori. Dua elemen adalah objek yang ditunjuk oleh pengidentifikasi bdan a, yang ada sebelum instruksi diberikan selama pelaksanaan program
  • tepat setelah pembuatan tuple ini, tidak ada tugas objek tuple ini masih dibuat, tetapi tidak masalah, Python secara internal tahu di mana itu
  • kemudian, sisi kiri dievaluasi, artinya tuple ditugaskan ke sisi kiri
  • karena sisi kiri terdiri dari dua pengidentifikasi, tuple dibongkar agar pengidentifikasi pertama aditugaskan ke elemen pertama tuple (yang merupakan objek yang sebelumnya b sebelum swap karena memiliki nama b)
    dan identifier kedua bditugaskan untuk elemen kedua dari tuple (yang merupakan objek yang sebelumnya seorang sebelum swap karena pengidentifikasi nya adalah a)

Mekanisme ini telah secara efektif menukar objek yang ditugaskan untuk pengidentifikasi adanb

Jadi, untuk menjawab pertanyaan Anda: YA, itu adalah cara standar untuk bertukar dua pengidentifikasi pada dua objek.
By the way, objek bukan variabel, mereka adalah objek.

eyquem
sumber
1
Sejauh yang saya mengerti, menukar dua variabel dengan cara ini TIDAK menggunakan memori tambahan, hanya memori untuk 2 variabel sendiri, apakah saya benar?
Catbuilts
1
@Catbuilts Membangun tuple akan memakan beberapa memori tambahan (kemungkinan lebih dari versi 3-variabel dari swap akan mengambil), tetapi karena satu-satunya hal yang ditukar adalah alamat memori, itu tidak akan banyak memori ekstra di absolut akal (mungkin 24 byte tambahan).
Brilliand
@Brilliand: Terima kasih. Apakah Anda memiliki dokumen untuk subjek ini. Ini cukup menarik dan saya ingin membaca lebih lanjut. Terima kasih.
Catbuilts
1
@Catbuilts Saya tidak yakin, tetapi mungkin membantu untuk membaca tentang cara kerja pointer C ++. Sedangkan Python mencoba untuk secara otomatis melakukan hal-hal dengan cara terbaik untuk Anda, C ++ sebenarnya memberi Anda semua opsi untuk melakukan hal-hal dengan cara yang benar dan salah yang mungkin, jadi itu adalah titik awal yang baik untuk mempelajari apa kelemahannya dari pendekatan yang diambil oleh Python . Juga ingat bahwa memiliki sistem operasi "64-bit" berarti bahwa menyimpan alamat memori membutuhkan 64 bit memori - itulah bagian dari mana saya mendapatkan nomor "24 byte" saya.
Brilliand
Penjelasan yang bagus. Hanya menambahkan bahwa inilah sebabnya Anda juga dapat menggunakan metode ini untuk mengatur ulang sejumlah "variabel", misalnya a, b, c = c, a, b.
alexlomba87
109

Itu adalah cara standar untuk menukar dua variabel, ya.

Martijn Pieters
sumber
38

Saya tahu tiga cara untuk menukar variabel, tetapi a, b = b, apaling sederhana. Ada

XOR (untuk bilangan bulat)

x = x ^ y
y = y ^ x
x = x ^ y

Atau singkatnya,

x ^= y
y ^= x
x ^= y

Variabel sementara

w = x
x = y
y = w
del w

Tukar swap

x, y = y, x
Tidak Ada Di Sini
sumber
1
Apakah yang paling sederhana dan satu-satunya yang tidak dikaburkan.
Jorge Leitao
17
XOR tidak menukar "variabel". Ini swap variabel integer. (Atau beberapa tipe lain yang menerapkan operator XOR dengan benar) Selanjutnya, karena menurut jawaban Rogalski, Tuple Swap dioptimalkan dalam interpreter, benar-benar tidak ada yang menentangnya. Singkat, jelas, dan cepat.
Rawler
Masalah XOR dapat dihindari dengan + - penggunaan operator, tapi tetap saya merasa yang terbaik adalah a, b = b, a code= x + yy = xy x = xycode
ashish
22

Saya tidak akan mengatakan itu adalah cara standar untuk bertukar karena akan menyebabkan beberapa kesalahan yang tidak terduga.

nums[i], nums[nums[i] - 1] = nums[nums[i] - 1], nums[i]

nums[i]akan dimodifikasi terlebih dahulu baru kemudian mempengaruhi variabel kedua nums[nums[i] - 1].

Yi Huang
sumber
2
Anda memiliki masalah di hampir semua bahasa pemrograman, yaitu tidak aman untuk menggunakan swap (a, b), jika a bergantung pada b atau sebaliknya. Misalnya, swap (a, b) mungkin diperluas ke: var c=a, a=b, b=c. Dan kemudian, tugas terakhir akan menggunakan nilai baru auntuk mengevaluasi alamat b.
Kai Petzke
1
nums[nums[i] - 1], nums[i] = nums[i], nums[nums[i] - 1]. Akan menyelesaikan masalah.
Bill Cheng
1
Ini memang memecahkan masalah, tetapi mengapa?
Jackson Kelley
2
@JacksonKelley Evaluasi sisi kanan aman. Dalam nums[i], nums[nums[i] - 1] = nums[nums[i] - 1], nums[i]: Masalahnya adalah ketika python melakukan tugas sisi kiri, nums[i]diubah, yang menyebabkan nums[nums[i] - 1]perubahan tak terduga. Anda dapat membayangkan pada awalnya Anda inginkan nums[1],nums[2] = nums[2],nums[1], tetapi setelah nums[1] = nums[2]berlari, Anda tidak lagi memilikinya nums[2] = nums[1], sebaliknya Anda mendapatkannya nums[888] = nums[1].
guo
5

Tidak berfungsi untuk array multidimensi, karena referensi digunakan di sini.

import numpy as np

# swaps
data = np.random.random(2)
print(data)
data[0], data[1] = data[1], data[0]
print(data)

# does not swap
data = np.random.random((2, 2))
print(data)
data[0], data[1] = data[1], data[0]
print(data)

Lihat juga Swap irisan array Numpy

gizzmole
sumber
Ini memang fitur khusus (atau bug) dari perpustakaan yang numpy.
Kai Petzke
-1

Untuk mengatasi masalah yang dijelaskan oleh eyquem , Anda dapat menggunakan copymodul untuk mengembalikan tuple yang berisi salinan nilai yang dibalik, melalui fungsi:

from copy import copy

def swapper(x, y):
  return (copy(y), copy(x))

Fungsi yang sama dengan lambda:

swapper = lambda x, y: (copy(y), copy(x))

Kemudian, tetapkan itu ke nama yang diinginkan, seperti ini:

x, y = swapper(y, x)

CATATAN: jika Anda ingin, Anda bisa mengimpor / menggunakan deepcopyalih-alih copy.

LogicalBranch
sumber
apa masalah yang Anda coba selesaikan dengan copy?
Hanan Shteingart
Yang dibahas di pos eyquem .
LogicalBranch
1
tetapi tidak menyatakan masalah, bahkan dia berkata "YA, itu cara standar untuk bertukar dua pengidentifikasi"
Hanan Shteingart
-2

Anda dapat menggabungkan tuple dan XOR swap: x, y = x ^ x ^ y, x ^ y ^ y

x, y = 10, 20

print('Before swapping: x = %s, y = %s '%(x,y))

x, y = x ^ x ^ y, x ^ y ^ y

print('After swapping: x = %s, y = %s '%(x,y))

atau

x, y = 10, 20

print('Before swapping: x = %s, y = %s '%(x,y))

print('After swapping: x = %s, y = %s '%(x ^ x ^ y, x ^ y ^ y))

Menggunakan lambda :

x, y = 10, 20

print('Before swapping: x = %s, y = %s' % (x, y))

swapper = lambda x, y : ((x ^ x ^ y), (x ^ y ^ y))

print('After swapping: x = %s, y = %s ' % swapper(x, y))

Keluaran:

Before swapping: x =  10 , y =  20
After swapping: x =  20 , y =  10
betcha
sumber