2016-05-31 4 views
3

Super()로 다중 상속을 처리하고 Facade 클래스에서 사용하려고했지만 이상한 버그가 발생했습니다. 필자는 Fireworks라는 잘 만들어진 Python Workflow 소프트웨어를 사용하고 있지만 클래스 및 워크 플로 작업의 구조는 매우 까다로워서 사용하기 쉽도록 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이 아닙니다. 예를 들면 : 나는 self.__dict__['isp'] = isp if isp else {} 모든 것을 내 외관 클래스에 self.__dict__['isp'] = isp을 변경하는 경우

>>> 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 

그러나 예상대로 작동하는 것 같다. 이전 인스턴스에서 설정된 매개 변수는 새 인스턴스로 넘겨지지 않습니다. 그래서 Facade 클래스가 isp = {} 기본값으로 설정되어 있지 않은 이유는 무엇입니까? (이 값은 __ init __에서 기본값입니다.) 생성시 입력 세트 매개 변수가 주어지지 않으면 그렇게해야합니까? 기본값은 공백 사전이어야하기 때문에 이전 매개 변수를 어디에서 가져 옵니까?

그냥 외관상으로는 Facade 클래스 기능을 만들기위한 솔루션이 필요합니다 (Facade에서 ispself.__dict__['isp'] = isp if isp else {}으로 변경).하지만 이것이 필요한 이유를 찾으려고합니다. super 또는 Python의 메서드 확인 순서와 관련하여 근본적인 것이 없다고 생각합니다. 왜 이것이 발생하고 내 지식 기반을 확장하려고하는지 궁금합니다.

다음은 Facade 클래스의 Method Resolution Order입니다.

>>> 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) 
+1

귀하의'__init__'에 [변경 가능한 기본 인수] (http://stackoverflow.com/questions/1132941/least-astonishment-in-python-the-mutable-default-argument)가 있습니다. – user2357112

+0

이 정보를 제공해 주셔서 감사합니다. 나는 변덕스러운 기본 주장에 대해 몰랐다. 이것은 분명히 내가 보았던 행동을 설명합니다. 그래서 지식이 부족한'super' 나'method resolution order'가 아니 었습니다. 그것은 내가 놓친 핵심 파이썬 인수의 일부였습니다. –

답변

1

Python의 기본 인수가 예상대로 작동하지 않습니다. 귀하의 함수 정의 (관련이없는 인수가 생략) :

DEFAULT_ISP = {} 
def __init__(self, ..., isp=DEFAULT_ISP, ...): 
    <CODE> 

(. DEFAULT_ISP 변수를 사용할 수없는 점을 제외하고)

위의 코드는 명확하게 보여줍니다 :

def __init__(self, ..., isp={}, ...): 
    <CODE> 

은 다음과 동일합니다 귀하의 두 작업은 같은 isp dictoinary를 사용하고 있습니다. 이것은 분명히 속성 설정자에 의해 수정되고 있습니다.

관련 문제