【问题标题】:Checking for type() and changing if str() or int()检查 type() 并更改 str() 或 int()
【发布时间】:2015-11-14 13:00:49
【问题描述】:

为清楚起见编辑:

我正在尝试解决导致错误的categoryNone 的问题: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 后的 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)

【问题讨论】:

  • 如果type(x) == unicode怎么办?
  • x = category。你是说x=category_name 吗?
  • @Two-BitAlchemist 而不是字符串可能更好:isinstance(x, basestring)
  • @MosheRabaev 我遇到的问题是,当我创建一个元素的实例时,如果该对象不是一个对象,我会收到一个 Traceback 错误,表明 Category 是 NONE。通过测试和转换,我可以避免这个错误。我不认为我完全理解你的评论。
  • category 来自哪里,最好在某个地方定义它?

标签: python python-2.7 oop inheritance sqlalchemy


【解决方案1】:

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

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

sa 等于函数api.create_category() 的返回值。我将假设这个函数没有定义的返回值,这将导致sa 成为None。您在该测试的下一行真正调用的是 api.create_element('gathering information', 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 所期望的对象,会发生什么?我将在这里停止这个答案,因为有几个可用的选项可以解决这个问题。

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

【讨论】:

  • 意思是问题区域确实在默认情况下。如果您知道category 应该是一个对象,那么我建议的要点是为category 创建一个默认值(在本例中为对象)。另外,您的两个测试用例中的哪一个失败了?我会在评论中询问您的问题,但我没有足够的声誉。
  • 我实际上是在我的表中返回一个值:class Element(Base): #code #category_id = Column(Integer, ForeignKey('categories.category_id')) category = relationship('CategoryElementLink', backref='elements') def __init__(self, element_text, category): self.element_text = element_text self.category = category def __repr__(self): return "&lt;Element(element_text='%s', category='%s')&gt;" % (self.element_text, self.category)
  • 你的元素类可以返回一个值,但是api.create_category()呢?
  • api.create_category(..)api.create_element(..) 类似,但该表返回 category_name:class Category(Base): __tablename__ = 'categories' category_id = Column(Integer, primary_key= True) category_name = Column(String(2000)) def __init__(self, category_name): self.category_name = category_name def __repr__(self): return "&lt;Category(category_name='%s')&gt;" % (self.category_name)
  • 这里还有一些我不明白的地方。示例:如果您的函数的第一步正在重命名其参数之一 (category = category_name),为什么不在函数定义中重命名参数?而且,这些类型测试仍然不正确。 isinstance(x, basestring)type(x) == str 好很多。同样,我想知道您是否还打算排除floatsints。如果是这样的话,如果有人通过decimal.Decimal 会发生什么?最后,这里还是没有is not None测试。
【解决方案2】:

我知道,正如我对其他答案的反对意见所表明的那样,这与您的问题有些相干。尽管如此,我认为您在检查类型的方式上犯了一个错误(您报告至少已部分纠正)。我将把这个程序留在这里供您考虑:

"""
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,而您基本上不想捕捉到它。

【讨论】:

  • 这是检查所有表/实体的绝佳测试方法。它是明确的 None ... 让 *args 对表运行可能会很好。但我会允许字符串并转换为对象。
猜你喜欢
  • 2011-07-21
  • 1970-01-01
  • 2013-07-29
  • 1970-01-01
  • 2013-06-02
  • 2011-02-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多