2014-01-12 3 views
3

Это то, что я хочу сделать:Элемент-член (в отличие от переменной-члена) класса?

obj = object() 
obj.(a,b,c) = 1,2,3 
f(obj.(d,e)) 

Это то, что я знаю, как это сделать:

obj = object() 
obj.a, obj.b, obj.c = 1,2,3 

Есть ли синтаксис, чтобы сделать это в Python?

Последующие вопросы:

  • Было ли это предложенные и отклоненные?
  • Существуют ли языки программирования с таким синтаксическим сахаром (ссылка на элемент по кортежу)?

(«Почему вы хотите это сделать?», Потому что мне кажется, что мне кажется, что иногда существуют группы переменных-членов как пакет. Существуют классы, для которых это имеет смысл, как фиксированная размерная точка или комплексное число)

+1

Я не думаю, что любое количество взлома '__getattr__' или' __getattribute__' вы можете получить это, потому что это против грамматики. – wim

ответ

0

На основе sweeneyrod Ответ, я написал способ иметь несколько схожий синтаксис, используя строку с разделителями-запятыми и квадратные скобки.Использование:

thing = myclass() 
thing['x,y'] = 3,6 
x,y = thing['x,y'] 
thing['x,y,z'] = 1,2,3 

Это дает

>>> x 
3 
>>> y 
6 
>>> thing.x 
1 
>>> thing.z 
3 

определение класса:

#user class 
class myclass: 
    def __getitem__(self,keys): 
     keys = keys.split(',') 
     return tuple(getattr(self, attr) for attr in keys) 

    def __setitem__(self,keys,values): 
     keys = keys.split(',') 
     if len(keys) != len(values): 
      raise ValueError('too many values to unpack (expected %d)'%len(keys)) 
     for attr,val in zip(keys, values): 
      setattr(self, attr, val) 
    def __delitem__(self,keys): 
     keys = keys.split(',') 
     for attr in keys: 
      delattr(self, attr) 

вопросы:

  • перекрывается с __getitem__, если вам это нужно.
  • Не исключение безопасного (может __setattr__ бросить исключение?)

Первоначально я думал использовать thing.grouping('x,y')=3,6, но я забыл, что я не могу назначить вызов функции.


декоратор версия:

try: 
    from itertools import izip as zip #python 2 
except: 
    pass #python 3 already has zip 

#decorator 
def attribute_tuple(cls): 

    if not hasattr(attribute_tuple,'initialized'): 
     attribute_tuple.initialized=True 
     def get(self,keys): 
      keys = keys.split(',') 
      return tuple(getattr(self, attr) for attr in keys) 
     attribute_tuple.get = get 
     def set(self,keys,values): 
      keys = keys.split(',') 
      if len(keys) != len(values): 
       raise ValueError('too many values to unpack (expected %d)'%len(keys)) 
      for attr,val in zip(keys, values): 
       setattr(self, attr, val) 
     attribute_tuple.set = set 
     def delete(self,keys): 
      keys = keys.split(',') 
      for attr in keys: 
       delattr(self, attr) 
     attribute_tuple.delete = delete 

    cls.__getitem__ = attribute_tuple.get 
    cls.__setitem__ = attribute_tuple.set 
    cls.__delitem__ = attribute_tuple.delete 

    return cls 

@attribute_tuple 
class myclass: 
    pass 
3

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

class Thing: 
    def __init__(self, x, y): 
     self.point = (x, y) 
    def __getattr__(self, name): 
     if name == "x": 
      return self.point[0] 
     elif name == "y": 
      return self.point[1] 
     else: 
      raise AttributeError 
    def __setattr__(self, name, value): 
     if name == "x": 
      self.point = (value, self.point[1]) 
     elif name == "y": 
      self.point = (self.point[0], value) 
     else: 
      object.__setattr__(self, name, value) 

thing = Thing(4, 7) 
thing.point = (3, 6) 
thing.x = 5 
+1

Единственная проблема заключается в том, что для групп требуются имена, что означает, что вы не можете выполнять группировки «на лету». Твист на этом: 'thing.grouping ('x', 'y', 'z') = 1,2,3', где" группировка "возвращает объект с переопределенным' __setattr__' и содержит ссылку на оригинал объект, затем устанавливает элементы один за другим. Вот как я это написал: http://pastebin.com/Zy2pKxz5 – leewz

+0

Любая причина для downvote? – rlms

+0

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

0

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

class MyClass: 
    pass 

def set_tuple(obj, **attrs): 
    for key in attrs: 
     setattr(obj, key, attrs[key]) 

def pass_tuple(obj, *attrnames): 
    return (getattr(obj, x) for x in attrnames) 

def print_things(*iterable): 
    for x in iterable: 
     print(x) 

obj = MyClass() 
set_tuple(obj, a=1, b=2, c=3) 
print(obj.a, obj.b, obj.c, '\n') 
print_things(*pass_tuple(obj, 'a', 'c')) 

Результат:

1 2 3 

1 
3 
1

Это не представляется возможным из-за grammar of attribute references.

Ссылка на атрибут является первичным последующим периодом и имя:

attributeref ::= primary "." identifier 

И identifier должны начинаться с буквы, а не круглые скобки.

Идентификаторы (называемые также имена) описываются следующими лексических определений:

identifier ::= (letter|"_") (letter | digit | "_")* 
letter  ::= lowercase | uppercase 
lowercase ::= "a"..."z" 
uppercase ::= "A"..."Z" 
digit  ::= "0"..."9" 

Это означает, что вы получите SyntaxError независимо от того, сколько взлома вы делаете на __getattr__ и/или __getattribute__.

Смежные вопросы