где декоратор instancemethod?

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

class MyClass:
  def fun( self, *args ): # the method
    return Props( self, *args )

class Props: # the returned object
  def __init__( self, parent, *args ):
    self.parent = parent
    self.args = args

Чтобы все было организовано, я рассматриваю возможность размещения реквизита внутри MyClass. Затем я хотел бы обойти веселье и напрямую сделать класс методом экземпляра MyClass, например:

class MyClass:
  @instancemethod # does not exist!
  class fun:
    def __init__( self, parent, *args ):
      self.parent = parent
      self.args = args

Обратите внимание на комментарий - декоратор instancemethod не существует.

Есть ли способ сделать это, то есть превратить вызываемый объект в метод экземпляра? Если я изменю @instancemethod на @classmethod, конструкция сработает, за исключением того, что родителем является класс, а не экземпляр. Я удивлен, что не могу найти ничего о том, что кажется противоположной операцией.

Любопытно, что это прояснилось!

Редактировать:

Кажется, мой вопрос был не ясен. У меня есть забавная функция-член, которая возвращает не одно значение или кортеж, а объект, полный данных. Эти данные генерируются на основе содержимого объекта MyClass и аргументов функции. Мой исходный код делает именно то, что я хочу. Второй код - это то, как я бы предпочел его написать.

Более того, я заметил, что декоратор, которого я ищу, просто следующий:

def instancemethod( cls ):
  def f( *args ):
    return cls( *args )
  return f

Это, конечно, идентично «забавному» методу, который я стремился обойти. Обратите также внимание на то, что тривиальный 'return cls' не идентичен, хотя на первый взгляд может показаться, что это так.

С этим декоратором мое второе определение класса является допустимым и дает желаемый результат, а именно, a.fun() возвращает объект, который (потенциально) инициализируется на основе данных в a:

a = MyClass()
p = a.fun(1,2,3)

print a        # <__main__.MyClass instance at 0xb775b84c>
print p.parent # <__main__.MyClass instance at 0xb775b84c>
print p.args   # (1, 2, 3)

Это по-прежнему оставляет меня с вопросом, не доступен ли метод экземпляра, определенный здесь, как встроенный в python, потому что это кажется упущением рядом с методом класса и статическим методом. Но, если нет, я думаю, я могу жить с этой конструкцией.


person gertjan    schedule 12.04.2011    source источник
comment
вызываемый объект должен реализовывать метод __call__   -  person Andrey Sboev    schedule 12.04.2011
comment
первый фрагмент кода выглядит более организованным. Просто переместите Proops определение класса внутрь fun тела функции   -  person Andrey Sboev    schedule 12.04.2011


Ответы (3)


Я точно не знаю, что вы пытаетесь сделать, но подозреваю, что вы хотите прочитать дескрипторы.

По сути, дескриптор — это атрибут класса, который сам является классом, определяющим методы __get__ и __set__. В вашем случае вы можете переместить код из Props.__init__ в Props.__set__, установить Props в качестве атрибута fun класса, и все должно работать так, как вы хотите.

person Daniel Roseman    schedule 12.04.2011
comment
Спасибо, но я не думаю, что дескрипторы решают мою проблему. Я хочу создать функцию, которая возвращает объект на основе объекта MyClass и аргументов. Насколько я могу судить, дескрипторы не могут работать с аргументами, поскольку ведут себя как атрибуты. Пожалуйста, поправьте меня, если я ошибаюсь. Я обновил свой вопрос, чтобы лучше объяснить, что я собираюсь сделать, и предложил конкретный декоратор, который я надеялся найти в качестве встроенного в Python. - person gertjan; 12.04.2011
comment
@gertjan: метод Descriptors может принимать аргументы. Установка, получение, удаление атрибутов полностью настраиваются через них. - person XORcist; 12.04.2011
comment
möter: Боюсь, я не понимаю, как с помощью дескрипторов добиться желаемого поведения, но мне любопытно. Не могли бы вы опубликовать предложенный вами код, который воспроизводит пример в моем обновленном сообщении? - person gertjan; 13.04.2011

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

IIUC, вы собираетесь сделать что-то вроде:

class SomeClass:
    # typical stuff
    def __init__(self, other, arg1, arg2, arg3, arg4):
        self.parent= other
        # blah blah

class SomeOtherClass:
    # initialize in __init__, setup stuff
    def __init__(self, initarg1, initarg2):
        self.initarg1= initarg1
        self.initarg2= initarg2

    def fun(self, arg3, arg4):
        # return an instance of SomeClass based on
        # initargs and arguments
        return SomeClass(self, self.initarg1, self.initarg2, arg3, arg4)
person tzot    schedule 05.05.2011

Вам не нужен декоратор instancemethod, это может сработать:

class MyClass:
  class fun:
    def __init__( self, parent, *args ):
      self.parent = parent
      self.args = args

m = MyClass()
f = m.fun(None, 1, 2, 3)
print f.args

Вы также можете изменить свой первый пример на

class Props:
    def __init__( self, parent, *args ):
        self.parent = parent
        self.args = args


class MyClass:
    fun = Props

m = MyClass()
f = m.fun(None, 1, 2, 3)
print f.args
person nitrogenycs    schedule 12.04.2011
comment
Спасибо, но боюсь, что так не пойдет, мне специально нужно, чтобы f.parent был m, а не None. Я хочу вызвать m.fun(1,2,3) и передать python m в качестве первого аргумента, как в моем примере. Пример урезан, на самом деле я бы использовал родителя для вычисления реальных свойств. - person gertjan; 12.04.2011