【发布时间】:2022-06-10 18:26:06
【问题描述】:
我正在尝试制作一个程序,允许您对某些用户定义的分子进行各种形式的化学分析。到目前为止,我已经定义了一个具有关联坐标属性的 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 上传递列表或在之后设置协调属性时将坐标设置为原子对象列表的行为?
【问题讨论】:
-
使用
ìsinstance进行类型检查 -
"Python 设置器不适用于实例化?"他们会这样做,但是您不会在
__init__的任何地方使用任何设置器,实际上,您似乎有意通过直接设置底层属性而不使用属性来避免它们。 -
所以我们很清楚:问题是为什么
__init__方法在它说self.__coordinates = coordinates的地方不使用属性coordinates来设置值,但是mol2.coordinates = ...的外部代码呢?可能是因为self.__coordinates的代码没有使用属性的名称,即coordinates,而不是__coordinates? -
另外:
None实际上是分子坐标的有效值吗?如果不是,在构造函数中将该参数设为可选的预期目标是什么?
标签: python python-3.x object oop instance