2013-07-26 3 views
1

У меня есть класс с пользовательским getter, поэтому у меня есть ситуации, когда мне нужно использовать мой пользовательский getter и ситуации, когда мне нужно использовать default.Как узнать, какой следующий атрибут запрашивается в python

Так что подумайте о нижеследующем.

Если я вызываю метод объекта с таким образом:

c.somePyClassProp 

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

c.somePyClassProp.getAttributes() 

В этом случае мне нужно использовать по умолчанию сеттера, и первый возврат должен быть объектом Python, а затем нам нужно вызвать метод GetAttributes возвращенного объекта питона (от c.somePyClassProp). Обратите внимание, что somePyClassProp на самом деле является свойством класса, который является другим экземпляром класса Python.

Итак, есть ли какой-либо способ в Python, на котором мы можем знать, будут ли вызываться какие-либо другие методы после вызова первого метода?

+1

Единственный возможный способ сделать то, что вы хотите сделать 'c.somePyClassProp' возвращает объект, который сочетает в себе (часть или все) из двух интерфейсов, которые вы хотите. То есть, вам нужно, чтобы это было что-то похожее на 'int', но также имело метод getAttributes. Если вам это нужно, чтобы иметь возможность сделать что-то нетривиальное, это будет грязно и сложно. Вы уверены, что не можете использовать другой метод или имя свойства для разделения двух видов использования? – Blckknght

+0

Ответ Kindall кажется лучшим, но только если вы в порядке с объектом, который ведет себя как int во всех контекстах ** кроме ** он также поддерживает метод getAttributes. –

ответ

3

Вы не хотите возвращать разные значения, на основании которых доступен атрибут дальше, вы хотите, чтобы вернуть объект int -like, что также имеет необходимый атрибут на нем. Для этого мы создаем подкласс int, который имеет метод getAttributes(). Экземпляр этого класса, конечно, должен знать, к какому объекту он привязан, то есть к какому объекту относится его метод getAttributes(), поэтому мы добавим его в конструктор.

class bound_int(int): 
    def __new__(cls, value, obj): 
     val = int.__new__(cls, value) 
     val.obj = obj 
     return val 
    def getAttributes(self): 
     return self.obj.somePyClassProp 

Теперь в вашем геттер для c.somePyClassProp, вместо того, чтобы возвратить целое, вы возвращаете bound_int и передать ему ссылку на объект его метод getAttributes() должен знать о (здесь я просто буду отнести его к self объект он возвращается из):

@property 
def somePyClassProp(self): 
    return bound_int(42, self) 

Таким образом, если вы используете c.somePyPclassProp как int, он действует точно так же, как и любой другой int, потому что это один, но если вы хотите в дальнейшем называть getAttributes() на нем , вы тоже можете это сделать. В обоих случаях это одно и то же значение; он просто построен для выполнения обеих целей. Этот подход может быть адаптирован к почти любой проблеме этого типа.

+0

Хотя это технически работает, это ужасно запутанно. «Bound_int» со значением int 3 будет печататься как «3» и выглядит почти так же, как реальный «3», но он не будет проверять «тип» и вызывать утечку памяти, если «bound_int» хранится дольше, чем объект, из которого он был создан. Вы не хотите отлаживать утечку памяти, вызванную чем-то вроде '3'. – user2357112

+0

Он передает проверки типа, если вы делаете их правильно, т. Е. С помощью 'issubclass()'. Ваша другая проблема, в то время как технически не является утечкой памяти, является хорошей точкой и чем-то, что нужно знать, если объект, на который ссылается, является большим. Есть много обстоятельств, когда 'bound_int' полностью уйдет, предотвращая эту проблему, но есть множество других обстоятельств, когда это не так. – kindall

+0

Вы можете использовать 'weakref.ref' для хранения ссылки на другой объект, чтобы не заставлять его зависнуть в памяти после того, как в противном случае это необходимо. – kindall

4

c.someMethod - самодостаточное выражение; на его оценку не может влиять контекст, в котором будет использоваться результат. Если бы вы могли достичь того, чего хотите, это было бы результатом:

x = c.someMethod 
c.someMethod.getAttributes() # Works! 
x.getAttributes()   # AttributeError! 

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

Не пытайтесь делать c.someMethod вести себя по-разному в зависимости от того, что с ним будет сделано, и если это возможно, не делайте вызова метода вообще. Люди ожидают, что c.someMethod вернет объект связанного метода, который затем можно вызвать для выполнения метода; просто def ine метод обычным способом и назовите его c.someMethod().

+0

Tnx на ваш ответ. На самом деле в моем случае «someMethod» не является методом, это другой класс Python, поэтому я отредактирую свой вопрос – user232343

0

Похоже, вы хотите получить два способа получить свойство в зависимости от того, что вы хотите с ним делать. Я не думаю, что есть какой-либо встроенный Pythonic способ реализовать это, и поэтому вам нужно сохранить имя переменной или свойства для каждого случая. Может быть:

c.somePyClassProp 

могут быть использованы в __get__ и c.somePyClassProp__getAttributes() могут быть реализованы в более Выборочный внутри функции __getattribute__.

Один из способов я использовал (который, вероятно, не лучший), чтобы проверить, что точное имя переменной:

def __getattribute__(self, var_name): 
    if ('__' in var_name): 
     var_name, method = var_name.split('__') 
    return object.__getattribute__(self, var_name).__getattribute__(method) 

Использование object.__get__(self, var_name) использует метод класса объектного получения собственности напрямую.

+0

Извините, что это был целый беспорядок, следует использовать метод '__getattribute__'. – smakateer

0

Вы можете сохранить содержащий объект python как переменную и создать получатели с помощью dectorator @property для любых значений, которые вы хотите. Когда вы хотите прочитать int, обратитесь к свойству. Если вы хотите, чтобы объект содержал, вместо него используйте его имя переменной.

class SomePyClass(object): 
    def getInt(self): 
     return 1 
    def getAttributes(self): 
     return 'a b c' 

class MyClass(object): 

    def __init__(self, py_class): 
     self._py_class = py_class 

    @property 
    def some_property(self): 
     return self._py_class.getInt() 

x = MyClass(SomePyClass()) 
y = self.some_property 
x._py_class.getAttributes() 
Смежные вопросы