【问题标题】:Can I override a class function without creating a new class in Python?我可以在不在 Python 中创建新类的情况下覆盖类函数吗?
【发布时间】:2013-07-19 09:32:02
【问题描述】:

我正在 pygame 中制作游戏,并且我创建了一个“抽象”类,它的唯一工作是存储给定关卡的精灵(目的是将这些关卡对象放在列表中以方便玩家移动从一个级别到另一个级别)

好的,那么问题来了。如果我能在 Python 中做同样的事情(Java 的代码curtesy):

Object object = new Object (){
    public void overriddenFunction(){
        //new functionality
        };
    };

与在游戏中构建关卡相比,我只需要使用精灵所在位置的信息覆盖构造函数(或负责构建关卡的类/实例方法),因为为游戏中的每个关卡都不是那么优雅的答案。或者,我必须在关卡类中创建方法,然后在实例化关卡对象后构建关卡,并根据需要放置精灵。

因此,在一位更坚定的开发人员继续谈论这可能是多么反 python(我已经阅读了足够多的本网站以从 Python 专家那里获得这种氛围)之前,请告诉我它是否可行。

【问题讨论】:

  • 当你说“'抽象'类”时,你的意思是你实际上使用了abc.ABCMetaabc.abstractmethod,或者你在这里做了自己的事情
  • 如果我错了,请有人纠正我。但是,是的,这实际上创建了一个匿名类。

标签: python oop object polymorphism overriding


【解决方案1】:

是的,你可以!

class Foo:
    def do_other(self):
        print('other!')
    def do_foo(self):
        print('foo!')


def do_baz():
    print('baz!')

def do_bar(self):
    print('bar!')

# Class-wide impact
Foo.do_foo = do_bar
f = Foo()
g = Foo()
# Instance-wide impact
g.do_other = do_baz

f.do_foo()  # prints "bar!"
f.do_other()  # prints "other!"

g.do_foo()  # prints "bar!"
g.do_other()  # prints "baz!"

所以,在一位更坚定的开发人员继续讨论这可能是多么反蟒蛇之前

以这种方式覆盖函数(如果你有充分的理由这样做)对我来说似乎是相当 Python 的。您可能必须这样做的一个原因/方式的一个示例是,如果您有一个静态继承不适用或不能适用的动态特性。

可能在 Python 之禅中找到反对的案例:

  • 美胜于丑。
  • 可读性很重要。
  • 如果实现难以解释,那就是个坏主意。

【讨论】:

  • 您已经覆盖了类方法 (Foo.do_foo),所以如果我执行 g = Foo() 并调用 g.do_foo(),也会打印出 bar。可能是 OP 想要的,不确定他是否想要每个 instance 或每个 class... 覆盖
  • 确实,这就是我的示例的意图。标题写着“类功能”,所以我就是这么做的。
  • 它可能不是pythonic(我主要是Java开发人员),但它对于使用isChildGivenCriteria(criteria)函数和根节点创建树结构非常有用,用“一切都是我的孩子”return True函数
【解决方案2】:

是的,这是可行的。在这里,我使用functools.partial 将隐含的self 参数转换为常规(非类方法)函数:

import functools

class WackyCount(object):
    "it's a counter, but it has one wacky method"
    def __init__(self, name, value):
        self.name = name
        self.value = value
    def __str__(self):
        return '%s = %d' % (self.name, self.value)
    def incr(self):
        self.value += 1
    def decr(self):
        self.value -= 1
    def wacky_incr(self):
        self.value += random.randint(5, 9)

# although x is a regular wacky counter...
x = WackyCount('spam', 1)
# it increments like crazy:
def spam_incr(self):
    self.value *= 2
x.incr = functools.partial(spam_incr, x)

print (x)
x.incr()
print (x)
x.incr()
print (x)
x.incr()
print (x)

和:

$ python2.7 wacky.py
spam = 1
spam = 2
spam = 4
spam = 8
$ python3.2 wacky.py    
spam = 1
spam = 2
spam = 4
spam = 8

编辑以添加注释:这是一个 每个实例 覆盖。它利用了 Python 的属性查找序列:如果x 是类K 的一个实例,那么x.attrname 首先查看x 的字典来查找属性。如果没有找到,下一个查找是在K。所有正常的类函数实际上都是K.func。因此,如果您想动态替换 class 函数,请改用@Brian Cane 的答案。

【讨论】:

    【解决方案3】:

    我建议通过继承为每个级别使用不同的类。

    但是,如果您真的愿意像对待 Java 一样对待 Python,那么您可能会从 copy.deepcopy() 和猴子补丁中获得一些好处。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-11-04
      • 1970-01-01
      • 2019-12-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-05-21
      • 1970-01-01
      相关资源
      最近更新 更多