python笔记(七)变量
变量/函数下划线的作用
-
value_
:区分 Python 关键字,比如想要定义一个名为 class 的类,class_
-
_value
:用来命名全局变量/函数,不会被from module import *
,但是依旧可以被import module
导入 -
__value
:用来命名类变量/方法,防止被子类中同名成员覆盖,实际名字会变成_classname__value
-
__value__
:魔术成员,最好不要去自定义这种风格的变量
变量作用域
- Local:函数/方法/列表推导式/类
- Enclosing:外层函数/方法
- Global:模块
- Built-in:Python 的 builtins 模块。全局变量中有一个名为
__builtins__
的模块对象
以 L –> E –> G –>B 的规则查找
Python除了 def/class/lambda/列表推导式/类 外,其他如: if/elif/else/ try/except for/while 是没有名字空间的
坑1:自由变量可访问不可赋值
自由变量就是不在当前作用域中的变量
变量的获取是按上述规则查找,但是对于变量的赋值(i=1 这种),只要该变量在当前作用域内没有被定义,就会定义一个新变量,除非使用 global,nonlocal 关键字
global 关键字:不要定义新变量,使用全局的同名变量
nonlocal 关键字:不要定义新变量,使用外层函数的同名变量
globals():当前模块全部的全局变量
locals():当前名字空间的所有变量,一般就是某个函数的全部变量
def func():
global tmp
tmp=123
# 如果全局变量存在,则将其赋值为 123
# 如果全局变量不存在,则创建一个全局变量,并赋值为 123
坑2:Enclosing 作用域
Enclosing 是函数定义时的嵌套作用域,而不是函数调用时的。
这其实不算是一个坑。我本身代码写得少,而我在 Java 中很少有【一个方法调用同一个类中的其它方法】的情况,所以对这种比较陌生。
比如下面这段代码是错误的
def say():
print(s) # s 没有被定义,不能使用
def main():
s='hello'
say()
坑3:类的局部作用域
类代码块是局部作用域,和方法的作用域是同级别的,不是嵌套的,所以以下代码是错误的
class C():
s=1
def say(self):
print(s) # s 没用被定义,必须使用 C.s
坑4:类需要在定义完成后才能使用
任何变量都要先定义后使用,这自不必说,但是以下情况常常使我忘记这点。
class C():
s=1
ss=[ C.s + i for i in range(10) ] # 不能使用 C.s,因为类还没定义完,还没有 C 这个类
ss=[ s + i for i in range(10) ] # 不能使用 s,因为列表推导式有自己的作用域
坑5:UnboundLocalError
下面的代码是错误的,i 已经在 Local 中被定义,所以不会去 Global 中查找,但是 Local 中 i 的使用先于定义,故报错。
Java 中也有这个坑。
i = 2
def test():
print(i)
i = 1
dir() 与 __dict__
的区别
__dict__
:在当前实例中定义的成员,就是用self.value=value
定义的成员。对于类就是类中定义的成员,对于函数方法,就是空,啥都没有
dir():当前实例所有能访问到的成员,对于实例而言,它还能访问到它的类中的成员。类成员并不是类私有的,而是所有实例共享的
dir() 获得的是包含属性名的列表;__dict__
获得的是包含属性名和属性值的字典
globals()和locals():类似于__dict__
,只不过这两个是函数,而__dict__
是属性
魔术变量的访问顺序
魔术变量如果不指定其所属的对象,那就是指 Global 中的魔术变量
"""
module
"""
def main():
"""
main()
"""
# __doc__='new module' 这一行将修改 Global 中的 __doc__ 属性
print(__doc__, main.__doc__, __builtins__.__doc__, sep='\n')
if __name__ == '__main__':
main()