2010-01-04 103 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))]