1

所以我从 python 2.7 脚本访问 MySQL,现在我可以这样做:

for id, name, area in db.select('SELECT id, name, area'
                     ' FROM some_table'
                     ' WHERE area IS NOT NULL'):
    print id, name, area

但是 for 语句和 select 语句中的重复变量id, name, area正在吞噬我。假设 db 列名可以用作变量名,我想要这样的东西:

for id, name, area in db.select(from='sometable', where='area IS NOT NULL'):
    print id, name, area

当然for语句中的变量必须是动态传入的db.select,这样我就可以不用改了db.select

4

2 回答 2

1

评论中的一个解决方案,建议使用字典行工厂,似乎非常接近你想要的。

在我看来,更接近(更容易编写)的namedtuple. 为此,我曾经写过:

def namtupiter(c):
    from collections import namedtuple
    fields = tuple(i[0] for i in c.description)
    Row = namedtuple('Row', fields)
    # make Row a tuple and a "dict" (well, kind of...) at the same time.
    # Don't lose tuple property, so only process strings and pass everything
    # other to super().
    Row.__getitem__ = lambda self, item: getattr(self, item) if isinstance(item, basestring) else super(Row, self).__getitem__(item)
    for i in c:
        try:
            # try to access i as a dict
            yield Row(*(i[f] for f in fields))
        except TypeError:
            # it is no dict -> try tuple
            yield Row(*i)

class CursorNTRowsMixIn(object):
    _fetch_type = 0 # tuples
    def _do_get_result(self):
        super(CursorNTRowsMixIn, self)._do_get_result()
        # create a named tuple class
        from collections import namedtuple
        if self.description:
            self.RowClass = namedtuple('Row', tuple(i[0] for i in self.description))
    def _fetch_row(self, size=1):
        rows = super(CursorNTRowsMixIn, self)._fetch_row(size)
        # turn every row into a Row().
        return tuple(self.RowClass(*i) for i in rows)

class NTCursor(CursorStoreResultMixIn, CursorNTRowsMixIn,
               BaseCursor):
    pass

class SSNTCursor(CursorUseResultMixIn, CursorNTRowsMixIn,
               BaseCursor):
    pass

使用namtupiter(),您可以遍历包含结果集的游标并接收带有作为属性包含的 DB 字段的 NamedTuples。

所以你可以做

for r in namtupiter(db.select(fields=('id', 'name', 'area', _from='sometable', where='area IS NOT NULL')):
    print r.id, r.name, r.area

另一种方式是 ( SS) NTCursor,它可以被视为提供元组或字典的现有游标的替代方案。这些新游标还将行作为命名元组提供从结果集中提取的名称信息。

于 2013-07-15T10:49:32.640 回答
0

以下示例未使用命名元组。我正在使用 mysql.connector,但可以使用任何数据库驱动程序来完成:

import mysql.connector

CONFIG = {
    'database': 'test',
    'user': 'root',
}

class MySQLStackOverflowConnect(mysql.connector.MySQLConnection):
    def select(self, table, where, fields=None):
        if isinstance(fields, (list, tuple)):
            select_fields = ', '.join(fields)
        else:
            select_fields = '*'
        query = "SELECT {fields} FROM `{table}` WHERE {where}".format(
            table=table, where=where, fields=select_fields)
        cur = self.cursor(buffered=True)
        cur.execute(query)
        return cur

cnx = MySQLStackOverflowConnect(**CONFIG)
for userid, username in cnx.select(table='users', where='id=1',
                                   fields=('id', 'username')):
    print userid, username
cnx.close()

(小心通过 WHERE 子句进行 SQL 注入)

使用 Python 3,您将能够执行最后一个 for 循环,前提是该表具有idusername作为第一个字段,如下所示:

for userid, username, *rest in cnx.select(table='auth_user', where='id=1'):
    print(userid, username)
于 2013-07-16T09:27:01.733 回答