2012-09-13 50 views
30

我剛剛學習Python,我來自C背景,所以請讓我知道如果我之間有任何混淆/混淆。Python類成員

假設我有下面的類:

class Node(object): 
    def __init__(self, element): 
     self.element = element 
     self.left = self.right = None 

    @classmethod 
    def tree(cls, element, left, right): 
     node = cls(element) 
     node.left = left 
     node.right = right 
     return node 

這是一個名爲Node類,即重載的構造,能夠在需要時處理不同的參數。

是什麼在僅__init__限定self.element之間的差(如上所示),而不是執行以下操作:

class Node(object): 
    element, left, right = None 
    def __init__(self, element): 
     self.element = element 
     self.left = self.right = None 

是不是在__init__相同類的element可變self.element定義?難道那只是將elementNone改爲element值傳入__init__

回答

56

一個是類屬性,而另一個是實例屬性。它們是不同的,但它們彼此緊密相關,使得它們有時看起來相同。

它與Python的方式做查找屬性。有一個層次結構。在簡單的情況下,它可能是這樣的:

instance -> Subclass -> Superclass -> object (built-in type) 

當你對instance像這樣的屬性...

`instance.val` 

...什麼是真正發生的是,第一,Python的長相在實例本身中爲val。然後,如果它沒有找到val,它在它的類中看起來是Subclass。然後,如果它沒有找到val,則它在SubclassSuperclass的父級中查找。這意味着,當你這樣做......

>>> class Foo(): 
    foovar = 10 
    def __init__(self, val): 
     self.selfvar = val 

...的Foo份額foovar所有實例,而是有自己獨特的selfvar秒。下面是如何工作的一個簡單,具體的例子:

>>> f = Foo(5) 
>>> f.foovar 
10 
>>> Foo.foovar 
10 

如果我們不碰foovar,這對雙方fFoo相同。但是,如果我們改變f.foovar ...

>>> f.foovar = 5 
>>> f.foovar 
5 
>>> Foo.foovar 
10 

...我們添加一個實例屬性,它有效地掩蓋的Foo.foovar值。現在,如果我們直接改變Foo.foovar,它不會影響我們的foo例如:

>>> Foo.foovar = 7 
>>> f.foovar 
5 

但它確實影響了新foo實例:

>>> Foo(5).foovar 
7 

而且記住,可變對象添加另一層間接(如mgilson提醒我)。在這裏,f.foovar指的是同一個對象Foo.foovar,所以當你改變了對象,所做的更改傳播了層次:

>>> Foo.foovar = [1] 
>>> f = Foo(5) 
>>> f.foovar[0] = 99 
>>> Foo.foovar 
[99] 
+2

出色答卷!在「Foo.foovar」是一個可變對象(例如'list')的情況下,這些事情會變得更加有趣。 – mgilson

2

self.element構造內部是一個實例變量(如果一個節點對象修改其值它只改變此對象),其中所述一個在所述第二版本是一個類變量(因此,如果一個節點對象修改它的值它將改變所有節點對象)。

C++中的類比是不靜態與你的類的靜態成員變量。

0

的重要組成部分,是self參數__init__。實際上,在的任何實例方法中,這將是第一個參數。這是通過設計完成的;在Python中,唯一一次實際訪問實例的時間是在方法調用期間,並且顯式地使用self參數顯示。

當你是一個class定義內,你沒有任何實例還,所以你實際上是修改的類本身。因此,如果您在類級別定義屬性,那麼它們確實成爲類屬性,而不是實例。

它比作C(++),你很可能說「類」這些語言的基本藍圖,他們代表的對象。 「這些對象應具有foobar屬性,此外還有以下方法。」然而,在Python中,類本身就是對象,它們的主要優點是它們可以爲自己創建副本(實例),這也碰巧使用類的方法。所以,它更像是「你將擁有foobar作爲類屬性,此外,還將使用以下方法創建實例。」

所以,而不是一個藍圖,這是更多的一步一步的方法。

0

self.element init是一個實例變量,您可以通過鍵入self.element來獲取/設置它的任何其他成員函數。在類中聲明的元素是類變量,您可以通過鍵入Node.element來獲取/設置它。

10

在Python中有可能有類變量和同名的實例變量。它們分別位於內存中,並且訪問方式不同。

在您的代碼:

class Node(object): 
    element, left, right = None 
    def __init__(self, element): 
     self.element = element 
     self.left = self.right = None 

第一組變量(__init__功能外)被稱爲類變量。這些可以隨後使用Node.element等進行訪問,等等。這些相當於C++中的靜態成員變量,它們由類的所有實例共享。

第二組變量(在__init__函數內)被稱爲實例變量。這些可通過self對象訪問,例如, self.element,或者通過實例名稱例如myNode.element以外的班級。

請務必注意,您必須使用self.variableNode.variable表單才能從成員函數中訪問其中的任意一個。只要訪問variable就會嘗試訪問名爲variable的本地變量。

0

你試圖用一個類來訪問變量它考慮只

cls.__dict__ 

但是當你試圖用實例來訪問變量它首先

self.__dict__ 

如果找到則返回或如果找不到,那麼它也看起來在

cls.__dict__ 

這裏cls是類

class Test: 
    temp_1=10 
    temp_2=20 

    def __init__(self): 
     self.test_1=10 
     self.test_2=20 

    @classmethod 
    def c_test(cls): 
     pass 

    def t_method(self): 
     pass 


print Test.__dict__ 
print Test().__dict__ 

輸出

{'c_test': <classmethod object at 0x7fede8f35a60>, '__module__': '__main__', 't_method': <function t_method at 0x7fede8f336e0>, 'temp_1': 10, '__doc__': None, '__init__': <function __init__ at 0x7fede8f335f0>, 'temp_2': 20} 

{'test_2': 20, 'test_1': 10} 

對於細節class special attribute