У вас есть две проблемы, связанные с повторным использованием list
s.Во-первых, вы использовали изменяемый аргумент по умолчанию для prefixComments
/ self.PrefixComments
. Не делай этого .Измените инициализатор на:
def __init__(self,atomName="",atomType="",charge=0.0,
comment="",prefixComments=(),
verbose=False):
self.Name=atomName
self.Type=atomType
self.Charge=charge
self.Comment=comment
self.PrefixComments = list(prefixComments)
, чтобы в первую очередь избежать получения изменяемого аргумента, и явно копировать его на новый list
, чтобы аргумент вызывающей стороны был не связан с атрибутом.
Во-вторых, ваш __repr__
изменяет этот атрибут, поэтому __repr__
не идемпотентен;он будет расти и расти каждый раз, когда вы его называете.Исправьте это тоже:
def __repr__(self):
outStrs=self.PrefixComments[:] # Shallow copy the l
outStrs.append(
"ATOM %6s %6s %6.3f !%s"%(
self.Name,self.Type,self.Charge,self.Comment))
return ''.join(outStrs)
Примечание: from_line_string
действительно должен быть альтернативным конструктором, так что вы можете напрямую использовать его для создания нового экземпляра из строки, а не делать пустой объект только дляпереинициализируйте его на следующей строке.Это легко исправить;просто измените его на classmethod
, который анализирует, затем вызывает обычный конструктор (и вызывает исключения при ошибках, вместо использования кодов возврата в стиле C, которые упрощают пропуск ошибок):
# Makes sure this works either on the class or an instance of the class
# as a constructor of a brand new instance
@classmethod
def from_line_string(cls, line):
# Returns a new instance, or raises an exception if an error is encountered
lineTokens = line.split()
if len(lineTokens) < 4:
raise ValueError("too few entries to construct ATOM record")
elif lineTokens[0] != "ATOM":
raise ValueError("atom entries must begin with the keyword 'ATOM'")
name=lineTokens[1]
type=lineTokens[2]
charge=float(lineTokens[3])
# This works fine, producing an empty string, even if lineTokens is
# doesn't have an index 5 or higher; comment will be the empty string
comment = ' '.join(lineTokens[5:]).replace('!', '')
return cls(name, type, charge, comment)
Это будетупростите использование с:
tempAtom1=AtomEntry()
tempAtom1.from_line_string("ATOM S1 SG2R50 -0.067 ! 93.531")
до:
tempAtom1 = AtomEntry.from_line_string("ATOM S1 SG2R50 -0.067 ! 93.531")
Возможно, вы также захотите сделать большинство аргументов для __init__
обязательными (без значений по умолчанию, кроме * 1031)* и prefixComment
), так как остальные три атрибута являются обязательными, и вам больше не нужно создавать пустые экземпляры только для их повторной инициализации с помощью from_line_string
.