2012-06-13 147 views
59

學習python,並且有一些基本的疑問。Python變量聲明

1.I看到變量聲明(路徑這裏)作爲

class writer: 
    path = "" 

有時,沒有明確的聲明,而是通過__init__初始化。

def __init__(self, name): 
    self.name = name 

我明白__init__的目的,但它是最好的任何其他職能聲明變量。

2.如何創建變量來保存自定義類型?

class writer: 
    path = "" # string value 
    customObj = ?? 
+10

而且,關於第二個問題:在Python中,變量沒有類型:值做。所以任何變量都可以容納自定義對象。 – jpaugh

+3

如果您不再將名稱/標識符視爲_variables_,它將有所幫助。他們是_references_對象 –

+2

@gnibbler或他們的名字... – detly

回答

148

好的,首先要做的事情。

Python中沒有「變量聲明」或「變量初始化」這樣的事情。

簡而言之,我們稱之爲「分配」,但應該只是稱爲「命名」。

分配意味着「現在左側的這個名稱指的是評估右側的結果,不管之前(如果有的話)引用了什麼」。因此,Python的名稱(可以說比「變量」更好的一個術語)沒有關聯的類型;但是,值的確如此。無論其類型如何,您都可以將相同的名稱重新應用於任何事物,但事物仍然具有取決於其類型的行爲。該名稱只是一種引用值(對象)的方法。這回答你的第二個問題:你不要創建變量來保存自定義類型。您不會創建變量來保存任何特定的類型。你根本不「創造」變量。你給對象命名。

觀點二:Python中遵循一個非常簡單的規則,當涉及到的類,它實際上是比什麼語言如Java,C++和C#做的更加一致:一切宣告內class塊是類的一部分。因此,這裏編寫的函數(def)是方法,即類對象的一部分(不是以每個實例爲基礎存儲),就像在Java,C++和C#中一樣;但這裏的其他名稱是也是的一部分。同樣,這些名稱只是名稱,它們沒有關聯類型,並且函數也是Python中的對象。因此:

class Example: 
    data = 42 
    def method(self): pass 

類是對象太,在Python。

