使用实例方法覆盖父类的classmethod

时间:2014-01-14 22:37:47

标签: python inheritance

我可能不会以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 个答案:

答案 0 :(得分: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()

使用这个单一类,我可以从实例myfn方法中轻松调用caller,但如果使用Bar(),则会传递单独的classcaller实例。使用Bar()调用classmethod与使用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中添加)。