我以爲我有一個與超級()的多重繼承的句柄,並試圖在Facade類中使用它,但我遇到了一個奇怪的錯誤。我使用了一個名爲Fireworks的製作良好的Python工作流程軟件,但類和工作流任務的結構非常僵硬,所以我創建了Facade類以便於使用。用Super創建適當的Python Facade類?
下面是工作流任務的基本結構:
class BgwInputTask(FireTaskBase):
required_params = ['structure', 'pseudo_dir', 'input_set_params', 'out_file']
optional_params = ['kpoints', 'qshift', 'mat_type']
def __init__(self, params):
self.structure = Structure.from_dict(params.get('structure').as_dict())
self.pseudo_dir = params.get('pseudo_dir')
self.kpoints = params.get('kpoints', None)
self.qshift = params.get('qshift', None)
self.isp = params.get('input_set_params')
self.run_type = params.get('run_type', None)
self.mat_type = params.get('mat_type', 'metal')
self.filename = params.get('out_file')
'''
misc code for storing pseudo_potentials in:
self.pseudo_files
self.occupied_bands
etc...
'''
params = {'structure': self.structure, 'pseudo_dir': self.pseudo_dir,
'kpoints': self.kpoints, 'qshift': self.qshift,
'input_set_params': self.isp, 'run_type': self.run_type,
'mat_type':self.mat_type, 'out_file': self.filename}
self.update(params)
def write_input_file(self, filename):
<code for setting up input file format and writing to filename>
我構建我的門面類下面super
:
class BgwInput(BgwInputTask):
def __init__(self, structure, pseudo_dir, isp={},
kpoints=None, qshift=None, mat_type='semiconductor',
out_file=None):
self.__dict__['isp'] = isp
self.__dict__['run_type'] = out_file.split('.')[0]
self.__dict__['params'] = {'structure': structure, 'pseudo_dir': pseudo_dir,
'kpoints': kpoints, 'qshift': qshift,
'input_set_params': self.isp, 'mat_type': mat_type,
'out_file': out_file, 'run_type': self.run_type}
print("__init__: isp: {}".format(self.isp))
print("__init__: runtype: {}".format(self.run_type))
super(BgwInput, self).__init__(self.params)
def __setattr__(self, key, val):
self.proc_key_val(key.strip(), val.strip()) if isinstance(
val, six.string_types) else self.proc_key_val(key.strip(), val)
def proc_key_val(self, key, val):
<misc code for error checking of parameters being set>
super(BgwInput, self).__dict__['params']['input_set_params'].update({key:val})
這非常適用除外是混淆了我一個小小的警告。創建BgwInput
的新實例時,不會創建空實例。輸入集在先前實例中設置的參數以某種方式結轉到新實例,但不包括kpoints
或qshift
。例如:
>>> epsilon_task = BgwInput(structure, pseudo_dir='/path/to/pseudos', kpoints=[5,5,5], qshift=[0, 0, 0.001], out_file='epsilon.inp')
__init__: isp: {}
__init__: runtype: epsilon
>>> epsilon_task.epsilon_cutoff = 11.0
>>> epsilon_task.number_bands = 29
>>> sigma_task = BgwInput(structure, pseudo_dir='/path/to/pseudos', kpoints=[5,5,5], out_file='sigma.inp')
__init__: isp: {'epsilon_cutoff': 11.0, 'number_bands': 29}
__init__: runtype: sigma
但是,如果我在門面類改變self.__dict__['isp'] = isp
到self.__dict__['isp'] = isp if isp else {}
似乎一切都按預期運行。在先前實例中設置的參數不會轉移到新實例。那麼,爲什麼Facade類默認不是isp = {}(因爲這是__ init __中的默認值),因爲它應該在創建時未提供輸入集參數?自從默認的應該是一個空白字典以來,它從哪裏拉動了以前的參數?
爲了清楚起見,我已經有了一個解決方案來使門面類功能正如我預期的那樣(通過將門面中的isp
更改爲self.__dict__['isp'] = isp if isp else {}
),但我試圖找出爲什麼需要這樣做。我相信我錯過了super
或Python中的方法解析順序。我很好奇爲什麼會發生這種情況,並試圖擴展我的知識基礎。
以下是Facade類的方法解析順序。
>>> BgwInput.__mro__
(pymatgen.io.bgw.inputs.BgwInput,
pymatgen.io.bgw.inputs.BgwInputTask,
fireworks.core.firework.FireTaskBase,
collections.defaultdict,
dict,
fireworks.utilities.fw_serializers.FWSerializable,
object)
你在'__init__'中有一個[mutable default argument](http://stackoverflow.com/questions/1132941/least-astonishment-in-python-the-mutable-default-argument)。 – user2357112
感謝您提供此信息。我不知道可變的默認參數。這絕對解釋了我所看到的行爲。所以,它不是'super'或'method resolution order'我缺乏知識,它是我錯過的核心Python參數的一部分。 –