[英]Problem creating new distinct class instance in python 2.7
我有一個本質上應該能夠初始化自身以及基於一行文本(字符串)設置內部值的類。 這在創建單個實例時似乎很好用,但是,在創建第二個實例時,饋入第一個實例的文本行顯然會饋入第二個實例的內部變量之一! 該類的init構造函數使用所有相關參數的默認值定義,這些默認參數將傳遞給相應的內部變量。 具體來說,“ prefixComments”參數的默認設置為[],這意味着“ self.PrefixComments”應設置為相同的內容(一個空列表)……不幸的是,顯然它已被設置為文本行用於創建先前的對象(或者至少是我的最佳猜測)。
我真的對這里發生的事情感到困惑。 關於如何解決它的任何想法。 代碼和輸出如下:
碼:
import collections
from collections import OrderedDict
import numpy as np
import string
import re
import gc
class AtomEntry:
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=prefixComments
def from_line_string(self,line):
#returns 1 if an error is encountered, 0 if successful
lineTokens=line.split()
if len(lineTokens)<4:
print("Error: too few entries to construct ATOM record")
return(1)
elif lineTokens[0] != "ATOM":
print("ERROR: atom entries must begin with the keyword 'ATOM'")
return(1)
else:
self.Name=lineTokens[1]
self.Type=lineTokens[2]
self.Charge=float(lineTokens[3])
if len(lineTokens) >=5:
self.Comment=string.replace(
s=' '.join(lineTokens[5:len(lineTokens)]),
old='!',new='')
return(0)
def to_str(self,nameOnly=False):
if nameOnly:
return "%s"%(self.Name)
else:
return repr(self)
def __repr__(self):
outStrs=self.PrefixComments
outStrs.append(
"ATOM %6s %6s %6.3f !%s"%(
self.Name,self.Type,self.Charge,self.Comment))
return ''.join(outStrs)
tempAtom1=AtomEntry()
tempAtom1.from_line_string("ATOM S1 SG2R50 -0.067 ! 93.531")
print tempAtom1
print ""
gc.collect()
tempAtom2=AtomEntry()
tempAtom2.from_line_string("ATOM C1 CG2R53 0.443 ! 83.436")
print tempAtom2
print""
print tempAtom2.Name
print tempAtom2.Type
print tempAtom2.Charge
print tempAtom2.Comment
print tempAtom2.PrefixComments
gc.collect()
輸出:
ATOM S1 SG2R50 -0.067 !93.531
ATOM S1 SG2R50 -0.067 !93.531ATOM C1 CG2R53 0.443 !83.436
C1
CG2R53
0.443
83.436
['ATOM S1 SG2R50 -0.067 !93.531', 'ATOM C1 CG2R53 0.443 !83.436']
您有兩個問題,都與重用list
有關。 一種,您對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__
大多數參數成為強制性的(除了comment
和prefixComment
之外,沒有默認值),因為其他三個屬性是必需的,並且您不再需要使空實例僅通過from_line_string
進行初始化。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.