代码之家  ›  专栏  ›  技术社区  ›  Bananach

Python:修改调用范围中的变量绑定

  •  -1
  • Bananach  · 技术社区  · 8 年前

    是否可以更换该功能 foo

    def foo():
        #calling_scope()['a']=2
    def bar(a):
        print(a)
        foo()
        print(a)
    bar(1)
    

    打印

    1
    2
    

    ?


    parse_args 它包含一系列函数,例如

    def bool(arg):
      if arg in [True,'True','true']:
         return True
      if arg in [False,'False','false']:
         return False
      raise ValueError('Did not understand boolean value')
    def nonnegative(arg):
      if arg<0:
        raise ValueError('Argument cannot be negative')
      return arg  
    

    我在 bar

    def bar(arg1,arg2)
        arg1=parse_args.bool(arg1)
        arg2=parse_args.nonnegative(arg2)
    

    def bar(arg1,arg2)
        parse_args(arg1='bool',arg2='nonnegative')
    

    其中的伪代码 parse_参数

    def parse_args(**kwargs)
        #cs=calling_scope()
        #for arg in kwargs:
        #    cs[arg]=globals()[kwargs[arg]](cs[arg])
    

    我知道这只是稍微少了一点罗嗦,我理解可能有理由支持我目前的方法而不是我的目标,但作为仍在学习Python的人,我真正感兴趣的是这里的可行性。

    2 回复  |  直到 8 年前
        1
  •  2
  •   Martijn Pieters    8 年前

    不,这是不可能的。您不能从堆栈的更底层更改函数的局部名称空间,因为CPython实现已经高度优化了局部名称空间,使得任何操作都不可能。

    def bar(arg1, arg2)
        namespace = {'arg1': arg1, 'arg2': arg2}
        parse_args(namespace, arg1='bool', arg2='nonnegative')
    
        2
  •  0
  •   Bananach    8 年前

    我找到了一种方法,使用函数注释和修饰符,以比我希望的更漂亮的方式进行解析。(实际上,这实际上修改了我想要修改的函数中的变量绑定,从技术上讲,这是可能的,因为通过使用decorators,调用者变成了被调用者。)

    我现在写

    @validated()
    def f(a:'nonnegative integer',b:'bool|function', c:'float in_range(0,1)', d:'{float}', e:'{integer:any}',f:'bool'):  
        print(a,b,c,d,e,f)
    

    >>f(a=2,b=lambda x: x>2, c=0,d=[1.2, 2.3], e={1:'foo',2:'bar'},f='true')
    2 <function <lambda> at 0x7f4779ae8400> 0.0 [1.2, 2.3] {1: 'foo', 2: 'bar'} True
    

    注意整数参数 c=0 已转换为浮动 0.0 True a c . 例如,如果不符合任何规格 a=-1 ,抛出一个有充分根据的错误:

    swutil.validation.ValidationError: Invalid argument for parameter 'a': -1 was rejected by 'nonnegative integer' (-1 was rejected by 'nonnegative')
    

    最后,装饰器接受可以用于指定必须传递哪些参数的参数。例如 @validated('a^b') @validated('a|b') 指定(正是)其中一个 b 必须通过。另一个将填充一个 NotPassed

    如果有人对代码感兴趣,请留下评论,我将与大家分享。