在Python中,当查找未定义的全局变量时,是否可以动态生成值?

时间:2018-10-24 16:49:22

标签: python-3.x dynamic global-variables undefined name-lookup

在Lua中,全局变量存储在名为<button onClick={this.removeContact(index)}> 的表中。您可以向_G添加一个元表,这样当您查找未定义的全局值时,将调用用户定义的函数来提供一个值。

在下面的示例中,查找任何未定义变量将返回未定义变量的名称。

_G

是否可以在Python 3中实现相同的效果?

2 个答案:

答案 0 :(得分:0)

从2018年12月12日起更新答案:

这是另一种(更好的方法)。基本上,我们手动read()compile(),然后exec()整个源文件。当我们调用exec()时,我们可以传入备用全局字典。整个文件被读取,编译和执行两次,但是我们确实达到了预期的结果。

def  baz  ():
  global  foo
  print ( foo )    #  should print the string 'foo'                             
  foo  =  5
  print ( foo )    #  should print 5                                            
  print ( bar )    #  should print the string 'bar'                             


class  CustomGlobals ( dict ):
  def  __getitem__  ( self, k ):
    if  k in self:  return  self .get ( k )
    if  hasattr ( self .get ( '__builtins__' ), k ):
      #  we raise KeyError to avoid clobbering builtins                         
      raise  KeyError
    return  k


def  main  ():

  with  open ( __file__, 'rb' ) as f:
    source  =  f .read()    # re-read __file__                                  
  code  =  compile ( source, __file__, 'exec' )    #  re-compile __file__       

  g  =  CustomGlobals ( globals() )
  g [ '__name__' ]  =  None    #  prevent infinite recursion                    
  exec ( code, g )    #  re-exec __file__ against g                             

  g [ 'baz' ] ()    #  call the re-complied baz function                        

if  __name__ == '__main__':  main()

以上方法(IMO)优越,因为我们不需要将代码嵌套在字符串中,并且错误消息将包含正确的行号。

2018年11月29日的原始答案:

如果有问题的Python代码来自字符串(而不是标准的.py文件),则可以exec()字符串并提供一个自定义全局字典,如下所示:

code  =  '''                                                                     
print ( foo )    #  should print the string 'foo'                               
foo  =  5                                                                       
print ( foo )    #  should print 5                                              
print ( bar )    #  should print the string 'bar'                               
'''

class  CustomDict ( dict ):
  def  __init__  ( self, other ):  super() .__init__ ( other )
  def  __getitem__  ( self, k ):
    if  k in self:  return  self .get ( k )
    if  hasattr ( self .get ( '__builtins__' ), k ):
      #  we raise KeyError to avoid clobbering builtins 
      raise  KeyError
    return  k

exec ( code, None, CustomDict ( globals() ) )

根据需要,以上输出:

foo
5
bar

我还没有找到任何使模块“突变”以实现该模块中代码相同结果的方法。如果有人知道改变模块的方法,我将很高兴看到它。

(也许模块可以将自己的源代码读取为字符串,然后在自定义全局dict的上下文中编译该字符串,然后将结果注入sys.modules?换句话说,该模块将用自身的克隆代替自身,但使用不同的全局dict。嗯。)

此外:有一些方法可以在模块上模拟__getitem__()__getattr__()。从Python 3.7开始,您可以在模块中直接简单地定义一个__getattr__()函数。但是,据我所知,这些技术都无法与全局变量的查找挂钩。来源:

答案 1 :(得分:-1)

你是说类似的东西

print(bar) if 'bar' in globals() else print('bar')