2010-01-04 98 views
1

我想確定類中屬性的類型。我使用setattr來設置值,我想檢查預期的類型,以便在調用setattr之前我可以正確地轉換字符串值。在類中查找屬性的類型

你如何在python中做到這一點?

編輯1- 基於答案爲止一些額外的信息:

我只知道我要的類型屬性的名稱,這裏是一些代碼:

def populate_object_properties(values_as_strings, 
           object_to_populate, 
           properties_to_populate): 
    for k in properties_to_populate:   
     value = values_as_strings.get(k) 
     if value: 
      setattr(object_to_populate, k, value) 
     else: 
      setattr(object_to_populate, k, None) 

我希望能夠測試value是我撥打setattr之前的正確類型。

編輯2-我需要驗證類型的原因是,我使用Google AppEngine的db.Model作爲object_to_populate的基本類型,它不喜歡何時將字符串放入int類型。我試圖儘量保持這個問題的簡單性,但也許這段信息會影響人們如何回答。(?)

+1

你爲什麼這樣做?只需設置值。如果任何對象的實際類型與預期的方法不兼容,它將會中斷。爲什麼要在使用鴨子打字的語言中對類型檢查浪費太多處理? – 2010-01-04 15:30:43

+0

我正在使用Google AppEngine的db.model,並且將我的db.model類的屬性強制爲一種類型。所以,如果我嘗試將Int屬性設置爲字符串,它會引發異常。 – mlsteeves 2010-01-04 15:56:54

+1

您可能想要查看db.djangoforms:http://code.google.com/appengine/articles/djangoforms.html – dar 2010-01-05 02:59:49

回答

6

在AppEngine中,每個模型都有一個properties()類方法,該方法返回您在模型中聲明的屬性的字典。你可以用它來檢查你的模型預計每個屬性的類型:

def populate_object_properties(values_as_strings, 
           object_to_populate, 
           properties_to_populate): 
    model_properties = object_to_populate.properties() 
    for k in properties_to_populate:   
     value = values_as_strings.get(k) 
     model_property = model_properties.get(k) 
     if value: 
      if isinstance(model_property, StringProperty): 
       setattr(object_to_populate, k, str(value)) 
      elif isinstance(model_property, IntegerProperty): 
       setattr(object_to_populate, k, int(value)) 
     else: 
      setattr(object_to_populate, k, None) 
0

檢查一個。 __class__,或者可能是isinstance(obj,class)如果你想檢查類型是否如預期。

>>> a = 1 
>>> a.__class__ 
<type 'int'> 
>>> isinstance(a, int) 
True 

更重要的是爲你大概是:

>>> b = "10" 
>>> isinstance(b, str) 
True 
>>> isinstance(b, int) 
False 
>>> int(b) 
10 

如果你唯一的目標是建立一個屬性,如果給定的參數可以表示爲一個整數,你也可以使用類似:

def convert(x): 
    try: 
     return int(x) # Or do something else with it 
    except ValueError, e: 
     print "The value", x, "is not an integer" 
     raise 

convert(123) # => 123 
convert("123") # => 123 
convert("abc") # => ValueError 

的問題有些多餘的文字讓我覺得改變:

value = values_as_strings.get(k) 

try: 
    value = int(values_as_strings.get(k)) 
except ValueError, e: 
    # It's not an int or string with int contents, what to do? 
    raise 

導致:

try: 
    setattr(object_to_populate, k, int(values_as_strings.get(k))) 
except: 
    setattr(object_to_populate, k, None) 
+0

isinstance()似乎是首選的方法,基於庫參考手冊中的註釋爲類型模塊。 – 2010-01-04 14:16:22

+0

我的問題並不像應該那樣清楚,我已經更新了它。 – mlsteeves 2010-01-04 14:23:47

0

可以使用type(a.v)來檢查,但如果它沒有默認值,這可能也爲None或不確定。

>> class A: 
>> v=10 
>> u=None 
>> a=A() 
>> print type(a.v) 
<type 'int'> 
>> print type(a.u) 
<type 'NoneType'> 
>> print type(a.w) 
AttributeError 
>> a.w=20 
>> print type(a.w) 
<type 'int'> 

