2017-09-19 59 views
1

更換的說法我有一個基類,我不能修改(代碼可能有其他錯誤,但請忽略這些)在argparse

class BaseClass(object): 
    def __init__(self): 
     self.parser = argparse.ArgumentParser() 
     self.parser.add_argument("arg1", choices=("a", "b")) 

我想要的是重寫ARG1如下

class DerivedClass(BaseClass): 
    def __init__(self): 
     BaseClass.__init__(self) 
     self.parser.add_argument("arg1", choices=("a", "c", "d")) 
+0

這段代碼有什麼問題?這個對我有用。你的論點被覆蓋。 – MrE

+0

@MrE'''$ python subclass.py c 用法:subclass.py [-h] {a,b} {a,b,c} subclass.py:error:argument arg1:invalid choice:'c' (從'a','b'中選擇) ''' –

+0

此代碼定義了2個位置參數,每個參數都有不同的選項集。 – hpaulj

回答

3

如果您不能修改基類的實現,你可以達到進入parser的屬性和修改您所關心的具體行動。下面是代碼演示只是一個草圖:

from base import BaseClass 


def _modify_choices(parser, dest, choices): 
    for action in parser._actions: 
     if action.dest == dest: 
      action.choices = choices 
      return 
    else: 
     raise AssertionError('argument {} not found'.format(dest)) 


class MySubClass(BaseClass): 
    def __init__(self): 
     super(MySubClass, self).__init__() 
     _modify_choices(self.parser, 'arg1', ('a', 'b', 'c')) 


def main(): 
    inst = MySubClass() 
    inst.parser.parse_args() 


if __name__ == '__main__': 
    exit(main()) 

與用法:

$ python subclass.py d 
usage: subclass.py [-h] {a,b,c} 
subclass.py: error: argument arg1: invalid choice: 'd' (choose from 'a', 'b', 'c') 

注意,這伸進私人實現細節(特別是ArgumentParser._actions),但以其他方式使用公共接口。

+0

我可能'def _append_choice' with'action.choices = action.choices + attached_choices' with'('c',)'如果基類確實改變了你不覆蓋這些改變,但這是一個折衷。無論哪種方式,我們都背叛了'BaseClass'的繼承。 – TemporalWolf

1

add_argument創建Action對象,該對象編碼add_argument調用中給出的參數。這些可以在創建後讀取和/或修改。

class BaseClass(object) 
    def __init__(self): 
     self.parser = argparse.ArgumentParser() 
     self.arg = self.parser.add_argument("arg1", choices=("a", "b")) 
     # self.arg is now the Action object defined by this add_argument method 

class DerivedClass(BaseClass): 
    def __init__(self): 
     BaseClass.__init__(self) 
     # modify the choices attribute of self.arg 
     self.arg.choices = ("a","b","c") 

的行動目標,也可在parser._actions列表中找到,但我更喜歡保存自己的代碼的參考。

(此代碼沒有經過測試,所以可能有錯誤或兩個)。


class BaseClass(object): 
    def __init__(self): 
     self.parser = argparse.ArgumentParser(prog="BASE") 
     self.parser.add_argument("arg1", choices=("a", "b")) 
     self.parser.add_argument('-f','--foo') 

class DerivedClass(BaseClass): 
    def __init__(self): 
     BaseClass.__init__(self) 
     self.parser.prog = "DERIVED" 
     print(self.parser._actions) 

顯示了當DerivedClass創建這個列表:

[_HelpAction(option_strings=['-h', '--help'], dest='help', nargs=0, const=None, default='==SUPPRESS==', type=None, choices=None, help='show this help message and exit', metavar=None), 
_StoreAction(option_strings=[], dest='arg1', nargs=None, const=None, default=None, type=None, choices=('a', 'b'), help=None, metavar=None), 
_StoreAction(option_strings=['-f', '--foo'], dest='foo', nargs=None, const=None, default=None, type=None, choices=None, help=None, metavar=None)] 

因此增加:

idx = [a.dest for a in self.parser._actions].index('arg1') 
    self.parser._actions[idx].choices = ("a","b","c") 

p1 = BaseClass() 
p1.parser.print_help() 

p2 = DerivedClass() 
p2.parser.print_help() 

產生2個usag ES:

usage: BASE [-h] [-f FOO] {a,b} 

positional arguments: 
    {a,b} 

optional arguments: 
    -h, --help   show this help message and exit 
    -f FOO, --foo FOO 

usage: DERIVED [-h] [-f FOO] {a,b,c} 

positional arguments: 
    {a,b,c} 

optional arguments: 
    -h, --help   show this help message and exit 
    -f FOO, --foo FOO 
+1

「我有一個基礎班我不能修改」我不知道這是如何滿足這個約束。 – TemporalWolf

+0

如果你不能擺弄基類,那麼我會在'_actions'列表中尋找Action。 – hpaulj

+0

我將如何從_actions列表中獲得正確的操作?我無法通過索引得到它,因爲這可能會改變(基類作者可能會增加更多) –