|
本帖最后由 万里云 于 2018-10-24 17:57 编辑
楼主是指类似Fortran那种在模块里定义的数据?
python中没有与之对应的概念,全局作用域其实是模块作用域,局部作用域是每个函数的作用域,不存在跨模块的全局作用域。这一点和C/Fortran不一样。举个例子:
设有一个模块foo,里面定义一个全局变量bar并初始化为10,同时定义一个函数print_bar()输出bar的值
- foo.py
- -----------------------------------------------------------
- bar = 10
- def print_bar():
- print(bar)
复制代码
然后导入模块foo并将bar赋值为11,再调用函数print_bar()
- main.py
- ---------------------------------
- from foo import bar, print_bar
- bar = 11
- print_bar()
复制代码
可以看到输出结果仍然是10
- [yhli@storage ~]$ python main.py
- 10
复制代码
这和python的赋值机制有关。python中的变量名对应的英文是“name”,而C/C++/Fortran中变量名是“identifier”。这其中有些微妙的差别,就好比一个人可以有很多个名字,但只能有一个身份证号。Python中的赋值操作实际上是“贴标签”,先检查等号右边的对象是否存在,如果不存在就创建它,然后把左边的name贴在这个对象上。a = b = [1, 2, 3]之后再修改b,a也会跟着变,因为a和b是贴在同一个列表对象上的两个标签,而不是两个独立的对象。
再回头看模块foo中全局变量bar。在python中,放到模块作用域中的语句会被当作初始化语句,所以在导入模块过程中就在foo中创建了一个整形对象10,并贴了一个"bar"的标签在上面。导入完成后,主程序(其实是__main__模块)知道自己的作用域中有个标签叫bar,被贴在10上。这种情况下执行bar = 11,实际上是把__main__模块中的bar贴在了11上,而foo中的bar还贴在10上。
要怎样才能修改foo中的bar呢?需要这样操作
- main.py
- -----------------------------------------
- import foo
- foo.bar = 11
- foo.print_bar()
- [yhli@storage ~]$ python main.py
- 11
复制代码 和前一个版本的main.py不同的是,导入foo过程中也会创建整型对象10并贴上bar这个标签,但导入完成后__main__中并没有bar。通过模块名来修改bar的值,实际上是新建了一个整形对象11,并把foo中的bar贴在了上面。
对于习惯了C/C++/Fortran等语言的人来说,这种赋值模式简直违反直觉。如果不对这种模式烂熟于心,很容易写出有BUG的python程序。
编程语言的语法规则一定程度上限制了程序的设计模式。Fortran就是简单直白:计算过程中需要用到一大堆数组,所以在程序开头就一股脑地把它们全部定义好。有些操作重复率较高,就拿出来做成子程序。子程序间传参数太麻烦,就把通用的一些数组放到模块中,谁要用就声明一下。而在C++/python中,把数据和操作数据的函数打包成一个类更方便。
fortran这种模式不利于代码复用。把数据和函数打包成一个类,直接导入这个类就行了。fortran这种模式还得把这些包含变量的模块带过去,零零碎碎的很容易出错。
其实我到现在都没搞懂怎样使用module中的变量才安全。这种变量有点类似C语言中的全局变量,初始化、修改、引用和内存回收都要很谨慎。目前想到的方法是每个含有变量的模块都定义xxxx_init和xxxx_finalize两个子程序,统一在主程序中调用,或者在上一级子程序调用。
|
评分 Rate
-
查看全部评分 View all ratings
|