从函数中访问模块变量被认为是不好的做法吗?

时间:2017-09-06 14:27:08

标签: python function variables module global-variables

在Python中,函数可以访问模块变量,如下所示:

def pow(a):
    return a**b

a = 3
b = 2
print(pow(a))

这被认为是不好的做法吗?

显而易见的替代方法是将所有参数显式传递给函数:

def pow(a, b):
    return a**b

a = 3
b = 2
print(pow(a, b))

我使用第一种形式来限制传递给函数的参数数量,我想知道这是否被认为是不好的做法。

2 个答案:

答案 0 :(得分:1)

最好将变量显式传递给函数。意图更清晰,功能的目的也是如此。请考虑以下事项:

my_list = [1, 2, 3]
min_len = 5

def check_length(my_list):
    return len(my_list) < min_len

check_length(my_list)

乍一看,我看到check_length被调用了,但它检查了多长时间?如果我不知道,我必须搜索它。这是一个麻烦,只会随着更大的脚本和功能而增长。

答案 1 :(得分:1)

这实际上取决于您的使用情况,因为:

  1. 访问导入模块的唯一方法是在模块范围中引用其命名空间:
  2. import foo
    import bar_var from bar as bvar
    
    def myfun(a):
        return foo.foo_func(a)
        # foo is in module namespace, nobody adds it to the caller's signature
    
    def myfun2(b):
        myfun(b) 
    
    >>> myfun2(bvar) # returns foo.foo_func(bvar)
    
    1. 同样依赖python词法范围规则是实现闭包的唯一方法:
    2. def outerfun(a):
      
          def innerfun():
              return a
      
          return innerfun
      
      >>> inner_alias = outerfun("foo")
      >>> inner_alias()
      "foo"
      

      因此,请遵循以下最佳实践:使代码易于阅读和管理全局变量/命名空间,特别是记住可变数据结构将被修改,无论它们是否在签名中传递:

      L = []
      
      def foo(alist):
          alist.append(1)
          return alist
      
      def foo2():
          L.append(1)
          return L
      
      >>> foo(L)
      [1]
      >>> L
      [1] #!!! (lists are mutable and python passes by assignment)
      >>> foo2()
      [1, 1]
      >>> L
      [1, 1]
      

      P.S。在使用Python的OOP中,实例方法是使用实​​例作为第一个参数显式定义的(但是使用此参数自动隐式调用),将类名称空间暴露给方法:

      class myClass(object):
          def __init__(self): # the first argument must be the instance
              # __init__ is the constructor which we are overriding here
              self.inst_var1 = 1
              # initialize an instance var
      
          def add(self, i): # the first argument must be the instance
              if i <= 0:
                  raise ValueError("i must be a positive number!")
                  # But ValueError is a module global, because Exceptions are in global namespace
              return self.inst_var1 + i
      
      >>> myclass_inst = myClass()
      >>> myclass_inst.inst_var1
      1
      >>> myclass_inst.add(1) 
      # python automatically binds first argument to `myclass_inst`, 
      # as if myclass_inst.add = functools.partial(myclass_inst.add, myclass_inst)
      2