python中for语句中对当前遍历对象赋值的问题?
PHP中文网
PHP中文网 2017-04-17 17:23:44
0
4
964

我有一个二维列表,列表中的元素是以字符串为元素的列表。
由于这些字符串表示的是数字,我想把这些字符串都转换成float型。

def loadCsv(filename):
    # 取出数据
    lines = csv.reader(open(filename, 'rb'))
    # 存入dataset
    dataset = list(lines)
    for data in dataset:
        for i in data:
            i = float(i) #为什么执行了该语句后i不变?
    return dataset

上面这段程序执行后dataset不变,为什么i = float(i)不能改变i的值呢?
虽然我知道这样写不是好习惯,但是想问python里for语句中所遍历的对象并不是在原对象上修改?

def loadCsv(filename):
    # 取出数据
    lines = csv.reader(open(filename, 'rb'))
    # 存入dataset
    dataset = list(lines)
    for i in range(len(dataset)):
        dataset[i] = [float(x) for x in dataset[i]]
    return dataset

这段程序能够成功,又是为什么呢?

PHP中文网
PHP中文网

认证高级PHP讲师

membalas semua(4)
迷茫

Pembolehubah hanyalah penunjuk kepada objek

Fahami, kemudian teruskan membaca.

Jenis pertama: Semasa traversal, penunjuk bernama i dicipta dan menunjuk ke elemen dalam data. Apabila anda melaksanakan i=float(i), anda hanya mencipta objek baru float(i) dan biarkan saya menunjuk kepadanya, itu sahaja.

Kaedah kedua adalah sama.

左手右手慢动作

Tepatnya, i = float(i) memang mengubah nilai i, tetapi i hanyalah salinan elemen data dan tidak mengubah nilai data, sama seperti:

>>> a = ["ab", "cd"]
>>> i = a[0]
>>> i = 123
>>> a
['ab', 'cd']

Yang kedua adalah kerana anda beroperasi terus pada senarai asal:

>>> a[0] = 123
>>> a
[123, 'cd']
PHPzhong

Dalam python, apabila melintasi objek melalui untuk, anda tidak boleh mengubah suai objek yang dilalui itu sendiri. Ini adalah peraturan umum.
Secara umumnya, elemen seterusnya diperoleh melalui kaedah next().
Jika objek traversal dibenarkan untuk diubah suai, ia akan menjejaskan susunan elemen, menjadikan keputusan setiap langkah seterusnya tidak dapat dikawal.
Pertimbangkan untuk menggunakan enumerate untuk mengubah suainya.

untuk i,v dalam enumerate(data):

data[i] = float(v)

Pada masa ini, objek lelaran ialah enumerate(data), bukan data, jadi ia boleh diubah suai.

Untuk mendapatkan maklumat tambahan, sila rujuk huraian pernyataan for dalam manual Python rasmi:
https://docs.python.org/2/reference/compound_stmts.html#the-for-statement

伊谢尔伦

Dalam for traversal dalam Python, biasanya tidak disyorkan (tidak mustahil) untuk mengubah suai secara langsung objek traversal itu sendiri, kerana ini akan menyebabkan masalah yang serupa dengan yang berikut:

n = [1, 2, 3]
for i in n:
    n.append(i)
    print(i)

Atur cara di atas akan memasuki gelung tak terhingga kerana panjang n bertambah dengan setiap lelaran, jadi for tidak akan pernah habis, jadi kami biasanya menggunakan salinan objek lelaran untuk melintasi:

n = [1, 2, 3]
for i in n[:]:
    n.append(i)
    print(i)

Dengan cara ini, nilai n boleh diubah suai dan traversal dapat diselesaikan dengan jayanya.

Sekarang kembali ke program pertama dalam contoh anda:

def loadCsv(filename):
    # 取出数据
    lines = csv.reader(open(filename, 'rb'))
    # 存入dataset
    dataset = list(lines)
    for data in dataset:
        for i in data:
            i = float(i) #这里前后两个`i`其实指代的是不同的对象
    return dataset

Malah, dua sebelum dan selepas i = float(i) anda sama sekali tidak merujuk kepada objek yang sama i yang terakhir ialah elemen data dan yang pertama i ialah pembolehubah setempat dalam. loadCsv skop , ini melibatkan perkara yang tidak munasabah dalam reka bentuk bahasa Python, mari kita lihat program:

for i in range(3):
    pass

print(i)
# 2

Maksudnya, pengecam i yang mengambil bahagian dalam lelaran belum dikitar semula selepas keluar daripada gelung for dan mengekalkan perkaitan dengan nilai terakhir lelaran, yang akan menjejaskan pembolehubah global dengan yang sama nama. Ralat ini sering berlaku:

i = 7

for i in range(3):
    pass

print(i)
# 2

Selepas gelung for, nilai pembolehubah global i berubah secara tidak dapat dijelaskan Sebabnya ialah i sebenarnya bukan objek itu sendiri, tetapi pengecam objek itu bukan atribut objek, tetapi atribut objek adalah sebahagian daripada ruang nama yang boleh digunakan semula.

Jadi apabila pengecam for dengan nama yang sama diberikan dalam gelung i, situasinya berbeza:

for i in range(5):
    i = 3
    
print(i)
# 3

Nilai i di sini betul-betul sama dengan nilai yang diberikan kepadanya dalam for Sebabnya ialah operasi penetapan dalam Python ialah operasi mengaitkan objek nilai dengan pengecam semasa lelaran terakhir , nilai 3 wasiat dikaitkan dengan pengecam i, jadi i terikat pada objek baharu anda, ini adalah kesnya: i = float(i) Ia mengikat objek nilai float(i) kepada pengecam i, jadi i yang ditetapkan bukan objek elemen data sama sekali, jadi dataset tidak akan diubah.
Dan program kedua anda:

def loadCsv(filename):
    # 取出数据
    lines = csv.reader(open(filename, 'rb'))
    # 存入dataset
    dataset = list(lines)
    for i in range(len(dataset)):
        dataset[i] = [float(x) for x in dataset[i]]
    return dataset

dalam fori hanyalah indeks yang anda ubah suai bukan i, tetapi objek yang dikaitkan dengan pengecam dataset[i] dan dataset[i] ialah elemen komponen dataset, jadi. ia boleh diubah data.

Untuk pengecam dan ruang nama, anda boleh membaca artikel ini: Ruang nama Python

Muat turun terkini
Lagi>
kesan web
Kod sumber laman web
Bahan laman web
Templat hujung hadapan