python3作用域
Ⅰ python变量的作用域到底怎么理解怎么用呢谢谢!
你可以 在 B页面 里面直接 调用 一下 函数
运行一下 ,你可以发现应该和 刚才 执行A 页面 报的是同样的错误;
这是 因为 在B 页面里面 并没有 s1List 这样一个数组
在运行A页面时,因为有了 from b import * ,python解释器就可以找的getS1和getS2这样的函数名;可以 在 import 之后 print dir() 来查看 当前作用域下可用的名字 ,可以看到 getS1 和getS2 都在其中
之所以 执行 A页面错误,是A页面调用 函数 getS1 时,在B页面中 执行 函数时找不到 s1List这个数组,因为在A 页面的那个 s1List 是不在 B页面的作用范围内的。
Ⅱ 深入探究Python中变量的拷贝和作用域问题
这篇文章主要介绍了Python中变量的拷贝和作用域问题,包括一些赋值、引用问题,以及相关函数在Python2和3版本之间的不同,需要的朋友可以参考下
在
python
中赋值语句总是建立对象的引用值,而不是复制对象。因此,python
变量更像是指针,而不是数据存储区域,
这点和大多数
OO
语言类似吧,比如
C++、java
等
~
1、先来看个问题吧:
在Python中,令values=[0,1,2];values[1]=values,为何结果是[0,[...],2]?
?
1
2
3
4
>>>
values
=
[0,
1,
2]
>>>
values[1]
=
values
>>>
values
[0,
[...],
2]
我预想应当是
?
1
[0,
[0,
1,
2],
2]
但结果却为何要赋值无限次?
可以说
Python
没有赋值,只有引用。你这样相当于创建了一个引用自身的结构,所以导致了无限循环。为了理解这个问题,有个基本概念需要搞清楚。
Python
没有“变量”,我们平时所说的变量其实只是“标签”,是引用。
执行
?
1
values
=
[0,
1,
2]
的时候,Python
做的事情是首先创建一个列表对象
[0,
1,
2],然后给它贴上名为
values
的标签。如果随后又执行
?
1
values
=
[3,
4,
5]
的话,Python
做的事情是创建另一个列表对象
[3,
4,
5],然后把刚才那张名为
values
的标签从前面的
[0,
1,
2]
对象上撕下来,重新贴到
[3,
4,
5]
这个对象上。
至始至终,并没有一个叫做
values
的列表对象容器存在,Python
也没有把任何对象的值复制进
values
去。过程如图所示:
执行
?
1
values[1]
=
values
的时候,Python
做的事情则是把
values
这个标签所引用的列表对象的第二个元素指向
values
所引用的列表对象本身。执行完毕后,values
标签还是指向原来那个对象,只不过那个对象的结构发生了变化,从之前的列表
[0,
1,
2]
变成了
[0,
?,
2],而这个
?
则是指向那个对象本身的一个引用。如图所示:
要达到你所需要的效果,即得到
[0,
[0,
1,
2],
2]
这个对象,你不能直接将
values[1]
指向
values
引用的对象本身,而是需要吧
[0,
1,
2]
这个对象“复制”一遍,得到一个新对象,再将
values[1]
指向这个复制后的对象。Python
里面复制对象的操作因对象类型而异,复制列表
values
的操作是
values[:]
#生成对象的拷贝或者是复制序列,不再是引用和共享变量,但此法只能顶层复制
所以你需要执行
?
1
values[1]
=
values[:]
Python
做的事情是,先
dereference
得到
values
所指向的对象
[0,
1,
2],然后执行
[0,
1,
2][:]
复制操作得到一个新的对象,内容也是
[0,
1,
2],然后将
values
所指向的列表对象的第二个元素指向这个复制二来的列表对象,最终
values
指向的对象是
[0,
[0,
1,
2],
2]。过程如图所示:
往更深处说,values[:]
复制操作是所谓的“浅复制”(shallow
),当列表对象有嵌套的时候也会产生出乎意料的错误,比如
?
1
2
3
4
a
=
[0,
[1,
2],
3]
b
=
a[:]
a[0]
=
8
a[1][1]
=
9
问:此时
a
和
b
分别是多少?
正确答案是
a
为
[8,
[1,
9],
3],b
为
[0,
[1,
9],
3]。发现没?b
的第二个元素也被改变了。想想是为什么?不明白的话看下图
正确的复制嵌套元素的方法是进行“深复制”(deep
),方法是
?
1
2
3
4
5
6
import
a
=
[0,
[1,
2],
3]
b
=
.deep(a)
a[0]
=
8
a[1][1]
=
9
2、引用
VS
拷贝:
(1)没有限制条件的分片表达式(L[:])能够复制序列,但此法只能浅层复制。
(2)字典
方法,D.()
能够复制字典,但此法只能浅层复制
(3)有些内置函数,例如
list,能够生成拷贝
list(L)
(4)
标准库模块能够生成完整拷贝:deep
本质上是递归
(5)对于不可变对象和可变对象来说,浅复制都是复制的引用,只是因为复制不变对象和复制不变对象的引用是等效的(因为对象不可变,当改变时会新建对象重新赋值)。所以看起来浅复制只复制不可变对象(整数,实数,字符串等),对于可变对象,浅复制其实是创建了一个对于该对象的引用,也就是说只是给同一个对象贴上了另一个标签而已。
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
L
=
[1,
2,
3]
D
=
{'a':1,
'b':2}
A
=
L[:]
B
=
D.()
print
"L,
D"
print
L,
D
print
"A,
B"
print
A,
B
print
"--------------------"
A[1]
=
'NI'
B['c']
=
'spam'
print
"L,
D"
print
L,
D
print
"A,
B"
print
A,
B
L,
D
[1,
2,
3]
{'a':
1,
'b':
2}
A,
B
[1,
2,
3]
{'a':
1,
'b':
2}
--------------------
L,
D
[1,
2,
3]
{'a':
1,
'b':
2}
A,
B
[1,
'NI',
3]
{'a':
1,
'c':
'spam',
'b':
2}
3、增强赋值以及共享引用:
x
=
x
+
y,x
出现两次,必须执行两次,性能不好,合并必须新建对象
x,然后复制两个列表合并
属于复制/拷贝
x
+=
y,x
只出现一次,也只会计算一次,性能好,不生成新对象,只在内存块末尾增加元素。
当
x、y
为list时,
+=
会自动调用
extend
方法进行合并运算,in-place
change。
属于共享引用
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
L
=
[1,
2]
M
=
L
L
=
L
+
[3,
4]
print
L,
M
print
"-------------------"
L
=
[1,
2]
M
=
L
L
+=
[3,
4]
print
L,
M
[1,
2,
3,
4]
[1,
2]
-------------------
[1,
2,
3,
4]
[1,
2,
3,
4]
4、python
从2.x
到3.x,语句变函数引发的变量作用域问题
先看段代码:
?
1
2
3
4
5
6
7
8
9
def
test():
a
=
False
exec
("a
=
True")
print
("a
=
",
a)
test()
b
=
False
exec
("b
=
True")
print
("b
=
",
b)
在
python
2.x
和
3.x
下
你会发现他们的结果不一样:
?
1
2
3
4
5
6
7
2.x:
a
=
True
b
=
True
3.x:
a
=
False
b
=
True
这是为什么呢?
因为
3.x
中
exec
由语句变成函数了,而在函数中变量默认都是局部的,也就是说
你所见到的两个
a,是两个不同的变量,分别处于不同的命名空间中,而不会冲突。
具体参考
《learning
python》P331-P332
知道原因了,我们可以这么改改:
?
1
2
3
4
5
6
7
8
9
10
11
12
def
test():
a
=
False
ldict
=
locals()
exec("a=True",globals(),ldict)
a
=
ldict['a']
print(a)
test()
b
=
False
exec("b
=
True",
globals())
print("b
=
",
b)
这个问题在
stackoverflow
上已经有人问了,而且
python
官方也有人报了
bug。。。
具体链接在下面:
http://stackoverflow.com/questions/7668724/variables-declared-in-execed-code-dont-become-local-in-python-3-documentatio
http://bugs.python.org/issue4831
http://stackoverflow.com/questions/1463306/how-does-exec-work-with-locals
Ⅲ PYTHON 的变量作用域与内存分配
原理:python中任何变量都是对象,所以参数只支持引用传递方式。即通过名字绑定的机制,把实际参数的值和形式参数的名称绑定在一起,形式参数和实际参数指向内存中的同一个存储空间。
回答问题2:
每一次给变量赋值就是把这个名称的值在一个新内存中存储 你print (id (a)) 会发现每一次f(x),a的内存地址都是新的。所以你的问题二中L=[4,3] 与之前的L[]不是同一个名称,所以append上a就是[4,3,3](简明点就是L=[4,3]与L=[1,2]是两不同名的玩意)
讨论问题1:
在你的程序中a=1,a=2,a=5是int对象的三个实例,所以占用的是三段不同的内存,自然在程序执行完收回内存的时候才会被清理;而L是通过列表的append方法进行变化时,print (f(1))
print (f(2)) print (f(5))是对对一个实例进行操作的,所以内存地址不变; 同理print (f(3,[4,3]))直接给L赋值时,由于 是一个新的列表实例了,内存位置自然变化。
产生以上的问题的根本原因就是python的精髓:万物皆对象 (赋值的过程是对象的实例化)
看完自己的回答后:感觉真的很绕,不过我是尽力了,希望你能看懂,不明白的话,在追问里注明吧!
Ⅳ Python语言中作用域怎么理解
命名空间 是从命名到对象的映射。当前命名空间主要是通过 Python 字典实现的,不过通常不关心具体的实现方式(除非出于性能考虑),以后也有可能会改变其实现方式。以下有一些命名空间的例子:内置命名(像 abs() 这样的函数,以及内置异常名)集,模块中的全局命名,函数调用中的局部命名。某种意义上讲对象的属性集也是一个命名空间。关于命名空间需要了解的一件很重要的事就是不同命名空间中的命名没有任何联系,例如两个不同的模块可能都会定义一个名为 maximize 的函数而不会发生混淆-用户必须以模块名为前缀来引用它们。
顺便提一句,我称 Python 中任何一个“.”之后的命名为 属性 --例如,表达式 z.real 中的 real 是对象 z 的一个属性。严格来讲,从模块中引用命名是引用属性:表达式 modname.funcname 中,modname 是一个模块对象,funcname 是它的一个属性。因此,模块的属性和模块中的全局命名有直接的映射关系:它们共享同一命名空间![1]
属性可以是只读过或写的。后一种情况下,可以对属性赋值。你可以这样做: modname.the_answer = 42 。可写的属性也可以用 del 语句删除。例如: del modname.the_answer 会从 modname 对象中删除 the_answer 属性。
不同的命名空间在不同的时刻创建,有不同的生存期。包含内置命名的命名空间在 Python 解释器启动时创建,会一直保留,不被删除。模块的全局命名空间在模块定义被读入时创建,通常,模块命名空间也会一直保存到解释器退出。由解释器在最高层调用执行的语句,不管它是从脚本文件中读入还是来自交互式输入,都是 __main__ 模块的一部分,所以它们也拥有自己的命名空间(内置命名也同样被包含在一个模块中,它被称作 builtins )。
当调用函数时,就会为它创建一个局部命名空间,并且在函数返回或抛出一个并没有在函数内部处理的异常时被删除。(实际上,用遗忘来形容到底发生了什么更为贴切。)当然,每个递归调用都有自己的局部命名空间。
作用域 就是一个 Python 程序可以直接访问命名空间的正文区域。这里的直接访问意思是一个对名称的错误引用会尝试在命名空间内查找。尽管作用域是静态定义,在使用时他们都是动态的。每次执行时,至少有三个命名空间可以直接访问的作用域嵌套在一起:
Ⅳ Python 的类中到底有没有建立作用域
类在定义的时候是有作用域的,这个作用域内的变量只能在 class 块内访问,而不能在类的方法(函数)中访问。
Ⅵ python中函数变量作用域和类变量作用域怎么搞都错,烦躁中
python中,变量的作用域要弄清楚。只有mole、class、def、lambda才会引入作用域,其他的代码块是不会引入作用域的。
1
图一中,你在函数中声明了d为全局变量,但这样是无效的,程序运行结果,已经说明这一点。
global这个关键字,是用来“在函数中修改全局变量值”的声明,而不是“在局部函数中定义一个全局变量”的声明。这里要注意一下。
你可以再局部函数外面声明变量d,再加上你原先的函数,就可以修改、访问这个变量了。
2
在类中函数的变量,作用域只在函数中。图二中,jian这个变量分别在yu(),yu1()两个函数中,是处于不同的定义域中的,是不能相互访问的。
所以,在各自函数中,只有先定义了jian变量,才能再使用。
如果想在yu1()中访问yu()中的jian变量,就需要将jian变量变成全局变量,即在class中定义一个全局变量jian,这样yu1(),yu()函数都可以访问了
Ⅶ python中什么叫局部作用域
1.这个怎么看,我不能理解;2.全局变量局部变量有什么区别吗? 区别肯定有的,不然名字就没必要区分了。全局的作用域比较大,一般在程序代码中任何地方都可以调用,局部变量一般只在函数内部使用。3.函数,说白了就是实现不同功能的代码段,比如MAX(a,b,c,...)函数,求最大值, MIN(a,b,c,...)函数,求最小值等、、、、还有很多。函数一般只知道使用方法(比如所需参数,返回值)和实现功能就行。
Ⅷ 学习python必备的基础知识
学Python应先复从Python开发基础部分入手,如学习Python语言介绍、环境安装、 Python基本语法、基本数据类型、 二进制运算、流程控制、 字符制编码、文件处理、 数据类型、用户认证、函数、 三级菜单程序、购物车程序开发、 员工信息表开发、内置方法、 递归、迭代器、装饰器、 模块的跨目录导入、 b加密百\re正则\logging日志模块、 常用标准库学习、 软件开发规范学习、 计算器程序、 ATM程序开发等,学完这些基本算是入度门了
Ⅸ python函数作用域的相关问题
global i表示声明一个全局变量i,而函数A当中的i还是第2行定义的局部变量i。第7行输出的是第2行定义的i,而第10行输出的是全局变量i。