2015-12-03 84 views
-1

當嘗試一個GUID分配給類實例的代碼,我寫了類似如下的內容:爲什麼不可變的對象拋出UnboundLocalError但可變的對象不?

#!/usr/bin/env python 
# -*- coding: UTF-8 -*- 
x_id = 0 # immutable 
x_id_list = [0] # mutable 
def fx(x): 
    global x_id # Disable to get "UnboundLocalError: local variable 'x_id' referenced before assignment" 
    if x is None: 
     x_id += 2 
     x_id_list[0] += 2 
    else: 
     x_id += 1 
     x_id_list[0] += 1 
     return (x_id - 1) 
    return x_id 

expected = [x for x in xrange(10)] 
actual = [fx(x) for x in expected] 
assert(expected == actual), "expected = {}, actual = {}".format(expected, actual) 
print x_id_list 
print x_id 

注意,只有永恆不變的x_id拋出,如果其在全球範圍內是沒有定義UnboundLocalError,但可變x_id_list在沒有全球範圍需要定義的情況下繼續正常工作。

這是爲什麼?

+0

我沒有得到一個例外(它不應該提出一個)。你的程序爲我輸出'[10]'和'10'。 – Zizouz212

+0

@ Zizouz212你需要註釋掉'global x_id'這一行來獲取錯誤。 – dimo414

+0

[從父函數分配變量:「賦值前引用的本地變量」](http:// stackoverflow。com/questions/8934772/assign-to-variable-from-parent-function-local-variable-referenced-before-as) – Zizouz212

回答

-1

這是因爲全局範圍變量在函數中是隻讀的。

由於您正在修改變量x_id,所以在使用它之前需要引用它,否則Python將嘗試創建一個新的變量,該變量對函數是本地的。

在函數的開頭使用了global表達式,您告訴Python需要在函數中引用和修改該變量。由於您正在修改變量x_id,因此會發生這種情況。由於x_id_list是可變的,因此您基本上不會對其進行明顯的修改(僅在內部,與x_id不同,這種更改是外部的),因此您不需要global關鍵字。

+0

你是否認爲x_id_list不是隻讀的,但x_id是?還需要參考。 – PoorLuzer

0

的問題不在於x_id是不可變的(它不是 - the integer value 0 is what's immutable),但是,你不能分配給一個函數外定義的變量沒有明確聲明你的意圖通過global這樣做。變更列表x_id_list是指不改變x_id_list變量本身的值,因此是允許的。

如果你試圖做x_id_list += [1]你會遇到同樣的錯誤。它將分配給變量,而不是突變,這是此處的問題。

the docs

在Python中,變量只在函數內部引用隱含全球。如果一個變量在函數體內的任何位置被賦值,它被認爲是一個局部變量,除非明確聲明爲全局變量。

雖然起初有點出人意料,但一時的考慮解釋了這一點。一方面,對指定的變量要求global可以防止意想不到的副作用。另一方面,如果所有全局引用都需要global,則您始終會使用global。您必須聲明爲全局的每個對內置函數的引用或對導入模塊的一個組件。這種混亂將破壞global聲明用於識別副作用的用處。

This answer也進入一些更詳細的內容。

+0

關於「突變列表x_id_list引用不會更改x_id_list的值」的好處。一些參考將是很好的。 – PoorLuzer

+1

@PoorLuzer已經添加:) – dimo414