Возвращение членов по умолчанию при доступе к объектам в Python - PullRequest
1 голос
/ 10 апреля 2009

Я пишу "среду", где каждая переменная состоит из значения и описания:

class my_var:
   def __init__(self, value, description):
      self.value = value
      self.description = description

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

my_dict["foo"] = my_var(0.5, "A foo var")

Это круто, но 99% операций с переменной выполняются с элементом value. Поэтому я должен написать так:

print my_dict["foo"].value + 15  # Prints 15.5

или

my_dict["foo"].value = 17

Мне бы хотелось, чтобы все операции над объектом my_dict ["foo"] могли по умолчанию принимать значение "value". Другими словами, я хотел бы написать:

print my_dict["foo"] + 15     # Prints 5.5

и все в таком духе.

Единственный способ, который я нашел, это переопределить все члены подчеркивания (например, add, str и т. Д.), Но я чувствую, что это неправильный путь. Есть ли магический метод, который я мог бы использовать?

Обходным решением было бы иметь больше словарей, например:

my_dict_value["foo"] = 0.5
my_dict_description["foo"] = "A foo var"

но мне не нравится это решение. У вас есть предложения?

Ответы [ 4 ]

3 голосов
/ 10 апреля 2009

Две общие заметки.

  1. Пожалуйста, используйте заглавные буквы для названий классов.

  2. Пожалуйста (если не используется Python 3.0) объект подкласса. class My_Var(object):, например.

Теперь к вашему вопросу.

Допустим, вы делаете

x= My_Var(0.5, "A foo var")

Как Python различает x, составной объект и значение x (x.value)?

Хотите ли вы следующее поведение?

  • Иногда x означает весь составной объект.

  • Иногда x означает x.value.

Как вы различаете эти два? Как вы скажете Python, что вы имеете в виду?

2 голосов
/ 10 апреля 2009

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

С учетом сказанного вы можете реализовать свой собственный класс dict:

class DescDict(dict):
    def __init__(self, *args, **kwargs):
        self.descs = {}
        dict.__init__(self)

    def __getitem__(self, name):
        return dict.__getitem__(self, name)

    def __setitem__(self, name, tup):
        value, description = tup
        self.descs[name] = description
        dict.__setitem__(self, name, value)

    def get_desc(self, name):
        return self.descs[name]

Вы бы использовали этот класс следующим образом:

my_dict = DescDict()
my_dict["foo"] = (0.5, "A foo var")  # just use a tuple if you only have 2 vals
print my_dict["foo"] + 15            # prints 15.5
print my_dict.get_desc("foo")        # prints 'A foo var'

Если вы решите пойти по волшебному пути поведения, то это должно стать хорошей отправной точкой.

2 голосов
/ 10 апреля 2009

Вы можете создать объект, который в основном действует как «значение», но имеет описание дополнительного атрибута, реализовав операторы в разделе «Эмуляция числовых типов», равном http://docs.python.org/reference/datamodel.html

class Fooness(object):
    def __init__(self,val, description):
        self._val = val
        self.description = description

    def __add__(self,other):
        return self._val + other

    def __sub__(self,other):
        return self._val - other

    def __mul__(self,other):
        return self._val * other

    # etc

    def __str__(self):
        return str(self._val)


f = Fooness(10,"my f'd up fooness")
b = f + 10
print 'b=',b
d = f - 7
print 'd=',d

print 'f.description=',f.description

Производит:

b= 20
d= 3
f.description= my f'd up fooness
1 голос
/ 10 апреля 2009

Я думаю, тот факт, что вам нужно проделать такую ​​большую работу, чтобы сделать причудливый ярлык, указывает на то, что вы идете против зерна. То, что вы делаете, нарушает LSP; это нелогично.

my_dict[k] = v;
print my_dict[k] == v # should be True

Даже два отдельных диктанта предпочтительнее, чем изменение значения диктата.

...