所以現在我們創建了一個名爲Example對象,它代表了所有事物的類別Example s。這個對象有兩個用戶提供的屬性(在C++中,「成員」;在C#中,「字段或屬性或方法」;在Java中,「字段或方法」)。其中一個名爲data,它存儲整數值42。另一個名爲method,它存儲一個函數對象。(還有幾個Python自動添加的屬性。)

雖然這些屬性仍然不是對象的一部分。從根本上講,一個對象只是一堆更多的名稱(屬性名稱),直到你找到不能再分開的東西。因此,如果您有意設置這些值,則可以在類的不同實例之間共享值,甚至可以在不同類的對象之間共享值。

讓我們創建一個實例:

x = Example() 

現在我們有一個名爲x一個單獨的對象,這是Example一個實例。 datamethod實際上並不是對象的一部分,但我們仍然可以通過x查找它們,因爲Python在幕後有一些神奇的功能。特別是當我們查詢method時,我們將取而代之得到一個「綁定方法」(當我們稱之爲x時,將自動作爲self參數通過,如果我們直接查找Example.method則不會發生)。

當我們嘗試使用x.data時會發生什麼?

當我們檢查它時,首先在對象中查找它。如果在對象中找不到它,Python將在該類中查找。

但是,當我們將分配給x.data時,Python將在該對象上創建一個屬性。它將不是替換類的屬性。

這使我們可以做對象初始化。如果存在,Python會在新實例創建時自動調用類'__init__方法。在這種方法中,我們可以簡單地分配給屬性爲每個對象上的屬性設置初始值:

class Example: 
    name = "Ignored" 
    def __init__(self, name): 
     self.name = name 
    # rest as before 

現在,當我們創建了一個Example,我們必須指定一個name,每個實例都有自己的name。無論何時查找實例的.name,Python都將忽略類屬性Example.name,因爲將首先找到實例的屬性。

最後一條警告:修改(突變)和分配是不同的事情!

在Python中,字符串是不可變的。他們不能被修改。當你這樣做:

a = 'hi ' 
b = a 
a += 'mom' 

不改變原來的「喜」字符串。在Python中這是不可能的。相反,您將創建字符串'hi mom',並導致a停止爲'hi '的名稱,而是開始爲'hi mom'而不是名稱。我們還爲'hi '創建了名稱b,並且在重新應用a名稱後,b仍然是'hi '的名稱,因爲'hi '仍然存在並且未被更改。

但名單可以更改:

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

現在b爲[1,2,3,4]爲好,因爲我們同樣的事情做b的名稱a命名,然後我們改變那個東西。我們沒有爲a創建一個新名單,因爲Python只是簡單地將+=視爲列表。

這對於對象很重要,因爲如果您有一個列表作爲類屬性,並且使用實例修改列表,那麼在所有其他實例中將會「看到」更改。這是因爲(a)數據實際上是類對象的一部分,而不是任何實例對象; (b)因爲你修改了列表而沒有做簡單的賦值,所以你沒有創建一個隱藏類屬性的新實例屬性。

+8

這就是我們稱之爲['標識符'](http://docs.python.org/2/reference/lexical_analysis.html#identifiers)的原因。 :-) –

+0

@Karl_Knechtel在最後的字符串示例中,如果我們從未將其命名爲'b',會發生什麼情況?這是內存泄漏嗎? – heretoinfinity

+1

@heretoinfinity:no; Python使用垃圾收集來釋放無法訪問的對象 –

1

變量有範圍,所以是適當的變量是特定於您的函數。你並不總是必須明確他們的定義;通常你可以使用它們。只有當你想做一些特定於變量類型的事情時,比如追加列表,你是否需要在開始使用它們之前定義它們。這是典型的例子。

list = [] 
for i in stuff: 
    list.append(i) 

順便說一下,這不是一個真正的設置列表的好方法。最好是說:

list = [i for i in stuff] # list comprehension 

......但我離題了。

您的其他問題。 自定義對象應該是一個類本身。

class CustomObject(): # always capitalize the class name...this is not syntax, just style. 
    pass 
customObj = CustomObject() 
18

有沒有必要在Python中聲明新的變量。如果我們正在討論函數或模塊中的變量,則不需要聲明。只需將值分配給您需要的名稱即可:mymagic = "Magic"。 Python中的變量可以保存任何類型的值,並且不能限制它。

雖然您的問題具體詢問類,對象和實例變量。創建實例變量的慣用方法是在__init__方法和其他地方 - 而你可能創建新的實例變量在其他方法,甚至在不相關的代碼,這只是一個壞主意。它會讓你的代碼難以推理或維護。

因此,例如:

class Thing(object): 

    def __init__(self, magic): 
     self.magic = magic 

容易。現在,這個類的實例有一個magic屬性:

thingo = Thing("More magic") 
# thingo.magic is now "More magic" 

創建本身就導致不同的行爲完全的類的命名空間的變量。它在功能上是不同的,如果你有特定的理由,你應該只做它。例如:

class Thing(object): 

    magic = "Magic" 

    def __init__(self): 
     pass 

現在試試:

thingo = Thing() 
Thing.magic = 1 
# thingo.magic is now 1 

或者:

class Thing(object): 

    magic = ["More", "magic"] 

    def __init__(self): 
     pass 

thing1 = Thing() 
thing2 = Thing() 
thing1.magic.append("here") 
# thing1.magic AND thing2.magic is now ["More", "magic", "here"] 

這是因爲類本身的命名空間是從它創建的對象的命名空間不同。我會留給你去研究一下。

這是一個習慣用語,是(a)在你的__init__方法中初始化對象屬性,(b)根據需要記錄你的類的行爲。你不需要爲你寫過的所有東西寫出完整的獅身人面像級文檔的麻煩,但至少對你或其他人可能需要的任何細節進行評論。

2

對於作用域的目的,我使用 -

custom_object =無