2017-06-12 62 views
24

在Python 3.5,說我有:有沒有辦法在沒有實例化對象的情況下列出某個類的屬性?

class Foo: 
    def __init__(self, bar, barbar): 
     self.bar = bar 
     self.barbar = barbar 

我想從班級列表["bar", "barbar"]

我知道我可以做:

foo = Foo(1, 2) 
foo.__dict__.keys() 

有沒有辦法讓["bar", "barbar"]沒有實例化對象?

+1

可能重複的[有沒有辦法獲得沒有肌酸的類實例屬性g類實例?](https://stackoverflow.com/questions/30128924/is-there-any-way-to-get-class-instance-attributes-without-creating-class-instanc) – idjaw

+1

'Foo .__ init__。 __code __。co_varnames' –

+3

@AvihooMamka這隻會給你傳遞給方法的參數嗎?如果你在'__init__'中創建了一個不依賴於傳遞給'__init__'的參數的動態屬性? – idjaw

回答

26

否,因爲屬性是動態的(所謂的實例屬性)。考慮下面,

class Foo: 
    def __init__(self): 
     self.bar = 1 

    def twice(self): 
     self.barbar = 2 

f = Foo() 
print(list(f.__dict__.keys())) 
f.twice() 
print(list(f.__dict__.keys())) 

在第一次印刷,只有f.bar設置,所以這是打印屬性鍵當這樣顯示的唯一屬性。但是在撥打f.twice()後,您將創建一個新的屬性爲f,並且現在打印它顯示barbarbar

+2

您可能想要考慮'__slots__'的類可能是一個例外。 – Paul

9

警告 - 以下不總是提供100%正確的數據萬無一失。如果最終在__init__中出現類似self.y = int(1)的內容,則最終將在您的屬性集合中包含int,這不屬於您的目標通緝結果。此外,如果您碰巧在您的代碼的某處添加了動態屬性,例如Foo.some_attr = 'pork',那麼您將永遠也看不到這一點。注意你在代碼的哪個部分檢查了什麼,並理解你爲什麼在結果中包含和不包含這些內容。有可能是其他「破損」,將不會給你完全100%的期望所有屬性與此類別相關聯,但是,但是,下面應該給你東西,你可能正在尋找。

不過,我強烈建議你把這裏的其他答案的建議,這是標記,解釋爲什麼你不能/不應該這樣做重複的。

以下是解決一個形式,你可以嘗試更動:

我將擴大在inspect答案。

但是,我在生產已經完成的代碼中做了類似這樣的事情的有效性的問題(並且可能會提出建議)。爲了調查的目的,當然,要把自己擊倒。

通過使用inspect模塊(如其他解答之一所示),您可以使用getmembers方法,然後您可以遍歷這些屬性並檢查想要調查的適當數據。

例如,你都在質疑在__init__

因此動態屬性,我們可以利用這個例子來說明:

from inspect import getmembers 


class Foo: 
    def __init__(self, x): 
     self.x = x 
     self.y = 1 
     self.z = 'chicken' 


members = getmembers(Foo) 

for member in members: 
    if '__init__' in member: 
     print(member[1].__code__.co_names) 

你的輸出將是一個元組:

('x', 'y', 'z') 

最終,當您檢查類Foo以獲取其成員時,您可以在迭代eac時進一步調查屬性h成員。每個成員都有屬性可以進一步檢查,依此類推。對於這個特定的例子中,我們側重於__init__檢查__code__(每個文件:表示所述編譯函數體的__code__對象)的屬性,其具有稱爲co_names的屬性如上面運行的輸出指示,其提供構件的元組碼。

-6

正如Lærne所說,函數內部聲明的屬性(如__init__)是動態的。他們實際上不存在直到__init__函數被調用。

但是,有一種方法可以做到你想要的。

您可以創建屬性,像這樣:

class Foo: 
    bar = None 
    barbar = None 

    def __init__(self, bar, barbar): 
     self.bar = bar 
     self.barbar = barbar 

你也可以像這樣訪問那些屬性:

[var for var in vars(Foo).keys() if not var.startswith('__')] 

哪個給出了這樣的結果:

['bar', 'barbar'] 
+1

您的代碼正在檢查** class **屬性,而不是** instance **屬性。 – martineau

+0

@martineau這是在答案(和問題)中提到的。這將是OP完成他們想要完成的任務的一種方式。 –

+2

儘管標題顯示「類的屬性」,但OP的代碼只顯示了在__init __()中創建的兩個實例屬性,然後詢問是否有方法可以在不實例化對象的情況下確定它們,所以我相信您誤解了這個問題。 – martineau

相關問題