2012-05-03 116 views
0

類可以通過其__str__方法充當字符串,或通過其__call__方法作爲函數來使用。它可以充當一個列表或一個元組嗎?Python:一個類實例可以評估爲任何類型嗎?

class A (object): 
    def __???__ (self): 
     return (1, 2, 3) 

>>> a = A() 
>>> a * 3 
(1, 2, 3, 1, 2, 3, 1, 2, 3) 

編輯...

這裏有一個更好的例子,以幫助澄清以上。

class Vector (object): 
    def __init__ (self): 
     self.vec = (1,2,3) 
    def __???__ (self): 
     # something like __repr__; non-string 
     return self.vec 

class Widget (object): 
    def __init__ (self): 
     self.vector = Vector() 

>>> w = Widget() 
>>> w.vector 
(1, 2, 3) # not a string representation (at least, before being repr'd here) 

基本上,我想是這樣__repr__不返回一個字符串,而是返回一個元組(或列表)時,我簡單地調用指向Vector實例的名字,但我不希望失去實例中的其他功能,如訪問其他屬性和方法。我也不希望使用w.vector.vec來獲取數據。我想讓矢量像w的元組屬性一樣工作,同時仍然可以執行諸如w.vector.whatever()之類的操作,或者覆蓋__mul__,以便通過w.vector * 5來縮放矢量。可能?

+1

當您調用'__str__'創建並返回一個NEW字符串對象時,該類不會作爲字符串。我真的不知道你在做什麼... –

+2

子類'元組'。 –

回答

3

取決於你的目標是什麼,你可以創建一個從內置的類繼承像listtuple類:

>>> class A(tuple): 
...  def speak(self): 
...   print "Bark!" 
... 
>>> a = A((1,2,3)) # extra parens needed to distinguish single tuple arg from 3 scalar args 
>>> a * 3 
(1, 2, 3, 1, 2, 3, 1, 2, 3) 
>>> a.speak() 
Bark! 

鑑於你的Vector用例,子類化元組可能很有用。

import math 

class Vector(tuple): 
    def magnitude(self): 
     return math.sqrt(self[0]*self[0]+self[1]*self[1]+self[2]*self[2]) 
+0

我打算做一個測試,但我認爲這是答案。我基本上想要一個元組,我可以用/來做其他事情,比如添加屬性和方法,並訪問它們,但是如果我只是在任何地方使用* it *,我希望它成爲一個元組。 –

+0

你最大的目標是什麼?你可能想要Panda3D或其他東西。 –

+0

這很有趣。我們實際上在我的公司使用熊貓。我的目標是能夠像矢量那樣具有某些類實例的類常量屬性,它可以非常容易地作爲實例屬性(iewvector)訪問,簡單地縮放(例如'w.vector * 3'縮放每個組件) ,並用自定義方法(例如wvector.inWorld())以許多其他方式進行操作。我也希望這些屬性能夠提供關於他們自己的更多信息(例如w.vector.property)。 –

0

當您撥打電話str時,該班級不會充當字符串。它創建並返回一個新的字符串對象。基本上,當你在對象上調用str(something),這到底發生了什麼:

a = str(someObject) 

a = someObject.__str__() 

所以str功能基本上可以認爲是這樣:

def str(variable): 
    return variable.__str__() 

,當你調用list()也是如此,tuple(),set()等。如果我想你問的是正確的:

tuple()list()set()所有調用類的__iter__()方法,所以你想要做的是:

class MyClass(object): 
    ... 
    def __iter__(self): 
     ... 
     return myIterable 
+0

我明白它是創建並返回一個字符串,但對我來說,它適合作爲字符串的類的定義。我不知道它會如何工作。 \ _ \ _ iter \ _ \ _是迄今爲止最接近我的答案,但它仍然需要額外的工作,如調用它。也許我現在還沒有把這個問題定義得很好。 –

+1

@GaryFixler:你不必調用'__iter __()'。使用'A'的實例,任何需要可迭代類型的地方都會隱式調用__iter __()。例如,A:中的項目的循環'是用於'A .__ iter __():'中的項目的語法糖。所以如果你定義了'__iter __()',那足以能夠將'A'的實例轉換爲列表,或者像列表一樣使用它們(儘管如果你想實現隨機訪問,你必須實現__setitem __()和'__getitem __()'。) –

+0

@GaryFixler:它不需要額外的工作。 'list(myObject)'隱式調用myObject .__ iter __(),就像任何需要迭代器的表達式一樣。 –

2

,具體行爲在你的例子中(A*3給出了A中數據的三個連接副本),你想實現__mul__()操作符。

