методы расширения Python - PullRequest
       2

методы расширения Python

20 голосов
/ 21 августа 2011

ОК, в 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

Есть предложения?

Ответы [ 5 ]

18 голосов
/ 21 августа 2011

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

def MyMethod(self):
      return self + self

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

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

Обновление

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

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

3 голосов
/ 20 ноября 2015

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

Но для установки запрещенных фруктов требуется компилятор 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()
0 голосов
/ 28 августа 2015

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

0 голосов
/ 26 августа 2011

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

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

0 голосов
/ 21 августа 2011

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

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