检查type()并更改str()或int()

时间:2015-08-20 18:34:39

标签: python python-2.7 oop inheritance sqlalchemy

为清晰起见,已编辑:

我正在尝试解决导致错误的category None问题:TypeError: Incompatible collection type: None is not list-like

我正在尝试检查在创建此对象category的实例时是否有字符串,int或对象,以便通过表中的ORM传递它。我一直遇到一个错误(如上所示),所以我想创建一个检查,让对象通过,如果它们是对象。

我一直在重做的代码,但并没有完全按照我希望的那样做。任何帮助/解释都将非常感激!

这里的课程

class BaseAPI(object):
    def create_element(self, element_text, category): # OBJ
        new_element = Element(element_text, category)
        self.session.add(new_element)
        self.session.commit()
        print(element_text)


 class ConvenienceAPI(BaseAPI):
    def create_element(self, element_text, category_name):
        category = category_name
        if type(category) == str:
            category = self.retrieve_category(category_name)
        elif type(category) == int:
            print('Sorry integers not accepted')
        else:
            return super(ConvenienceAPI, self).create_element(element_text, category)

在test.py文件中,我创建了元素和类别的两个实例:

api = ConvenienceAPI()
    sa = api.create_category('Situation Awareness')
    api.create_element('gathering information', sa)

    api.create_category('Leadership')
    api.create_element('gathering information', 'Leadership')
运行test.py后

ADDED TRACEBACK ERROR:

Traceback (most recent call last):
  File "/usr/local/lib/python2.7/site-packages/nose/case.py", line 197, in runTest
    self.test(*self.arg)
  File "/Users/ack/code/venv/NotssDB/notssdb/test/test.py", line 41, in test1
    sa3 = api.create_element('projecting and anticipating future state', sa)
  File "/Users/ack/code/venv/NotssDB/notssdb/api/convenience.py", line 22, in create_element
    return super(ConvenienceAPI, self).create_element(element_text, category)
  File "/Users/ack/code/venv/NotssDB/notssdb/api/object.py", line 192, in create_element
    new_element = Element(element_text, category)
  File "<string>", line 4, in __init__
  File "/usr/local/lib/python2.7/site-packages/sqlalchemy/orm/state.py", line 306, in _initialize_instance
    manager.dispatch.init_failure(self, args, kwargs)
  File "/usr/local/lib/python2.7/site-packages/sqlalchemy/util/langhelpers.py", line 60, in __exit__
    compat.reraise(exc_type, exc_value, exc_tb)
  File "/usr/local/lib/python2.7/site-packages/sqlalchemy/orm/state.py", line 303, in _initialize_instance
    return manager.original_init(*mixed[1:], **kwargs)
  File "/Users/ack/code/venv/NotssDB/notssdb/model/base.py", line 180, in __init__
    self.category = category
  File "/usr/local/lib/python2.7/site-packages/sqlalchemy/orm/attributes.py", line 224, in __set__
    instance_dict(instance), value, None)
  File "/usr/local/lib/python2.7/site-packages/sqlalchemy/orm/attributes.py", line 1022, in set
    lambda adapter, i: adapter.adapt_like_to_iterable(i))
  File "/usr/local/lib/python2.7/site-packages/sqlalchemy/orm/attributes.py", line 1038, in _set_iterable
    new_values = list(adapter(new_collection, iterable))
  File "/usr/local/lib/python2.7/site-packages/sqlalchemy/orm/attributes.py", line 1022, in <lambda>
    lambda adapter, i: adapter.adapt_like_to_iterable(i))
  File "/usr/local/lib/python2.7/site-packages/sqlalchemy/orm/collections.py", line 636, in adapt_like_to_iterable
    given, wanted))
TypeError: Incompatible collection type: None is not list-like

-------------------- >> begin captured stdout << ---------------------
--start db Session--
Situation Awareness
(u'Leadership', 1)

2 个答案:

答案 0 :(得分:1)

在test.py的第一个测试用例中:

sa = api.create_category('Situation Awareness')
api.create_element('gathering information', sa)

sa等于函数api.create_category()的返回值。我将假设此函数没有定义的返回值,这将导致saNone。你在该测试的下一行真正调用的是api.create_element('gathering information', None),当你期望可迭代的东西时,会导致意外类型的'None'被传递给sqlalchemy。

简单解决方案

  • 不要将create_category()的结果分配给变量,因为没有任何变量,而是以与领导示例相同的方式使用API​​。基本上不要做与sa = api.create_category('Situation Awareness')
  • 类似的任何事情
  • 编辑create_category()函数以返回其输入类别。例如,create_category("Situation Awareness")应返回“情境意识”,而不是None

问题的根源

