添加方法到函数返回的类

时间:2012-10-22 02:37:38

标签: python class python-3.x mysql-python

免责声明:此问题与家庭作业有关。我不期待一个解决方案,但我希望能更好地理解所要求的内容以及这项家庭作业的(可能)效用。

在使用Python的MySQLdb模块课程以及如何更好地表示结果集(可能还有其行)而不是元组元组(默认情况下是MySQLdb)之后,问了这个问题。

问题是:修改classFactory.py源代码,以便build_row函数返回的DataRow类有另一种方法:

retrieve(self, curs, condition=None)

self(像往常一样)调用其方法的实例,curs是现有数据库连接上的数据库游标,条件(如果存在)是一个条件字符串,必须为所有接收到的行都为true 。 retrieve方法应该是一个生成器,产生结果集的连续行,直到它完全耗尽。每行应该是DataRow类型的新对象。

def build_row(table, cols):
    """Build a class that creates instances of specific rows"""
    class DataRow:
        """Generic data row class, specialized by surrounding function"""
        def __init__(self, data):
            """Uses data and column names to inject attributes"""
            assert len(data)==len(self.cols)
            for colname, dat in zip(self.cols, data):
                setattr(self, colname, dat)
        def __repr__(self):
            return "{0}_record({1})".format(self.table, ", ".join(["{0!r}".format(getattr(self, c)) for c in self.cols]))
    DataRow.table = table
    DataRow.cols = cols.split()
    return DataRow
  1. 在函数定义中创建类的目的是什么?这通常由专业开发人员完成吗?如果是这样,有什么好处?
  2. 为什么数据库游标是retrieve方法的(显式)参数?不应该在此脚本的范围之外引用数据库游标(在建立数据库连接时)?
  3. 说(当前)build_row函数将接受两个参数 - tablecols - 并返回一个看起来像的字符串(作为示例)是否正确exampleTable_record(fieldA,fieldB,fieldC)“?
  4. 成功添加retrieve方法后,我应该期待build_row现在返回什么?
  5. 正如我前面提到的那样,如果我知道为什么要求我添加retrieve方法,那么我可能会更好地了解如何解决这个问题。

3 个答案:

答案 0 :(得分:3)

  1. 这被称为工厂设计模式...虽然在这种情况下它只是为了使类的实例强制到包含类的方法...这迫使你设置表和列名属性在实例化的时候......当你试图调用检索时,如果没有正确地实例化,可能会导致错误......
  2. 我是为了查询数据库,它需要一个游标对象
  3. 是的,但它返回,而DataRow Class不是字符串......这有一个字符串表示
  4. 包含数据的数据行...
  5. 这是一个讨论工厂设计模式的链接 Why do we need Abstract factory design pattern?

    示例检索功能

    @classmethod #if this is a classmethod
    def retrieve(self, curs, condition=None):
            if condition:
               curs.execute("SELECT * FROM {0} WHERE {1}".format(self.table,condition)
            else:
               curs.execute("SELECT * FROM {0}".format(self.table)
            for row in curs.fetchall():
                yield DataRow(row)
    

    然后你会做类似

    的事情
    my_users = build_row("users",["username","password","avatar"])
    my_users = my_users()  #if you need to operate on an instance.... but class method would be better
    #users is the name of a table already in our database, whose columns are username,password, and avatar
    db=sqlite3.connect("some_database.sql")
    for user in my_users.retrieve(db.cursor(),"username='bob'"):
        print user #something like users_record({'username':'bob','password':'123%gw','avatar':None)
        print user.username #bob
        print user.avatar #None
        print user.password #whatever
        print user.blah #Error!!!!
    

答案 1 :(得分:2)

  

2)为什么数据库游标是检索方法的(显式)参数?数据库游标是否应该在此脚本范围之外引用(在建立数据库连接时)?

封装。依赖全局魔术变量会创建应尽可能避免的依赖关系。考虑您的应用程序可能同时有多个游标处于活动状态,或者甚至可能通过单独的连接与两个数据库通信。

传入参数也使代码更容易测试:你可以传递一个模拟类或类似的东西,而不必修改全局变量。

答案 2 :(得分:1)

您所拥有的是一个可以专业使用的示例。函数build_row是一个类工厂,它返回一个适合处理特定表和列数据的类。

虽然在个别情况下我个人不会使用工厂模式,但确实有效。

因此,为了解释这段代码正在做什么,它基本上创建了一个使用函数调用中的表和cols的类。如果您在代码self.colsself.table中注意到它们,但它们实际上不是DataRow的一部分,那么它们之后会附加到它上面,这表明了以这种方式创建类的灵活性

build_row函数实际返回的是一个类!这个类应该用于从数据库中获取数据......这是你必须为你的任务建立的部分。您需要在select语句中使用table(表名),您还需要cols ...基本上您的函数(我不会为您编写)应该:

SELECT <PUT THE `cols` HERE> FROM `table`;

并返回结果。这应该足以让你前进。