Как реализовать подметод в Python-классе? - PullRequest
0 голосов
/ 31 декабря 2011

Я прошу прощения, если я не выразил себя ясно.То, что я хочу сделать, это:

class someClass(object):
    def aMethod(self, argument):
        return some_data #for example a list or a more complex datastructure
    def aMethod_max(self, argument):
        var = self.aMethod(argument)
        #do someting with var
        return altered_var    

или я мог бы сделать:

    def aMethod(self, argument):
        self.someVar = some_data
        return some_data #for example a list or a more complex datastructure
    def aMethod_max(self, argument):
        if not hasattr(self, someVar):
            self.aMethod(argument)        
        #do someting with self.var
        return altered_var

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

Поэтому я фантазировал о чем-то похожем в следующем абзаце.

Foo.someMethod(argument).subMethod()

Как бы я сделал что-то подобное в Python?

РЕДАКТИРОВАТЬ: или как это?

subMethod(self):
    var = self.someMethod()
    return doSomething(var)

Ответы [ 5 ]

2 голосов
/ 31 декабря 2011

Давайте сравним существующие решения, уже приведенные в вашем вопросе (например, те, которые вы называете "сложными" и "не элегантными"), с предложенной вами альтернативой.

Существующие решения означают, что вы сможете написать:

foo.subMethod() # foo.someMethod() is called internally

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

foo.someMethod().subMethod()

что явно хуже.

С другой стороны, если subMethod должен иметь возможность изменять результат любого метода, а не просто someMethod, то существующие решения означают, что вы должны написать:

foo.subMethod(foo.anyMethod())

с единственным недостатком в том, что вы должны набрать foo дважды, а не один раз.

Вывод: в целом, существующие решения менее сложны и не элегантны, чем предлагаемая вами альтернатива, поэтому придерживайтесь существующих решений.

1 голос
/ 31 декабря 2011

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

def on_result(f):
    def decorated(self,other,*args,**kwargs):
        result = getattr(self,other)(*args,**kwargs)
        return f(result)
    return decorated

Использование:

class someClass(object):
    def someMethod(self,x,y):
        #doSomething
        result = [1,2,3,x,y] # example
        return result
    @on_result
    def subMethod(self):
        #doSomething with the result of someMethod
        print self # example

Foo = someClass()
Foo.subMethod("someMethod",4,5)

Выход:

[1, 2, 3, 4, 5]

Как видите, первый аргумент - это имя метода, который должен быть объединен в цепочку, а остальные будут переданы ему независимо от его сигнатуры.

РЕДАКТИРОВАТЬ: если подумать, это довольно бессмысленно, поскольку вы всегда можете использовать

Foo.submethod(Foo.someMethod(4,5))...

Может быть, я не понял, чего вы пытаетесь достичь. Нужно ли подключать подметод только к специфическому методу? Или, может быть, это синтетическая форма

a.b().c()

это важно для тебя? (в этом случае см. ответ Кодзиро)

1 голос
/ 31 декабря 2011

Не уверен, правильно ли я понимаю, но, возможно, вы имеете в виду следующее:

Foo.subMethod(Foo.someMethod())

Это передает результат someMethod () в subMethod (). Вам нужно изменить текущее определение subMethod (), чтобы принять результат someMethod ().

1 голос
/ 31 декабря 2011

Вы можете создать метод цепочки , когда результатом someMethod является экземпляр someClass.

Простой пример:

>>> class someClass:
...   def someMethod(self):
...     return self
...   def subMethod(self):
...     return self.__class__
... 
>>> x=someClass()
>>> x
<__main__.someClass instance at 0x2aaaaab30d40>
>>> x.someMethod().subMethod()
<class __main__.someClass at 0x2aaaaab31050>
0 голосов
/ 31 декабря 2011

Из отзывов пока я понимаю, что subMethod свяжет только с someMethod , верно? Может быть, вы можете достичь этого, комбинируя декоратор с закрытием:

def on_result(other):
    def decorator(f):
        def decorated(self,*a1,**k1):
            def closure(*a2,**k2):
                return f(self,getattr(self,other)(*a1,**k1),*a2,**k2)
            return closure
        return decorated
    return decorator

class someClass(object):
    def someMethod(self,a,b):
        return [a,2*b]
    @on_result('someMethod')
    def subMethod(self,result,c,d):
        result.extend([3*c,4*d])
        return result

Foo = someClass()
print Foo.subMethod(1,2)(3,4) # prints [1,4,9,16]

Декоратор вроде "некрасивый", но как только он написан, его использование довольно элегантно, ИМХО (плюс, в сигнатуре обоих методов нет никаких ограничений).

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...