这是一个关于python语法的有趣问题。
当我从matlab转到python时,我创建了一个类,其工作原理与matlab的struct
相似。class DynStruct(AbstractPrintable):
' dynamical add and remove members '
def __init__(self, child_exclude_list=[]):
super(DynStruct, self).__init__(child_exclude_list)
它只是一个对象,您可以动态地添加成员,而不必这样做求助于字典(因为我讨厌键入引号)
我还制作了一个很酷的助手类,它可以很好地打印出类的成员,以便您可以看看你在用python工作时都在做些什么。(我省略了我的导入,但它只是一些标准的东西以及一些numpy)
class AbstractPrintable(object):
'A base class that prints its attributes instead of the memory address'
def __init__(self, child_print_exclude=[]):
self._printable_exclude = ['_printable_exclude'] + child_print_exclude
def __str__(self):
head = printableType(self)
body = self.printable_attributes()
body = re.sub('n *n *n','nn',body)
return head+('n'+body).replace('n','n ')
def printable_attributes(self, type_bit=True):
body = ''
attri_list = []
for key in self.__dict__.iterkeys():
if key in self._printable_exclude: continue
val = self.__dict__[key]
namestr = str(key)
valstr = printableVal(val)
typestr = printableType(val)
max_valstr = 10000
if len(valstr) > max_valstr:
valstr = valstr[0:max_valstr/2]+valstr[-max_valstr/2:-1]
attri_list.append( (typestr, namestr, valstr) )
attri_list.sort()
for (typestr, namestr, valstr) in attri_list:
entrytail = 'n' if valstr.count('n') <= 1 else 'nn'
typestr2 = typestr+' ' if type_bit else ''
body += typestr2 + namestr + ' = ' + valstr + entrytail
return body
#---------------
def printableType(val):
if type(val) == numpy.ndarray:
info = npArrInfo(val)
_typestr = info.dtypestr
elif isinstance(val, object):
_typestr = val.__class__.__name__
else:
_typestr = str(type(val))
_typestr = _typestr.replace('type','')
_typestr = re.sub('['><]','',_typestr)
_typestr = re.sub(' *',' ',_typestr)
_typestr = _typestr.strip()
return _typestr
然后我有一个情况,我需要从我的DynStruct中获得一堆元素,所以我添加了一个函数,它返回我想要的元素元组。
# I added this function to DynStruct
def getprops(self, *prop_list):
return tuple([self.__dict__[prop_name] for prop_name in prop_list])
,
>> point = DynStruct()
>> point.x = 3
>> point.y = 1
>> point.z = 60
>> print point
DynStruct
int x = 3
int y = 1
int z = 60
>> # Now I want to get the points
>> (x,y,z) = point.getprops('x','y','z')
现在,这工作得很好,它使调试非常容易。但我遇到了一个情况,我想一次设置一堆属性(有点像上面)。我知道还有其他方法可以做到这一点,但我真的希望有一个setprop,语法是这样的:
point.setprops('x','y','z') = (14, 22, 30)
我不确定,但我觉得可能有一种方法可以做到这一点,因为@someobj。setter装饰。但我不知道如何重载等号操作符以这种方式使用它,或者它是否可能。
我想在此期间我就这样写吧点。Setprops ('x','y','z', 14,22,30)
马上,你就不需要这个了——因为你可以这样做:
point.x, point.y, point.z = (14, 22, 30)
# Tuple unpacking ... is there nothing it cannot do?
然而,假设这还不够清楚,您确实需要能够一次设置多个字段。然后可以使用__setitem__
:
def __setitem__(self, key, value):
if isinstance(key, tuple):
for k, v in zip(key, value):
setattr(self, k, v)
else:
setattr(self, key, value)
那么你可以这样做:
point['x', 'y', 'z'] = (14, 22, 30)
然后你也可以用__getitem__
方法替换你的getprops
方法,类似地实现,并且能够做:
x, y, z = point['x', 'y', 'z']
也许我在你的解释中遗漏了什么,但是你不能已经这样做了吗?例如它只是一个对象,你可以动态地添加成员,而不必诉诸字典(因为我讨厌键入引号)
class Foo(Object):
def __init__(self):
pass
f = Foo()
f.x = 1
f.y = 2
f.z = 3
print f.x, f.y, f.z # outputs 1 2 3
关于你问题的第二部分,关于获得这种语法,
point.setprops('x','y','z') = (14, 22, 30)
不幸的是,我不确定这是否可能。原因是
point.setprops('x', 'y', 'z')
是一个'call'表达式。由于python的解析方式,我认为你不能在赋值语句的左边有一个调用表达式。据我所知,您只能有一个变量名列表或切片/索引表达式。话虽如此,我也不是百分百确定。也许你可以做一些疯狂的蟒蛇忍者的事情来实现它。