例如,這些是等價的:

>>> a = [1,2,3] 
>>> a*3 
[1, 2, 3, 1, 2, 3, 1, 2, 3] 
>>> a.__mul__(3) 
[1, 2, 3, 1, 2, 3, 1, 2, 3] 
>>> 

更一般地,如果你想實現一個序列類型,你必須實現所有operations defined for sequence types的。你必須定義 -

  • 什麼A[3]手段(__getitem__()__setitem__()
  • 什麼A[1:10]手段(__getslice__()
  • 什麼for item in A:手段(__iter__()

等。

這裏有list已定義的方法的完整列表:

>>> pprint.pprint(dict(list.__dict__)) 
{'__add__': <slot wrapper '__add__' of 'list' objects>, 
'__contains__': <slot wrapper '__contains__' of 'list' objects>, 
'__delitem__': <slot wrapper '__delitem__' of 'list' objects>, 
'__delslice__': <slot wrapper '__delslice__' of 'list' objects>, 
'__doc__': "list() -> new empty list\nlist(iterable) -> new list initialized from iterable's items", 
'__eq__': <slot wrapper '__eq__' of 'list' objects>, 
'__ge__': <slot wrapper '__ge__' of 'list' objects>, 
'__getattribute__': <slot wrapper '__getattribute__' of 'list' objects>, 
'__getitem__': <method '__getitem__' of 'list' objects>, 
'__getslice__': <slot wrapper '__getslice__' of 'list' objects>, 
'__gt__': <slot wrapper '__gt__' of 'list' objects>, 
'__hash__': None, 
'__iadd__': <slot wrapper '__iadd__' of 'list' objects>, 
'__imul__': <slot wrapper '__imul__' of 'list' objects>, 
'__init__': <slot wrapper '__init__' of 'list' objects>, 
'__iter__': <slot wrapper '__iter__' of 'list' objects>, 
'__le__': <slot wrapper '__le__' of 'list' objects>, 
'__len__': <slot wrapper '__len__' of 'list' objects>, 
'__lt__': <slot wrapper '__lt__' of 'list' objects>, 
'__mul__': <slot wrapper '__mul__' of 'list' objects>, 
'__ne__': <slot wrapper '__ne__' of 'list' objects>, 
'__new__': <built-in method __new__ of type object at 0x1E1DACA8>, 
'__repr__': <slot wrapper '__repr__' of 'list' objects>, 
'__reversed__': <method '__reversed__' of 'list' objects>, 
'__rmul__': <slot wrapper '__rmul__' of 'list' objects>, 
'__setitem__': <slot wrapper '__setitem__' of 'list' objects>, 
'__setslice__': <slot wrapper '__setslice__' of 'list' objects>, 
'__sizeof__': <method '__sizeof__' of 'list' objects>, 
'append': <method 'append' of 'list' objects>, 
'count': <method 'count' of 'list' objects>, 
'extend': <method 'extend' of 'list' objects>, 
'index': <method 'index' of 'list' objects>, 
'insert': <method 'insert' of 'list' objects>, 
'pop': <method 'pop' of 'list' objects>, 
'remove': <method 'remove' of 'list' objects>, 
'reverse': <method 'reverse' of 'list' objects>, 
'sort': <method 'sort' of 'list' objects>} 
+0

我瞭解\ _ \ _ mul \ _ \ _操作符,並將爲此實現它。然而,在我的例子中,我只是想表明它確實返回了一個元組,而不是元組的字符串表示。它獲得了一個類的簡單用法,就像一個類型一樣,同時仍然保留着其他能力,比如調用我感興趣的方法。也許我可以以某種方式繼承元組嗎? –

+1

@GaryFixler:如果您希望能夠將對象轉換爲元組,您需要使對象「可迭代」。 (記住'TypeError:'A'對象不是可迭代的錯誤?這就是它所談論的。)實現'__iter __()'應該足以做到這一點。然後'元組(A)'擴展爲'元組(A____ iter __())',應該做你想要的。同樣,通過'A'的循環將起作用,列表解析將起作用,等等。 –

+1

@ Li-aungYip注意你不需要實現'__setitem__'作爲序列協議的一部分(除非你明確地希望它是可變的,在這種情況下,你想實現'__delitem__','insert'和其他),'__ {get,set,del} slice__'已被棄用了一段時間,以支持將'slice'對象傳遞給'__ {get,set,del} item__'。一個類實現完整序列協議的最好和最簡單的方法是從'collections.Sequence'(或3.3中的'collections.abc.Sequence')繼承。 (當然,除非從現有的序列類型繼承)。 – lvc

相關問題