当前位置: 首页 > 面试题库 >

在Python中重分类实例

秦俊豪
2023-03-14
问题内容

我有一个由外部库提供的类。我已经创建了该类的子类。我也有一个原始类的实例。

现在,我想将此实例转换为我的子类的一个实例,而不更改该实例已经具有的任何属性(但无论如何,我的子类都会覆盖这些属性)。

以下解决方案似乎有效。

# This class comes from an external library. I don't (want) to control
# it, and I want to be open to changes that get made to the class
# by the library provider.
class Programmer(object):
    def __init__(self,name):
        self._name = name

    def greet(self):
        print "Hi, my name is %s." % self._name

    def hard_work(self):
        print "The garbage collector will take care of everything."

# This is my subclass.
class C_Programmer(Programmer):
    def __init__(self, *args, **kwargs):
        super(C_Programmer,self).__init__(*args, **kwargs)
        self.learn_C()

    def learn_C(self):
        self._knowledge = ["malloc","free","pointer arithmetic","curly braces"]

    def hard_work(self):
        print "I'll have to remember " + " and ".join(self._knowledge) + "."

    # The questionable thing: Reclassing a programmer.
    @classmethod
    def teach_C(cls, programmer):
        programmer.__class__ = cls # <-- do I really want to do this?
        programmer.learn_C()


joel = C_Programmer("Joel")
joel.greet()
joel.hard_work()
#>Hi, my name is Joel.
#>I'll have to remember malloc and free and pointer arithmetic and curly braces.

jeff = Programmer("Jeff")

# We (or someone else) makes changes to the instance. The reclassing shouldn't
# overwrite these.
jeff._name = "Jeff A"

jeff.greet()
jeff.hard_work()
#>Hi, my name is Jeff A.
#>The garbage collector will take care of everything.

# Let magic happen.
C_Programmer.teach_C(jeff)

jeff.greet()
jeff.hard_work()
#>Hi, my name is Jeff A.
#>I'll have to remember malloc and free and pointer arithmetic and curly braces.

但是,我不认为该解决方案没有包含我从未想到的警告(对三重否定表示抱歉),尤其是因为重新分配魔术师__class__感觉不对。即使这行得通,我也不禁感到应该有一种更Python化的方式来做到这一点。

在那儿?

编辑:谢谢大家的回答。这是我从他们那里得到的:

  • 尽管通过分配给实例来重分类实例的想法__class__并不是一种广泛使用的习语,但是大多数答案(在撰写本文时,每6个问题中就有4个)认为它是一种有效的方法。一个回答者(由ojrac撰写)说,“乍一看,这很奇怪”,我对此表示同意(这是提出问题的原因)。只有一个答案(由Jason Baker撰写;有两个正面的评论和投票)积极地阻止了我这样做,但是这样做的依据更多是示例用例,而不是一般的技术。

  • 不管是肯定的还是不是肯定的,答案都没有找到这种方法的实际技术问题。一个小例外是jls,他提到要提防老式类(这很可能是真的)和C扩展。我想这种方法应该和Python本身一样好(假设后者是正确的),尽管这种方法可以保持答案,但是我想新风格类C扩展应该和Python本身一样好。

关于这是pythonic的问题,有一些肯定的答案,但没有给出真正的原因。看一下Zen(import this),我想在这种情况下最重要的规则是“显式胜于隐式”。不过,我不确定该规则是否支持这种重分类。

  • 使用{has,get,set}attr似乎更明确,因为我们明确地对对象进行了更改,而不是使用魔术。

  • 使用__class__ = newclass似乎更明确,因为我们明确地说“这现在是类’newclass’的对象,期望有不同的行为”,而不是默默地更改属性,但使对象的用户认为他们正在处理旧类的常规对象。

总结:从技术的角度来看,该方法似乎还可以。pythonicity问题仍然没有答案,偏向“是”。

