Можете ли вы изменить метод __get__ дескриптора Python во время выполнения? - PullRequest
3 голосов
/ 29 февраля 2012

Все, как и спрашивает заголовок, возможно ли изменить метод дескриптора __get__ во время выполнения.Я нахожусь в ситуации, когда у меня есть функция, которая украшается и украшается на лету во время выполнения.Я бы хотел, чтобы результат этой функции был доступен как атрибут, аналогичный тому, что делает @property.Я исследовал это и обнаружил, что это дескриптор, но кажется, что метод дескрипторов __get__ предназначен только для чтения.

class Test( object ):
    def __init__( self ):
        self._x = 10

    def get_x( self ):
        return self._x

    @property
    def x( self ):
        return self.get_x()

Приведенный выше код делает то, что я хочу, примерно, в этом

  1. Значение устанавливается в конструкторе
  2. Я могу украсить get_xМетод к моему сердцу
  3. instance.x возвращает правильное значение

Моя проблема в том, что я бы предпочел не создавать метод get_x, так как он в принципе не нужен.Я просто не смог украсить __get__ метод x, поскольку он доступен только для чтения.

Фон

Я пишу пошаговую стратегическую игру и использую декораторы для реализации постоянных условий.Я могу эффективно реализовать эти декораторы при использовании тестовых случаев, но проблема в том, что для получения вычисленного значения необходимо использовать вызов функции, а не доступ к атрибуту.Это кажется плохой идеей, потому что получение значений, описывающих единицу, непоследовательно использует функции или атрибуты.Я бы хотел стандартизировать атрибуты, если смогу.

1 Ответ

4 голосов
/ 29 февраля 2012

Вы можете переопределить стандартную характеристику «только для чтения» атрибута property __get__, используя простое наследование:

class MyProperty( property ): pass

class Test( object ):
    def __init__( self ):
        self._x = 10

    def get_x( self ):
        return self._x

    @MyProperty
    def x( self ):
        return self.get_x()

test = Test()

Проблема теперь в том, что даже если вы переопределите __get__ атрибут вашегоСвойство Text.x, для test.x запроса Python во время выполнения вызовет MyProperty.__get__(Test.x, test, Test)

Так что вы можете переписать его только там, как

MyProperty.__get__ = lambda self,instance,owner: ""the x attribute"

Так что хороший вариант здесь - делегировать вызов некоторымredifineable атрибут, такой как

MyProperty.__get__ = lambda self,instance,owner: self.get(instance,owner)

Отныне получите атрибут вашей собственности под вашим полным контролем.Также есть плохая опция для генерации отдельного типа для каждого объекта, похожего на свойство.Так что в хорошем случае вы можете сделать что-то вроде:

class MyProperty( property ):
    def __get__(self,instance,owner) :
        if not instance: return self
        else: return self.get(instance,owner)

class Test( object ):
    def __init__( self ):
        self._x = 10

    def get_x( self ):
        return self._x

    @MyProperty
    def x( self ): pass

    @MyProperty
    def y(self): pass

    x.get = lambda self,clazz: self.get_x()
    y.get = lambda self,clazz: "the y property of " + clazz.__name__ + " object"

>>> test = Test()
>>> test.x
10
>>> test.y
'the y property of Test object'
...