【问题标题】:python generator in recursive function递归函数中的python生成器
【发布时间】:2016-04-03 22:14:36
【问题描述】:

我看了很多帖子,还是不太明白。我有以下代码,它在代码中嵌入的 sql 文本中打印出这个查询的外层。

K.a
K.b
I
J
K
1
2

当函数被递归调用时,我不清楚如何获得内层。我在https://github.com/andialbrecht/sqlparse/blob/master/examples/extract_table_names.py 之后设计了这个,它非常相似并且有效。提前致谢。

# This example illustrates how to extract table names from nested
# SELECT statements.

# See:
# http://groups.google.com/group/sqlparse/browse_thread/thread/b0bd9a022e9d4895

sql = """
select K.a,K.b from (select H.b from (select G.c from (select F.d from
(select E.e from A, B, C, D, E), F), G), H), I, J, K order by 1,2;
"""
import sqlparse
from sqlparse.sql import IdentifierList, Identifier
from sqlparse.tokens import Keyword, DML


def is_subselect(parsed):
    if not parsed.is_group():
        return False
    for item in parsed.tokens:
        if item.ttype is DML and item.value.upper() == 'SELECT':
            return True
    return False


def extract_from_part(parsed):
    from_seen = False
    for item in parsed.tokens:
        if item.ttype is Keyword:
            lastKeyword = str(item)
        #if from_seen:
        if is_subselect(item):
            for x in extract_from_part(item):
                if type(item) in(sqlparse.sql.IdentifierList,sqlparse.sql.Identifier):
                    yield x
        else:
            if type(item) in( sqlparse.sql.IdentifierList,sqlparse.sql.Identifier):
                yield item

def extract_table_identifiers(token_stream):
    for item in token_stream:
        if isinstance(item, IdentifierList):
            for identifier in item.get_identifiers():
                    yield str(identifier)
        elif isinstance(item, Identifier):
            #yield item.get_name()
            yield str(identifier)
        # It's a bug to check for Keyword here, but in the example
        # above some tables names are identified as keywords...
        elif item.ttype is Keyword:
            yield item.value

def extract_tables():
    stream = extract_from_part(sqlparse.parse(sql)[0])
    return list(extract_table_identifiers(stream))
    #return stream


if __name__ == '__main__':
    #print('Tables: %s' % ', '.join(extract_tables()))
    ids = extract_tables()
    for x in ids:
        print x

【问题讨论】:

    标签: python recursion yield


    【解决方案1】:

    您在递归调用之后的循环中进行的类型检查会测试错误对象的类型:

        if is_subselect(item):
            for x in extract_from_part(item):
                # next line should check type(x) rather than type(item)
                if type(item)  in(sqlparse.sql.IdentifierList,sqlparse.sql.Identifier):
                    yield x
    

    尽管如此,这种类型检查是不必要的,因为非递归情况只会产生 IdentifierIdentifierList 项。因此,只需删除该行(并取消缩进以下yield)。

    虽然这不是导致此问题的原因,但我也建议使用 isinstance 而不是直接比较类型:

    if isinstance(item, (sqlparse.sql.Identifier, sqlparse.sql.IdentifierList)):
        yield item
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-03-24
      • 2012-05-03
      • 2012-01-14
      • 2021-05-22
      • 2016-05-03
      • 2017-02-16
      • 1970-01-01
      • 2012-04-06
      相关资源
      最近更新 更多