类型安全。你假设传递的变量类型不一定是真的。特别要看:

 class ConvenienceAPI(BaseAPI):
    def create_element(self, element_text, category_name):
        category = category_name
        if type(category) == str:
            category = self.retrieve_category(category_name)
        elif type(category) == int:
            print('Sorry integers not accepted')
        else:
            return super(ConvenienceAPI, self).create_element(element_text, category)

假设在else:子句中,category是某种类型的对象。但正如您所看到的,只要category不是str,int或对象,您就会立即得到错误。而这仍然留下了BaseAPI期望的对象类型的问题。 可能的解决方案:

class ConvenienceAPI(BaseAPI):
    def create_element(self, element_text, category_name):
        category = category_name

        # if category is None, then this will fail
        # and print out the type (since None evaluates to False).
        if category:
            if isinstance(category, basestring):
                category = self.retrieve_category(category_name)
            # Is int and float the only numeric types that can happen?
            elif isinstance(category, int) or isinstance(float) : 
                print('Sorry integers not accepted')
            else:
                # Danger Zone!!
                return super(ConvenienceAPI, self).create_element(element_text, category)
        else:
            print('Sorry, category is type %s' % str(type(category)))

请注意,我们正在检查basestring而非str。这是因为category可能是unicode,它是有效文本,但它不是strstrunicode都是basestring的子类。有关详细信息,请阅读https://stackoverflow.com/a/152596/5249060

即使您采取了此修复措施,如果类别不是strint,那么危险区域会发生什么?如果它是一个对象会发生什么,但不是BaseAPI期望的那种?我将在这里停止这个答案,因为有几个选项可以解决这个问题。

为了澄清我之前的一些编辑和评论,您帮助此代码的方法之一是为category创建一个默认对象,如果它不是str,{{1或某种对象,而不是记录错误消息。但是,这实际上取决于您正在处理的是否存在可接受的默认值。

答案 1 :(得分:1)

我知道,正如我对其他答案的赞成表明,这与你的问题有些相关。尽管如此,我认为您检查类型的方式是错误的(您报告的类型至少已部分更正)。我将把这个程序留在这里供你考虑:

"""
Exploration of type testing in Python.
"""

def type_test(x):
    """
    Reject strings, numbers, and None. Other objects pass through.
    """
    if x is None:
        return 'Must pass an object: None given.'

    try:
        float(x)
    except ValueError:
        if isinstance(x, basestring):
            return 'String types are not accepted.'
        else:
            return x
    else:
        return 'Numeric types are not accepted.'


def bad_string_test(x):
    """
    Only testing for 'str' type lets unicode fall through.
    """
    if isinstance(x, str) or type(x) == str or type(x) is str:
        return 'Strings are not accepted.'

    return x


def bad_numeric_test(x):
    """
    Only testing for 'int' or even 'int' and 'float' fails
    for numeric types like decimal.Decimal
    """
    if isinstance(x, int) or type(x) == int or type(x) is int:
        return 'Integers are not accepted.'
    elif isinstance(x, float) or type(x) == float or type(x) is float:
        return 'Floats are not accepted.'

    return x


if __name__ == '__main__':
    from decimal import Decimal
    print "bad_string_test('Hello') ->", bad_string_test('Hello')
    print "bad_string_test(u'Hello') ->", bad_string_test(u'Hello')
    print "type_test('Hello') ->", type_test('Hello')
    print "type_test(u'Hello') ->", type_test(u'Hello')
    print "bad_numeric_test(1) ->", bad_numeric_test(1)
    print "bad_numeric_test(1.0) ->", bad_numeric_test(1.0)
    print "bad_numeric_test(Decimal('1.0')) ->",\
            bad_numeric_test(Decimal('1.0'))
    print "type_test(1) ->", type_test(1)
    print "type_test(1.0) ->", type_test(1.0)
    print "type_test(Decimal('1.0')) ->", type_test(Decimal('1.0'))
    print "type_test(None) ->", type_test(None)

输出:

bad_string_test('Hello') -> Strings are not accepted.
bad_string_test(u'Hello') -> Hello
type_test('Hello') -> String types are not accepted.
type_test(u'Hello') -> String types are not accepted.
bad_numeric_test(1) -> Integers are not accepted.
bad_numeric_test(1.0) -> Floats are not accepted.
bad_numeric_test(Decimal('1.0')) -> 1.0
type_test(1) -> Numeric types are not accepted.
type_test(1.0) -> Numeric types are not accepted.
type_test(Decimal('1.0')) -> Numeric types are not accepted.
type_test(None) -> Must pass an object: None given.

需要注意的事项:

  • 我们不是试图枚举所有数字类型,而是尝试使用强制转换来浮动,将失败解释为对象是“数字类型”。这会投出更广泛的网络,并且还会选择decimal.Decimal这样的内容,我认为您也希望排除它。

  • type_test包含明确的None测试。这是必需的,因为float(None)会引发TypeError,您基本上不想抓住它。