在类中查找属性的类型

时间:2010-01-04 14:09:05

标签: python google-app-engine

我想确定一个类中属性的类型。我使用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类型。我试图让问题尽可能简单,但也许这些信息会对某人的回答产生影响。(?)

8 个答案:

答案 0 :(得分: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)

答案 1 :(得分:1)

您似乎误解了Python(语言)的设计方式。属性没有先验类型(语言是动态类型的),因此在大多数情况下,在设置属性时尝试明确强制属性没什么意义。

答案 2 :(得分: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)

答案 3 :(得分:0)

您可以使用type(a.v)进行检查,但如果它没有默认值,则可以是None或undefined。

>> 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内置工具在这里并不完全有用。在这种情况下我不会依赖它们。例如,xmlrpc libs提供了更有用的方法。

如果您只知道名称,请在上面的代码中使用a.getattr('v')而不是a.v.

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

或使用外部建议的实例,它也是一样的。

答案 4 :(得分: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)

几个旁注:

# why don't you just take two parameters? 1) the object, 2) a dict with 
# property-value pairs?

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)

        # here you are branching on 'value', just to populate 
        # property 'k' with whah might have been 'value' before ..
        # it's nothing serious, though, just a bit too much to read

        if value:
            setattr(object_to_populate, k, value)
        else:
            setattr(object_to_populate, k, None)

        # you could simply write:
        # setattr(object_to_populate, k, value)

进一步阅读:

答案 5 :(得分:0)

通常,Python类(或其实例)不携带任何给定属性“期望”的类型的信息,因为它没有这样的“期望”。

当您需要对这些元数据进行编码时,您可以使用现有的第三方扩展程序(如Enthought的Traits - 在Traits中,而不是“自己动手”),以及其他功能,您将获得:

  

验证:特质属性的类型   明确声明。类型是   在代码中很明显,只有值   满足程序员指定的集合   标准(即特征)   定义)可以分配给它   属性。请注意默认值   不必满足为之定义的标准   分配价值。

答案 6 :(得分:0)

由于显式类型检查是非pythonic的,因此请考虑将值包装在int()中。然后,如果值(无论是什么)可以被强制转换为int,那么它就是。{如果无法将其强制转换为int,则无论如何都需要抛出错误(它会自动执行)。

这是“在你跳跃之前看”和“请求宽恕比要求许可更容易”之间的根本区别的一个例子。 Python不是一种“在你跳跃之前”的语言,它是一种“请求宽恕而不是请求许可”的语言。 :)

答案 7 :(得分:0)

您可以通过结合使用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))] 方法来获取类的属性名称和类型:

COUNTER