python內置工具introspecion在這裏並不完全有用。在這種情況下,我不會依賴他們。例如xmlrpc庫提供了更多有用的方法來做到這一點。

如果您只知道名稱,請在上面的代碼中使用a.getattr('v')而不是a.v。

if type(getattr(object_to_populate, k))==type('a'): 
    setattr(object_to_populate, k, value) 

或者按照extraneon的建議使用isinstance,它也是一樣的。

+0

我的問題並不像應該那樣清楚,我已經更新了它。 – mlsteeves 2010-01-04 14:24:23

0

由於python在這種情況下不會進行類型檢查,所以必須手動實現此功能(或使用現有庫;請參閱Alex Martellis答案)。

一種方法:通過isinstance檢查值是否是所需類型的實例。

這裏是你的代碼的修改版本,我會先從...

# 'pdict' is a dictionary of property-value pairs { 'property' : 'value', ... } 
def populate_object_properties(object_to_populate, pdict): 
    for p, v in pdict.items(): 
     setattr(object_to_populate, p, v) 

然後,我們添加了類型檢測,在這個例子中,我們只是要填充的對象與對象的屬性

:相同類型的當前使用的值....

def populate_object_properties(object_to_populate, pdict): 
    for p, v in pdict.items(): 

     current_value = getattr(p, v, None) 
     klass = type(current_value) 

     # allow setting the attribute, when 
     # 
     # - the attribute did not exist before, 
     # - the attribute value was 'None', 
     # - the value to be inserted is of the same type as the current value 

     if not current_value or isinstance(v, klass): 
      setattr(object_to_populate, p, v) 

幾個圖片的標題說明的


延伸閱讀:

1

你似乎誤解的Python(語言)如何設計。屬性沒有先驗類型(語言是動態類型的),因此它在大多數情況下在設置屬性時顯式強制屬性沒什麼意義。

+0

我正在使用Google AppEngine的db.model,並且我的db.model類的屬性被強制執行到一個類型。所以,如果我嘗試將Int屬性設置爲字符串,它會引發異常。 – mlsteeves 2010-01-04 15:55:52

+0

那麼問題是爲什麼你嘗試設置一個Int屬性爲一個字符串?你的應用程序應該知道它接收的是什麼類型(例如來自用戶),以及它應該轉換爲什麼類型,所以轉換很簡單(例如'y = int(x)',如果你想做一個字符串轉換-int轉換)。 – 2010-01-04 16:39:36

+0

我正在使用一個函數,以便我可以將請求對象,db.model對象以及我希望從請求對象移動到db.model中的屬性列表傳入。這種方式我可以從任何Web處理程序調用它,使用任何db.model,只需更改屬性列表,並且我認爲它會減少大量的複製和粘貼代碼。所以我需要在運行時弄清楚我正在處理什麼類型,並從請求對象中轉換字符串。 – mlsteeves 2010-01-04 23:16:41

0

通常,Python類(或其實例)不攜帶有關它「期望」任何給定屬性具有的類型的信息,因爲它沒有這種「期望」。

當你需要編碼這種元數據,而不是「滾你自己」,您可以使用現有的第三方擴展一樣Enthought的Traits - 在性狀,除其他功能,您可以:

驗證:顯式聲明特徵屬性的類型 。類型爲代碼中明顯的 ,並且只有符合程序員指定的標準集合 的值 (即,特性 定義)可以被分配給該屬性 屬性。請注意,默認值 不需要符合 賦值的標準。

0

由於顯式類型檢查是非pythonic,可以考慮將值包裝在int()中。然後,如果價值(不管它是什麼)可以強制到int,它將會是。如果它不能被強制轉換成int,那麼你需要拋出一個錯誤(它會自動執行)。

這是「看你跳躍之前」和「請求寬恕比請求允許更容易」之間的根本區別的一個例子。 Python不是「看你跳躍式」語言,而是「請求寬恕比請求許可更容易」的語言。 :)

0

您可以通過使用dir()eval()type()相結合的方法這樣得到的一類屬性的名稱和類型:

def GetFieldNamesAndTypes(self): 
    attributes = dir(self) 
    typenames = [eval("type(self." + dir(self)[i] + ").__name__") for i in range(len(dir(self)))]  
    return [attributes[i] + ":" + typenames[i] for i in range(len(attributes))]