我接受了马丁·盖斯勒(Martin
Geisler)的回答,因为Mercurial插件示例是一个非常强大的示例(还因为它回答了我什至没有问过自己的问题)。但是,如果在pythonicity问题上有任何争论,我还是想听听他们的看法。到目前为止谢谢大家。

PS实际用例是UI数据控制对象,需要 在运行时 增加其他功能。但是,这个问题的含义很笼统。


问题答案:

当扩展(插件)想要更改表示本地存储库的对象时,在Mercurial(分布式修订控制系统)中对此类实例进行重分类。该对象被调用repo,并且最初是一个localrepo实例。它依次传递给每个扩展,并在需要时扩展将定义一个新类,该新类是该子类的子类,repo.__class__并将其类
更改repo为该新子类!

在代码中看起来像这样:

def reposetup(ui, repo):
    # ...

    class bookmark_repo(repo.__class__): 
        def rollback(self):
            if os.path.exists(self.join('undo.bookmarks')):
                util.rename(self.join('undo.bookmarks'), self.join('bookmarks'))
            return super(bookmark_repo, self).rollback()

        # ...

    repo.__class__ = bookmark_repo

扩展名(我从书签扩展名中获取了代码)定义了一个名为的模块级函数reposetup。在初始化扩展并传递ui(用户界面)和repo(存储库)参数时,Mercurial将调用此方法。

然后,该函数定义repo碰巧是任何类的子类。这将
足够简单的子类localrepo,因为扩展需要能够延长对方。因此,如果第一个扩展名更改repo.__class__foo_repo,则下一个扩展名应更改repo.__class__为的子类,foo_repo而不仅仅是的子类localrepo。最后,该函数将更改instanceø的类,就像您在代码中所做的一样。

我希望这段代码可以显示对该语言功能的合法使用。我认为这是我在野外看到它的唯一地方。



 类似资料:
  • 本文向大家介绍Python栈类实例分析,包括了Python栈类实例分析的使用技巧和注意事项,需要的朋友参考一下 本文实例讲述了python栈类。分享给大家供大家参考。具体如下: 希望本文所述对大家的Python程序设计有所帮助。

  • 问题内容: 我已经在python中编写了一个类,希望通过IronPython包装到.net程序集中,并在C#应用程序中实例化。我已经将该类迁移到IronPython,创建了一个库程序集并对其进行了引用。现在,我实际上如何获得该类的实例? 该类看起来(部分地)是这样的: 我用C#编写的测试存根是: 为了在C#中实例化此类,我必须做什么? 问题答案: IronPython类 不是.NET类。它们是Ir

  • 本文向大家介绍Python基类函数的重载与调用实例分析,包括了Python基类函数的重载与调用实例分析的使用技巧和注意事项,需要的朋友参考一下 本文实例讲述了Python基类函数的重载与调用方法。分享给大家供大家参考。具体分析如下: 刚接触Python语言的时间不长,对于这个语言的很多特性并不是很了解,有很多用法都是还不知道。今天想着写一个Python面向对象编程时的继承中的函数调用。分享出来,一

  • 本文向大家介绍python文件拆分与重组实例,包括了python文件拆分与重组实例的使用技巧和注意事项,需要的朋友参考一下 文件拆分代码: 文件重组代码: 拆分文件演示: 源文件: 拆分: 拆分后文件: 重组文件: 重组后文件: 以上这篇python文件拆分与重组实例就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持呐喊教程。

  • 本文向大家介绍python实现KNN分类算法,包括了python实现KNN分类算法的使用技巧和注意事项,需要的朋友参考一下 一、KNN算法简介 邻近算法,或者说K最近邻(kNN,k-NearestNeighbor)分类算法是数据挖掘分类技术中最简单的方法之一。所谓K最近邻,就是k个最近的邻居的意思,说的是每个样本都可以用它最接近的k个邻居来代表。 kNN算法的核心思想是如果一个样本在特征空间中的k