Методы расширения python

ОК, в С# у нас есть что-то вроде:

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

Любое предложение?

Ответы

Ответ 1

Через неделю у меня есть решение, которое ближе всего к тому, что я искал. Решение состоит из использования 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 

Я не тестировал этот пример, я просто дал ему понять, кто может быть заинтересован. Надеюсь, что это поможет.

Ответ 2

Вы можете просто изменить класс напрямую, иногда называемый патчем обезьян.

def MyMethod(self):
      return self + self

MyClass.MyMethod = MyMethod
del(MyMethod)#clean up namespace

Я не уверен на 100%, что вы можете сделать это на специальном классе, таком как str, но это отлично подходит для ваших пользовательских классов.

Обновление

В комментарии вы подтверждаете мое подозрение, что это невозможно для встроенной строки str. В этом случае я считаю, что аналогов методов расширения С# для таких классов нет.

Наконец, удобство этих методов, как в С#, так и в Python, сопряжено с риском. Использование этих методов может сделать код более сложным для понимания и поддержки.

Ответ 3

Вы можете изменить встроенные классы с помощью патчей обезьян с помощью запрещенных фруктов

Но для установки запрещенного плода требуется компилятор C и неограниченная среда, поэтому он, вероятно, не будет работать или потребует больших усилий для работы в Google App Engine, Heroku и т.д.

Я изменил поведение класса unicode в Python 2.7 для турецкой 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()

Ответ 4

Вы можете сделать то, что вы просили, например:

def extension_method(self):
    #do stuff
class.extension_method = extension_method

Ответ 5

С# реализованы методы расширения, поскольку в нем отсутствуют функции первого класса, у Python есть их, и это предпочтительный метод для "обертывания" общей функциональности в разных классах на 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 любит функции.