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

例如,假设我想在 Python 的 dict 类型中添加一个 helloWorld()方法?

JavaScript 有一个这样行为的原型对象。也许这是糟糕的设计,我应该子类的 dict 对象,但它只工作在子类,我希望它工作在任何和所有未来的字典。

以下是 JavaScript 中的流程:

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

这里有一个有用的链接,有更多的例子

42090 次浏览

Yes, by subclassing those types. See unifying types and classes in Python.

No, this doesn't mean that actual dicts will have this type, because that would be confusing. Subclassing a builtin type is the preferred way to add functionality.

You can't directly add the method to the original type. However, you can subclass the type then substitute it in the built-in/global namespace, which achieves most of the effect desired. Unfortunately, objects created by literal syntax will continue to be of the vanilla type and won't have your new methods/attributes.

Here's what it looks like

# 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'
"""

Subclassing is the way to go in Python. Polyglot programmers learn to use the right tool for the right situation - within reason. Something as artfully constructed as Rails (a DSL using Ruby) is painfully difficult to implement in a language with more rigid syntax like Python. People often compare the two saying how similar they are. The comparison is somewhat unfair. Python shines in its own ways. totochto.

Just tried the forbbidenfruit!

here is the code, very simple!

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()
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()

output

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

Dataclass in 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()

output

H e l l o

NOTE: this QA is marked as duplicate to this one, but IMO it asks for something different. I cannot answer there, so I am answering here.


Specifically, I wanted to inherit from str and add custom attributes. Existing answers (especially the ones saying you can't) didn't quite solve it, but this worked for me:

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

Hopefully this helps someone! Cheers,
Andres

Yes indeed, but you have to define a new class of the same type and it should inherit from that type.

For example:

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))

Yes, we can add custom methods and attributes to built-in python types. For example, let us say, you wanna define a new method inside the list class.

Let us think of defining a 'list' class and writing your own function like as follows :

class list:
def custom_method (self):
return("Hey, I'm a custom method of list class")
#lets create an object here
obj = list([1,2,3])


print(obj.custom_method())
#The above runs fine, but a list has append() method also right?? let's try it


print(obj.append(1))
"""Now you will get Attribute error : list object has no attribute append()"""

Because, when you define class having 'list' as class name, you will no longer be able to access the 'in-built list' class methods as 'list' is treated as a user-defined class rather than a inbuilt class.

So, in order to get rid of this error, you can inherit the properties/members of 'list' class and you can define own methods or attributes. So, in this way, you can call user-defined / in-built class methods using the same class name.

Here's how it looks :

#Extending in-built list class
class list(list):
def custom_method (self):
return("Hey, I'm a custom method of list class")
obj = list([1,2,3])
print(obj.custom_method())
obj.append(1)
print(obj)

It runs fine, and outputs modified list as [1,2,3,1].

NOTE : But when you do like this, it may create some ambiguity issues in long run like naming conflicts

For example, if you had a method having same signature that of an inbuilt function in user-defined class(say 'list' here), then it will be overridden without your knowledge or notice, thus you may not be able to use its original functionality in future. Considering the above code, if you ever define a method like append(self, value), the original functionality of append() will be lost.

So, it is better to use a different class name for your class name rather than same name as inbuilt class name

For example, you can declare a class like here as follows which does not raise any errors or you will not face any naming conflicts.

class custom_list(list):
def custom_method (self):
return("Hey, I'm a custom method of list class")
obj = custom_list([1,2,3])
print(obj.custom_method())
obj.append(1)
print(obj)