好的,在c#中我们有类似的东西:
public static string Destroy(this string s) {
return "";
}
所以基本上,当你有一个字符串时,你可以这样做:
str = "This is my string to be destroyed";
newstr = str.Destroy()
# instead of
newstr = Destroy(str)
现在这很酷,因为在我看来它更具可读性。 python有类似的东西吗?我的意思是代替这样写:
x = SomeClass()
div = x.getMyDiv()
span = x.FirstChild(x.FirstChild(div)) # so instead of this I'd like to write:
span = div.FirstChild().FirstChild() # which is more readable to me
有什么建议吗?
答案 0 :(得分:18)
您可以直接修改该类,有时也称为猴子修补。
def MyMethod(self):
return self + self
MyClass.MyMethod = MyMethod
del(MyMethod)#clean up namespace
我不是100%确定你可以在像str这样的特殊类上执行此操作,但是对于用户定义的类来说这很好。
<强>更新强>
你在评论中证实我怀疑这对于像str这样的内置是不可能的。在这种情况下,我认为这类的C#扩展方法没有类似的东西。
最后,在C#和Python中,这些方法的便利性带来了相关的风险。使用这些技术可以使代码更难以理解和维护。
答案 1 :(得分:4)
我会在这里使用Adapter模式。因此,假设我们有一个Person
类,并且在一个特定的位置上我们想添加一些与健康相关的方法。
from dataclasses import dataclass
@dataclass
class Person:
name: str
height: float # in meters
mass: float # in kg
class PersonMedicalAdapter:
person: Person
def __init__(self, person: Person):
self.person = person
def __getattr__(self, item):
return getattr(self.person, item)
def get_body_mass_index(self) -> float:
return self.person.mass / self.person.height ** 2
if __name__ == '__main__':
person = Person('John', height=1.7, mass=76)
person_adapter = PersonMedicalAdapter(person)
print(person_adapter.name) # Call to Person object field
print(person_adapter.get_body_mass_index()) # Call to wrapper object method
我认为它是一种易于阅读但灵活且具有Python风格的解决方案。
答案 2 :(得分:3)
您可以在forbidden fruit
的帮助下通过猴子修补来更改内置类但安装禁果需要 C编译器和不受限制的环境,因此它可能无法运行或需要努力在Google App Engine,Heroku等上运行< / p>
我通过此库更改了Python 2.7中unicode
类的行为,以解决土耳其语i,I
大写/小写问题。
# -*- coding: utf8 -*-
# Redesigned by @guneysus
import __builtin__
from forbiddenfruit import curse
lcase_table = tuple(u'abcçdefgğhıijklmnoöprsştuüvyz')
ucase_table = tuple(u'ABCÇDEFGĞHIİJKLMNOÖPRSŞTUÜVYZ')
def upper(data):
data = data.replace('i',u'İ')
data = data.replace(u'ı',u'I')
result = ''
for char in data:
try:
char_index = lcase_table.index(char)
ucase_char = ucase_table[char_index]
except:
ucase_char = char
result += ucase_char
return result
curse(__builtin__.unicode, 'upper', upper)
class unicode_tr(unicode):
"""For Backward compatibility"""
def __init__(self, arg):
super(unicode_tr, self).__init__(*args, **kwargs)
if __name__ == '__main__':
print u'istanbul'.upper()
答案 3 :(得分:1)
您可以通过以下context manager很好地实现此目标,该方法将方法添加到上下文块内的类或对象中,然后将其删除:
newJsonx = dict()
for item in data["resultsPage"]["results"]["calendarEntry"]:
name = item["event"]["performance"][0]["displayName"]
page_titles = [name]
url = (
'https://en.wikipedia.org/w/api.php'
'?action=query'
'&prop=info'
'&inprop=subjectid'
'&titles=' + '|'.join(page_titles) +
'&format=json')
json_response = requests.get(url).json()
title_to_page_id = {page_id for page_id, page_info in json_response['query']['pages'].items()}
print(title_to_page_id)
wikipedia_url = f'https://fr.wikipedia.org/w/api.php?format=json&action=query&prop=extracts&exintro&explaintext&redirects=1&titles={name}'
r = requests.get(wikipedia_url)
wikipedia_json = r.json()
intro = wikipedia_json['query']['pages'][{title_to_page_id}]['extract']
print(intro)
用法如下:
class extension_method:
def __init__(self, obj, method):
method_name = method.__name__
setattr(obj, method_name, method)
self.obj = obj
self.method_name = method_name
def __enter__(self):
return self.obj
def __exit__(self, type, value, traceback):
# remove this if you want to keep the extension method after context exit
delattr(self.obj, self.method_name)
答案 4 :(得分:0)
您可以按照以下方式执行您的要求:
def extension_method(self):
#do stuff
class.extension_method = extension_method
答案 5 :(得分:0)
我认为 C# 中的扩展方法与普通方法调用几乎相同,在普通方法调用中,您传递实例然后传递参数和其他东西。
instance.method(*args, **kwargs)
method(instance, *args, **kwargs) # pretty much the same as above, I don't see much benefit of it getting implemented in python.
答案 6 :(得分:-1)
C#实现了扩展方法,因为它缺少第一类函数,Python有它们,并且它是&#34;包装&#34;的首选方法。 Python中不同类的通用功能。
有充分的理由相信Python永远不会有扩展方法,只需查看可用的内置插件:
len(o) calls o.__len__
iter(o) calls o.__iter__
next(o) calls o.next
format(o, s) calls o.__format__(s)
基本上,Python 喜欢功能。
答案 7 :(得分:-10)
一周后,我有一个最接近我所寻求的解决方案。解决方案包括使用getattr
和__getattr__
。以下是感兴趣的人的一个例子。
class myClass:
def __init__(self): pass
def __getattr__(self, attr):
try:
methodToCall = getattr(myClass, attr)
return methodToCall(myClass(), self)
except:
pass
def firstChild(self, node):
# bla bla bla
def lastChild(self, node):
# bla bla bla
x = myClass()
div = x.getMYDiv()
y = div.firstChild.lastChild
我没有测试这个例子,我只是想让它知道谁可能会感兴趣。希望有所帮助。