Python setter不适用于实例化?



我正在尝试制作一个程序,允许您对某些用户定义的分子进行各种形式的化学分析。到目前为止,我已经定义了一个带有坐标属性的Molecule对象。我设置它是为了在用户将坐标属性设置为描述分子的列表时生成某种Atom对象。但是,当我在分子对象实例化之后重置坐标属性时,它只对应于一个原子对象列表。当我在对象实例化时传递坐标列表时,属性仍然是字符串列表(与输入相同),并且不响应相应的原子对象列表。对应的代码是,

periodic_table = {
'H': {'Z': 1.008, 'nelec': 1},
'C': {'Z': 12.011, 'nelec': 6},
'N': {'Z': 14.007, 'nelec': 7},
'O': {'Z': 15.999, 'nelec': 8},
'S': {'Z': 32.06, 'nelec': 16},
'Br': {'Z': 79.904, 'nelec': 35},
'I': {'Z': 126.90, 'nelec': 53}
}


class Atom:
def __init__(self, label: str, vector: list):
self.__label = label
self.vector = vector
self.__lookup_info()

def __lookup_info(self):
atom_info = periodic_table[self.__label]
self.__Z = atom_info['Z']
self.__nelec = atom_info['nelec']
@property
def label(self):
return self.__label
@label.setter
def label(self, value):
if type(value) != str:
raise Exception("Atomic labels must be a string")
else:
value = value.upper()
self.__label = value
self.__lookup_info()
# lookup info and set z/nelec
@property
def Z(self):
return self.__Z
@property
def nelec(self):
return self.__nelec

class Molecule(object):
def __init__(self, coordinates=None):
self.__coordinates = coordinates
self.nelec = None
self.Z = None
self.natom = None
@property
def coordinates(self):
return self.__coordinates
@coordinates.setter
def coordinates(self, coords: list):
depth = lambda l: isinstance(l, list) and max(map(depth, l)) + 1
if depth(coords) != 2:
raise Exception("Coordinates must be provided as a nested list of depth 2")
else:
atom_list = []
for atom_coord in coords:
print("Test")
atom_coord = self.__check_coord(atom_coord)
atom_label, atom_vec = atom_coord[0], atom_coord[1:]
atom_list.append(Atom(atom_label, atom_vec))
self.__coordinates = atom_list
@staticmethod
def __check_coord(coord):
isnumber = lambda x: (type(x) == float or type(x) == int)
if type(coord[0]) != str:
raise Exception("First element must a string for an atomic label")
if len(list(filter(isnumber, coord))) != 3 and len(coord) != 4:
raise Exception("Each coordinate must be a list of length 4 with 1 string and 3 numbers")
coord[0] = coord[0].upper()
return coord

生成以下输出,

>>> mol = Molecule([['H', 0, 1, 1], ['O', -1, 0, 0], ['H', -1, 0, 1]])
>>> mol.coordinates
[['H', 0, 1, 1], ['O', -1, 0, 0], ['H', -1, 0, 1]]
>>> mol2 = Molecule()
>>> mol2.coordinates =[['H', 0, 1, 1], ['O', -1, 0, 0], ['H', -1, 0, 1]]
Test
>>> mol2.coordinates
[<__main__.Atom object at 0x10c62c850>, <__main__.Atom object at 0x10c62c640>, <__main__.Atom object at 0x10c62c910>]

我怎样才能实现在对象的init上传递列表的情况下的行为,或者当协调属性设置之后,坐标被设置为原子对象的列表?

当你做self.__coordinates = coordinates时你直接设置__coordinates,你不调用setter

Molecule.__init__()应该看起来像

def __init__(self, coordinates=None):
if coordinates is not None:
self.coordinates = coordinates
self.nelec = None
self.Z = None
self.natom = None

同样适用于其他设置了"内部"直接

属性作为旁注,可能您想使用单下划线,意思是"内部使用",而不是双下划线。还有其他我想重构的东西,例如lambda函数的使用,你提出的一般Exception,等等。

最新更新