Ich dachte, ich hätte Multiple Inheritance mit Super() im Griff und versuchte es in einer Facade-Klasse zu benutzen, aber ich stolperte in einen seltsamen Fehler. Ich benutze eine gut gemachte Python Workflow-Software namens Fireworks, aber die Strukturen der Klassen und Workflow-Aufgaben sind ziemlich starr, deshalb habe ich eine Facade-Klasse erstellt, um die Benutzerfreundlichkeit zu erhöhen.Konstruieren der richtigen Python Fassadenklasse mit Super?
Unten ist die Grundstruktur der Workflow-Aufgabe:
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>
I strukturierte meine Fassade Klasse mit super
unter:
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})
Das funktioniert gut, bis auf einen kleinen Vorbehalt, dass ich ist verwirrend. Beim Erstellen einer neuen Instanz von BgwInput
wird keine leere Instanz erstellt. Input Set Parameter, die in früheren Instanzen gesetzt wurden, werden irgendwie auf die neue Instanz übertragen, aber nicht kpoints
oder qshift
. Zum Beispiel:
>>> 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
Allerdings, wenn ich self.__dict__['isp'] = isp
in meiner Fassade Klasse self.__dict__['isp'] = isp if isp else {}
alles ändern scheint wie erwartet zu funktionieren. Parameter, die in vorherigen Instanzen festgelegt wurden, werden nicht auf die neue Instanz übertragen. Warum ist die Facade-Klasse nicht auf isp = {} voreingestellt (vorausgesetzt, dies ist der Standardwert in __ init __), so wie es sein sollte, wenn bei der Erstellung keine Eingabeparameter übergeben wurden? Wo zieht es die vorherigen Parameter aus seit der Standard sollte ein leeres Wörterbuch sein?
Nur um klar zu sein, ich habe eine Lösung, um die Fassade Klasse funktionieren, wie ich es erwartet hatte (durch Änderung isp
in der Fassade zu self.__dict__['isp'] = isp if isp else {}
), aber ich versuche herauszufinden, warum dies erforderlich ist. Ich glaube, ich vermisse etwas Grundlegendes mit super
oder die Reihenfolge der Methodenauflösung in Python. Ich bin neugierig, warum dies geschieht und versuche, meine Wissensbasis zu erweitern.
Unten ist die Methode Auflösung für die Fassadenklasse.
>>> 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)
Sie haben ein [veränderbares Standardargument] (http://stackoverflow.com/questions/1132941/least-astonishment-in-python-the-mutable-default-argument) in Ihrem '__init__'. – user2357112
Vielen Dank für diese Information. Ich wusste nichts über veränderbare Standardargumente. Dies erklärt definitiv das Verhalten, das ich gesehen habe. Also, es war nicht "super" oder "Methodenauflösung". Mir fehlte das Wissen, es war Teil der Kern-Python-Argumente, die ich vermisste. –