Могу ли я добавлять собственные методы/атрибуты к встроенным типам Python?
Например, я хочу добавить метод helloWorld()
к типу типа Python. Могу ли я это сделать?
JavaScript имеет объект-прототип, который ведет себя таким образом. Возможно, это плохой дизайн, и я должен подклассифицировать объект dict, но тогда он работает только в подклассах, и я хочу, чтобы он работал над любыми будущими словарями.
Вот как это будет выглядеть в JavaScript:
String.prototype.hello = function() {
alert("Hello, " + this + "!");
}
"Jed".hello() //alerts "Hello, Jed!"
Здесь полезная ссылка с большим количеством примеров — http://www.javascriptkit.com/javatutors/proto3.shtml
Ответы
Ответ 1
Вы не можете напрямую добавить метод к исходному типу. Однако вы можете подклассифицировать тип, затем подставить его во встроенное/глобальное пространство имен, которое достигает большей части желаемого эффекта. К сожалению, объекты, созданные с помощью литерального синтаксиса, по-прежнему будут иметь тип ванили и не будут иметь ваши новые методы/атрибуты.
Здесь он выглядит как
# 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'
"""
Ответ 2
Да, путем подклассификации этих типов. См. объединение типов и классов в Python.
Нет, это не означает, что фактические dicts будут иметь этот тип, потому что это будет путать. Подкласс встроенного типа является предпочтительным способом добавления функциональности.
Ответ 3
Только что попробовал запрещенный фрукт!
вот код, очень просто!
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()
Ответ 4
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
Dataclass в 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
Ответ 5
ПРИМЕЧАНИЕ: этот QA помечен как дубликат этого, но 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
Надеюсь, это кому-нибудь поможет! Cheers,
Andres
Ответ 6
Подкласс - это путь к Python. Программисты Polyglot учатся использовать правильный инструмент для правильной ситуации - в разумных пределах. То, что искусно сконструировано как Rails (DSL, использующее Ruby), очень трудно реализовать на языке с более жестким синтаксисом, подобным Python. Люди часто сравнивают двух, говорящих, как они похожи. Сравнение несколько несправедливо. Python светит по-своему. totochto.