我可以将自定义方法/属性添加到内置Python类型吗?


76

例如,例如我想helloWorld()向Python的dict类型添加一个方法。我可以这样做吗?

JavaScript具有这种行为的原型对象。也许这是错误的设计,我应该将dict对象子类化,但随后它只能在子类上工作,而我希望它在将来的所有字典中都可以使用。

这是在JavaScript中的用法:

String.prototype.hello = function() {
    alert("Hello, " + this + "!");
}
"Jed".hello() //alerts "Hello, Jed!"

这是带有更多示例的有用链接-http ://www.javascriptkit.com/javatutors/proto3.shtml


1
您也可以通过简单地再次打开类来在ruby中执行此操作,即:class String; def new_method()...;结束; 我很确定python也有类似的东西。
阿卜杜拉·吉巴利

@阿卜杜拉(Abdullah),我相信您指的是猴子修补,大多数人对此并不满意。
拉菲·凯特勒

是啊 它已在Rails中完成。
阿卜杜拉·吉巴利

这是特定于的,numpy.ndarray但是如果有人来这里尝试此操作,但在尝试将方法添加到的实例时失败numpy.ndarray,请查看该numpy.ndarray.view方法。
mondaugen

Answers:


79

您不能直接将方法添加到原始类型。但是,您可以对类型进行子类化,然后将其替换为内置/全局名称空间,从而实现所需的大多数效果。不幸的是,通过文字语法创建的对象将继续为原始类型,并且不会具有新的方法/属性。

这是它的样子

# Built-in namespace
import __builtin__

# Extended subclass
class mystr(str):
    def first_last(self):
        if self:
            return self[0] + self[-1]
        else:
            return ''

# Substitute the original str with the subclass on the built-in namespace    
__builtin__.str = mystr

print str(1234).first_last()
print str(0).first_last()
print str('').first_last()
print '0'.first_last()

output = """
14
00

Traceback (most recent call last):
  File "strp.py", line 16, in <module>
    print '0'.first_last()
AttributeError: 'str' object has no attribute 'first_last'
"""

我想我只需要使用首选的子类化方法。也许我会爱上它。
jedmao 2011年

26
注意:该__builtin__模块builtins在Python3中已重命名为。
changokun 2013年

好吧,我在python 2中遇到了一个问题。之后,我再也无法检查类型了> type('')== str <只是给出了> false <。当我键入(“”)时,我得到<type'str'>,但是以某种方式,比较不再起作用。在运行“内置线.str = mystr”之前,检查类型是否有效。
纳杜

@Nadu如OP所说,“通过文字语法创建的对象将继续为普通类型”
Alex Hall

@nadu。通常,检查类型时不应使用==。而是使用isinstance(“”,str),如果第一个值是第二个实例或第二个实例的任何子类,则它将返回True。
克里斯·科格登

6

刚试过的禁果!

这是代码,非常简单!

from forbiddenfruit import curse


def list_size(self):
    return len(self)

def string_hello(self):
    print("Hello, {}".format(self))

if __name__ == "__main__":
    curse(list, "size", list_size)
    a = [1, 2, 3]
    print(a.size())
    curse(str, "hello", string_hello)
    "Jesse".hello()

6
首先,禁止的水果不仅是一个坏主意,而且执行不佳,很容易导致段错误和内存损坏。
user2357112支持Monica

我喜欢。我会用。
维塔利·法德耶夫

@ user2357112supportsMonica您是否有任何链接可以更详细地了解禁果?
DarthVlader

2
class MyString:
    def __init__(self, string):
        self.string = string
    def bigger_string(self):
        print(' '.join(self.string))

mystring = MyString("this is the string")
mystring.bigger_string()

输出

t h i s   i s   t h e   s t r i n g

Python 3.7中的数据类

from dataclasses import dataclass

@dataclass
class St:

    text : str

    def bigger(self) -> None:
        self.text = list(self.text)
        print(" ".join(self.text))

mys = St("Hello")
mys.bigger()

输出

H e l l o

2

注意:此质量检查标记为与重复,但IMO要求提供其他内容。我不能在那里回答,所以我在这里回答。


具体来说,我想继承自str定义属性并添加自定义属性。现有答案(尤其是那些说不能)的答案并不能完全解决问题,但这对我有用:

class TaggedString(str):
    """
    A ``str`` with a ``.tags`` set and ``.kwtags`` dict of tags.
    Usage example::
      ts = TaggedString("hello world!", "greeting", "cliche",
                        what_am_i="h4cker")
      (ts.upper(), ts.tags, ts.kwtags)
    """

    def __new__(cls, *args, **kwargs):
        return super().__new__(cls, args[0])

    def __init__(self, s, *tags, **kwtags):
        super().__init__()
        self.tags = set(tags)
        self.kwtags = kwtags

希望这可以帮助某人!干杯,
安德烈斯


1

确实可以,但是您必须定义一个相同类型的新类,并且它应该从该类型继承。

例如:

class list(list):
    def __init__(self,*args):
        super().__init__(args)
    def map(self,function):
        return [function(i) for i in self]

a = list(1,2,3,4,5)
Def double(i): return i*2

print(a.map(double))

0

是的,通过对这些类型进行子类化。请参阅在Python中统一类型和类

不,这并不意味着实际的字典将具有这种类型,因为这会造成混淆。子类化内置类型是添加功能的首选方法。


11
那会令人困惑,并且非常有用。
Evgeni Sergeev

1
@Veky我想any_dictionary_instance.len()还是.size(),除了现有的any_dictionary_instance.__len__()len(any_dictionary_instance)调用它。大小在语义上是容器的属性,因此写起来更方便,例如“从0迭代到对象的大小” ...哎呀,无法表达,语言迫使我将其改写为“从0迭代。到物体的大小”。出于历史原因,我聚集了。
Evgeni Sergeev

1
@nehemiah,你知道Evgeni是什么意思。我读了他的话。您读过上面的他的评论吗?他明确地哀叹在访问尺寸时无法使用Saxon整语的事实。顺便说一句,这是他的代码,直到有人维护它为止。而且他显然可以根据自己的喜好更改和重新编译运行时环境。:-P
Veky

1
@nehemiah,这是什么问题?您确实同意str是与MyStr不同的类型,对吗?
Veky

4
我希望不会(尽管Guido辞职了,一切皆有可能:-/)。知道Python类型的全部目的就是知道它们具有什么方法。如果有人可以向添加随机功能str,那么您就是不知道什么类型'abc'。当然,那是不可接受的。是的,JS确实存在很大的问题:见证motools Array.flatten惨败。
Veky

-3

子类化是使用Python的方式。Polyglot程序员学会在合理的情况下针对正确的情况使用正确的工具。用Rails(使用Ruby的DSL)这样巧妙地构造的东西很难用像Python这样具有更严格语法的语言来实现。人们经常将两者相提并论。这种比较有点不公平。Python以自​​己的方式发光。托托托。


我看不出子类化字符串类的意义。OP对他想要什么很清楚。
nehem
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.