python:命名空间学习
一、一个bug引发的思考
最近在学习python小项目,其中一个模块是有关时间的,就设计了一个辅助类叫做MyTimer
代码如下:(简略版)
import os
import time
class MyTimer():
# 私有方法:把时间戳转化为时间:
def __timestamp_to_time(self,timestamp):
timeStruct = time.localtime(timestamp)
return time.strftime("%Y-%m-%d %H_%M_%S",timeStruct)
# 获得文件创建时间
def get_file_createtime(self,filePath):
t = os.path.getctime(filePath)
create_time = self.__timestamp_to_time(t)
return create_time
# 测试函数
time = MyTimer()
filepath = 'G:\\Users\\IMUHERO\\old\\a.txt'
print(time1.get_file_createtime(filepath))
使用测试函数测试功能时一直报错,说没有找到 localtime
Traceback (most recent call last):
File ".\timer.py", line 67, in <module>
print(time.get_file_createtime(filepath))
File ".\timer.py", line 60, in get_file_createtime
create_time = self.__timestamp_to_time(t)
File ".\timer.py", line 54, in __timestamp_to_time
timeStruct = time.localtime(timestamp)
AttributeError: 'MyTimer' object has no attribute 'localtime'
可是在time这个模块里面确实有localtime这个方法呀,到底咋回事呢?
二、修正BUG
认真检查一下才发现,自己犯了一个低级错误,把实例化对象的命名和导入的包重复了。
这样就使得导入的time,被我自己命名的time对象覆盖了,我自己实例化的对象当然没有localtime啦,因为内部我还要调用外部time模块来实现功能呢。
把这个bug解决后也引发了我自己的思考,python的命名空间规则是怎么样的呢?全局变量,局部变量的作用范围和java有什么不同呢?读和写在python的编译期会有什么不同?
三、示例总结
下面通过几个小例子总结一下:
1.全局变量、局部变量和global关键字
范例一:
name = "test"
def Test():
print (name)
def Test1():
name = "test1"
print (name)
def Test2():
name += "1"
print (name)
Test()
Test1()
Test2()
运行这段代码的结果是什么?
test
test1
Traceback (most recent call last):
File ".\test.py", line 23, in <module>
Test2()
File ".\test.py", line 19, in Test2
name += "1"
UnboundLocalError: local variable 'name' referenced before assignment
可以看到Test()和Test1()都能正常执行
-》其中Test()函数内是没有name这个变量的,那他为什么能够执行呢?
这里的原因是:Python 的查找顺序为:局部的命名空间去 -> 全局命名空间 -> 内置命名空间
函数中定义的是局部空间,局部空间没有就去全局空间找,然后找到并打印。
-》 Test1()也是一样的道理,在局部空间我们定义了name,所以直接打印出来就结束了。
基础知识补充:
一般有三种命名空间:
- 内置名称(built-in names), Python 语言内置的名称,比如函数名 abs、char 和异常名称 BaseException、Exception 等等。
- 全局名称(global names),模块中定义的名称,记录了模块的变量,包括函数、类、其它导入的模块、模块级的变量和常量。
- 局部名称(local names),函数中定义的名称,记录了函数的变量,包括函数的参数和局部定义的变量。(类中定义的也是)
-》那么问题来了,为什么在Test2()中会报错:本地变量"name"未定义呢?
这里就涉及到python在编译期对读和写的不同操作,在Test2()中新增加了name += "1"
按道理说,局部变量没找到,应该去全局变量读取并且做修改,但是这里却没有。
我个人的理解是,一般情况下写操作是不安全的,对全局变量进行修改可能导致不可预料的结果,所以Python不允许。
-》那么我们怎么样才能对全局变量进行修改呢?
这里一个比较常用的方法是 global 关键字
这里我们顺便打印一下全局变量看一下结果:
test
test1
test2
test2
这次没有报错了,name += "2"得出了正确结果
我们可以注意到,全局变量name也发生了改变,变成了修改后的test2,说明global关键字可以对全局变量进行修改。
继续拓展:如果我们想要在函数内部获取全局变量来做操作,并且不希望改变全局变量的值怎么办?
2、闭包和nonlocal关键字
再举一个例子
假设一个人初始走0步,第一次走2步,第二次走3步,第三次走5步,那么计算他每一次走完的总步数。
看到这个问题大多数同学会想到使用 global 关键字
(1)用global解决
示例代码:
origin = 0
def factory(step):
global origin
origin += step
print(origin)
factory(2)
factory(3)
factory(5)
可以得出正确答案:
2
5
10
但是我们的origin也发生了改变,我们命名叫做origin就是起始值的意思,起始值怎么能够一直变呢。
还有没有更好的办法,不去修改起始值?
(2)用闭包解决
要理解闭包首先要理解python的独特之处
俗话说:Python一切皆对象
比较好的证明就是,python可以return一个函数,比如:
而闭包,就是函数+环境变量
闭包 = 函数+环境变量
下面的这个例子就是闭包,在函数里面嵌套函数,return的是内部函数。
最终打印的结果是50.
而全局变量a的结果仍然是10.
-》滴——————————————
今天学习时间到了,明天继续补充。
加油:)
上一篇: thinkphp5多级命名空间
下一篇: 命名空间