2014-01-14 59 views
0

我可能没有想到Pythonic方法。 我有一个类,SQLDB,它使用使用fetchall把所有的行从游标:使用实例方法覆盖父级的方法

class SqlDB(object): 

    @classmethod 
    def executeQuery(cls, cursor, query, params): 
     # code to set up and execute query here 
     rows = cls.fetchRows(cursor) 
     # other code here 

    @classmethod 
    def fetchRows(cls, cursor): 
     print "in class SqlDB" 
     return cursor.fetchall() 

所以我想补充一点,使用支持fetchmany一个子类,并得到了批量初始化:

class SqlDBBatch(SqlDB): 

    def __init__(self, batchsize=1000): 
     self.batchsize = batchsize 

    def fetchRows(self, cursor): 
     print "in SqlDBBatch" 
     while True: 
      results = cursor.fetchmany(self.batchsize) 
     # more code 

当然,由于原始的executeQuery函数正在调用传递给它的类的fetchRows,所以当我尝试调用SqlDBBatch实例上的executeQuery时,我得到了TypeError: unbound method fetchRows() must be called with SqlDBBatch instance as first argument (got CursorDebugWrapper instance instead)。有什么办法来实现我要去的地方,我可以用实例方法覆盖父类的方法,并让父类能够调用子类的实现?

+1

实例方法仅在实例的上下文中才有意义。在类方法中,您没有实例来调用实例方法。这确实没有意义。为什么'executeQuery'和'fetchRows'必须是类方法?他们似乎是非常有意义的实例方法... – BartoszKP

+0

'SqlDB'父类没有任何状态附加到它,因为它做一个'fetchall()'每次没有参数,所以它看起来像它会作为一种类方法是有意义的。对于'SqlDBBatch',它正在使用批处理大小进行初始化,因此可以使用它的'fetchmany()'调用,因此实例中的值会影响一次提取多少行。 – TransatlanticFoe

+0

1)似乎很奇怪,一个DB类没有状态 - 通常它是一个数据库连接。 2)缺乏状态不足以决定使用类方法。你的设计中的问题就是一个很好的例子。 – BartoszKP

回答

0

我不认为问题是父母或继承,而只是从类方法调用实例方法。

class Bar(object): 
    def caller(self,x='cx'): 
     print('bar caller',self) 
     self.myfn(x) 
    @classmethod 
    def classcaller(cls,x='ccx'): 
     print('bar class caller',cls) 
     cls.myfn(x) 
    def myfn(self,x=None): 
     print('in bar instance',self,x) 
    def __repr__(self): 
     return 'BarInstance' 

Bar().myfn() 
# ('in bar instance', BarInstance, None) 
Bar.myfn(Bar()) 
# ('in bar instance', BarInstance, None) 
Bar().caller() 
# ('bar caller', BarInstance) 
# ('in bar instance', BarInstance, 'cx') 
Bar.classcaller(Bar()) 
# ('bar class caller', <class '__main__.Bar'>) 
# ('in bar instance', BarInstance, None) 
Bar().classcaller(Bar()) 
# same 

# the following produce: 
#  TypeError: unbound method myfn() must be called with Bar instance ... 
# Bar.myfn() 
# Bar.caller() 
# Bar.classcaller() 
# Bar().classcaller() 

利用该单个类,我可以很容易地调用从实例caller方法myfn,但是具有如果使用classcaller通过一个单独的Bar()实例。用Bar()调用类方法与用Bar调用它没有区别。

即使使用实例调用classmethod,它也是通过的klass,而不是objhttp://docs.python.org/2/howto/descriptor.html#static-methods-and-class-methods

class ClassMethod(object): 
    "Emulate PyClassMethod_Type() in Objects/funcobject.c" 
    ... 
    def __get__(self, obj, klass=None): 
      if klass is None: 
       klass = type(obj) 
      def newfunc(*args): 
       return self.f(klass, *args) 
      return newfunc 

你为什么要使用@classmethod?你是用类名还是实例来称呼它们?即使父类版本不使用实例属性,也可能更简单地在所有级别使用实例方法。 Python在没有这个装饰器的情况下相处了很多年(在2.4中加入)。

+0

错误是说它将光标作为第一个参数而不是'self',因为我在父类的类上调用它。我试图有效地调用'SqlDBBatch(batchsize = 1000).executeQuery(“queryhere”)',并且使用孩子'fetchRows(游标)'而不是父级。 – TransatlanticFoe

+0

实验更多,我已经断定问题是使用'classmethod'来调用一个实例方法。这不是关于父类。 'executeQuery'获取'SqlDBBatch'类,但不是'SqlDBBatch()'实例。 – hpaulj