【问题标题】:Extending builtin classes in python在python中扩展内置类
【发布时间】:2010-09-26 00:52:27
【问题描述】:

如何在 python 中扩展内置类? 我想在 str 类中添加一个方法。
我已经进行了一些搜索,但我找到的只是旧帖子,我希望有人知道更新的内容。

【问题讨论】:

标签: python string monkeypatching


【解决方案1】:

只是子类化类型

>>> class X(str):
...     def my_method(self):
...         return int(self)
...
>>> s = X("Hi Mom")
>>> s.lower()
'hi mom'
>>> s.my_method()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in my_method
ValueError: invalid literal for int() with base 10: 'Hi Mom'

>>> z = X("271828")
>>> z.lower()
'271828'
>>> z.my_method()
271828

【讨论】:

  • 我希望我不必进行子类化,但经过更多研究后,我得出结论,这是不可能的,所以我会接受这个答案。
  • @Unkwntech:无法想象比子类化更好的方法。严重地。无论您想到什么(monkeypatching?)似乎都没有一个清晰、精确、明显的子类。
  • @S.Lott - Ruby 的开放类和 C# 的扩展方法浮现在脑海。
  • @orip:知道这些。发现所有形式的猴子补丁都是管理的噩梦——它们通过以晦涩的方式注入功能来有效地防止重用。
  • @dagfr 通过覆盖 X 类中的 .lower() 方法并返回一个新的 X 对象
【解决方案2】:

一种方法是使用“类重新打开”概念(原生存在于 Ruby 中),该概念可以使用类装饰器在 Python 中实现。 此页面中给出了一个示例: http://www.ianbicking.org/blog/2007/08/opening-python-classes.html

我引用:

我认为使用类装饰器可以做到这一点:

@extend(SomeClassThatAlreadyExists)
class SomeClassThatAlreadyExists:
    def some_method(self, blahblahblah):
        stuff

这样实现的:

def extend(class_to_extend):
    def decorator(extending_class):
        class_to_extend.__dict__.update(extending_class.__dict__)
        return class_to_extend
    return decorator

【讨论】:

  • Python 3.9,__dict__ 不再是dict 而是mappingproxy,你必须改用@MVP 的解决方案。
【解决方案3】:

假设您不能更改内置类。 在 Python3 中模拟像 Ruby 这样的“类重新打开”,其中 __dict__ 是映射代理对象而不是 dict 对象:

def open(cls):
  def update(extension):
    for k,v in extension.__dict__.items():
      if k != '__dict__':
        setattr(cls,k,v)
    return cls
  return update


class A(object):
  def hello(self):
    print('Hello!')

A().hello()   #=> Hello!

#reopen class A
@open(A)
class A(object):
  def hello(self):
    print('New hello!')
  def bye(self):
    print('Bye bye')


A().hello()   #=> New hello!
A().bye()     #=> Bye bye

在 Python2 中,我也可以编写一个装饰器函数 'open':

def open(cls):
  def update(extension):
    namespace = dict(cls.__dict__)
    namespace.update(dict(extension.__dict__))
    return type(cls.__name__,cls.__bases__,namespace)
  return update

【讨论】:

  • 我终于可以像在 Ruby 中一样做到这一点了。奇迹般有效。我更喜欢第二种定义。
猜你喜欢
  • 2013-08-26
  • 1970-01-01
  • 1970-01-01
  • 2011-10-08
  • 1970-01-01
  • 1970-01-01
  • 2010-10-24
  • 2011-09-09
  • 2010-09-07
相关资源
最近更新 更多