类的成员元组(而不是成员变量)?

时间:2014-01-12 17:29:19

标签: python

这就是我想要做的事情:

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中有没有这样做的语法?

后续问题:

  • 这是建议和拒绝的吗?
  • 是否有编程语言使用这种语法糖(元组成员参考)?

(“你为什么要这样做?”因为我有时候会直觉地将成员变量组视为一个包。有些类是有意义的,比如固定维度点,或者复数。)

4 个答案:

答案 0 :(得分: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 :(得分: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__

答案 2 :(得分: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

答案 3 :(得分: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