찾다
백엔드 개발파이썬 튜토리얼深入探究Python中变量的拷贝和作用域问题

在 python 中赋值语句总是建立对象的引用值,而不是复制对象。因此,python 变量更像是指针,而不是数据存储区域,

201555102817358.jpg (668×316)

 这点和大多数 OO 语言类似吧,比如 C++、java 等 ~
1、先来看个问题吧:

在Python中,令values=[0,1,2];values[1]=values,为何结果是[0,[...],2]?
 

>>> values = [0, 1, 2]
>>> values[1] = values
>>> values
[0, [...], 2]

我预想应当是

[0, [0, 1, 2], 2]

但结果却为何要赋值无限次?

可以说 Python 没有赋值,只有引用。你这样相当于创建了一个引用自身的结构,所以导致了无限循环。为了理解这个问题,有个基本概念需要搞清楚。

Python 没有「变量」,我们平时所说的变量其实只是「标签」,是引用。

执行

values = [0, 1, 2]

的时候,Python 做的事情是首先创建一个列表对象 [0, 1, 2],然后给它贴上名为 values 的标签。如果随后又执行

values = [3, 4, 5]

的话,Python 做的事情是创建另一个列表对象 [3, 4, 5],然后把刚才那张名为 values 的标签从前面的 [0, 1, 2] 对象上撕下来,重新贴到 [3, 4, 5] 这个对象上。

至始至终,并没有一个叫做 values 的列表对象容器存在,Python 也没有把任何对象的值复制进 values 去。过程如图所示: 

201555102850996.jpg (600×450)

 执行

values[1] = values

的时候,Python 做的事情则是把 values 这个标签所引用的列表对象的第二个元素指向 values 所引用的列表对象本身。执行完毕后,values 标签还是指向原来那个对象,只不过那个对象的结构发生了变化,从之前的列表 [0, 1, 2] 变成了 [0, ?, 2],而这个 ? 则是指向那个对象本身的一个引用。如图所示:

201555102915614.jpg (600×450)

要达到你所需要的效果,即得到 [0, [0, 1, 2], 2] 这个对象,你不能直接将 values[1] 指向 values 引用的对象本身,而是需要吧 [0, 1, 2] 这个对象「复制」一遍,得到一个新对象,再将 values[1] 指向这个复制后的对象。Python 里面复制对象的操作因对象类型而异,复制列表 values 的操作是

values[:] #生成对象的拷贝或者是复制序列,不再是引用和共享变量,但此法只能顶层复制

所以你需要执行

values[1] = values[:]

Python 做的事情是,先 dereference 得到 values 所指向的对象 [0, 1, 2],然后执行 [0, 1, 2][:] 复制操作得到一个新的对象,内容也是 [0, 1, 2],然后将 values 所指向的列表对象的第二个元素指向这个复制二来的列表对象,最终 values 指向的对象是 [0, [0, 1, 2], 2]。过程如图所示: 

201555102947381.jpg (600×450)

 往更深处说,values[:] 复制操作是所谓的「浅复制」(shallow copy),当列表对象有嵌套的时候也会产生出乎意料的错误,比如

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 的第二个元素也被改变了。想想是为什么?不明白的话看下图 

201555103010789.jpg (600×450)

 正确的复制嵌套元素的方法是进行「深复制」(deep copy),方法是

 

import copy
 
a = [0, [1, 2], 3]
b = copy.deepcopy(a)
a[0] = 8
a[1][1] = 9

201555103115187.jpg (600×450)

 2、引用 VS 拷贝:

(1)没有限制条件的分片表达式(L[:])能够复制序列,但此法只能浅层复制。

(2)字典 copy 方法,D.copy() 能够复制字典,但此法只能浅层复制

(3)有些内置函数,例如 list,能够生成拷贝 list(L)

(4)copy 标准库模块能够生成完整拷贝:deepcopy 本质上是递归 copy

(5)对于不可变对象和可变对象来说,浅复制都是复制的引用,只是因为复制不变对象和复制不变对象的引用是等效的(因为对象不可变,当改变时会新建对象重新赋值)。所以看起来浅复制只复制不可变对象(整数,实数,字符串等),对于可变对象,浅复制其实是创建了一个对于该对象的引用,也就是说只是给同一个对象贴上了另一个标签而已。
 

L = [1, 2, 3]
D = {'a':1, 'b':2}
A = L[:]
B = D.copy()
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。

属于共享引用
 

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,语句变函数引发的变量作用域问题 

先看段代码:
 

def test():
  a = False
  exec ("a = True")
  print ("a = ", a)
test()
 
b = False
exec ("b = True")
print ("b = ", b)

在 python 2.x 和 3.x 下 你会发现他们的结果不一样:
 

2.x:
a = True
b = True
 
3.x:
a = False
b = True

这是为什么呢?

因为 3.x 中 exec 由语句变成函数了,而在函数中变量默认都是局部的,也就是说

你所见到的两个 a,是两个不同的变量,分别处于不同的命名空间中,而不会冲突。

具体参考 《learning python》P331-P332

知道原因了,我们可以这么改改:
 

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


성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
Python 학습 : 2 시간의 일일 연구가 충분합니까?Python 학습 : 2 시간의 일일 연구가 충분합니까?Apr 18, 2025 am 12:22 AM

하루에 2 시간 동안 파이썬을 배우는 것으로 충분합니까? 목표와 학습 방법에 따라 다릅니다. 1) 명확한 학습 계획을 개발, 2) 적절한 학습 자원 및 방법을 선택하고 3) 실습 연습 및 검토 및 통합 연습 및 검토 및 통합,이 기간 동안 Python의 기본 지식과 고급 기능을 점차적으로 마스터 할 수 있습니다.

웹 개발을위한 파이썬 : 주요 응용 프로그램웹 개발을위한 파이썬 : 주요 응용 프로그램Apr 18, 2025 am 12:20 AM

웹 개발에서 Python의 주요 응용 프로그램에는 Django 및 Flask 프레임 워크 사용, API 개발, 데이터 분석 및 시각화, 머신 러닝 및 AI 및 성능 최적화가 포함됩니다. 1. Django 및 Flask 프레임 워크 : Django는 복잡한 응용 분야의 빠른 개발에 적합하며 플라스크는 소형 또는 고도로 맞춤형 프로젝트에 적합합니다. 2. API 개발 : Flask 또는 DjangorestFramework를 사용하여 RESTFULAPI를 구축하십시오. 3. 데이터 분석 및 시각화 : Python을 사용하여 데이터를 처리하고 웹 인터페이스를 통해 표시합니다. 4. 머신 러닝 및 AI : 파이썬은 지능형 웹 애플리케이션을 구축하는 데 사용됩니다. 5. 성능 최적화 : 비동기 프로그래밍, 캐싱 및 코드를 통해 최적화

Python vs. C : 성능과 효율성 탐색Python vs. C : 성능과 효율성 탐색Apr 18, 2025 am 12:20 AM

Python은 개발 효율에서 C보다 낫지 만 C는 실행 성능이 높습니다. 1. Python의 간결한 구문 및 풍부한 라이브러리는 개발 효율성을 향상시킵니다. 2.C의 컴파일 유형 특성 및 하드웨어 제어는 실행 성능을 향상시킵니다. 선택할 때는 프로젝트 요구에 따라 개발 속도 및 실행 효율성을 평가해야합니다.

Python in Action : 실제 예제Python in Action : 실제 예제Apr 18, 2025 am 12:18 AM

Python의 실제 응용 프로그램에는 데이터 분석, 웹 개발, 인공 지능 및 자동화가 포함됩니다. 1) 데이터 분석에서 Python은 Pandas 및 Matplotlib를 사용하여 데이터를 처리하고 시각화합니다. 2) 웹 개발에서 Django 및 Flask 프레임 워크는 웹 응용 프로그램 생성을 단순화합니다. 3) 인공 지능 분야에서 Tensorflow와 Pytorch는 모델을 구축하고 훈련시키는 데 사용됩니다. 4) 자동화 측면에서 파이썬 스크립트는 파일 복사와 같은 작업에 사용할 수 있습니다.

Python의 주요 용도 : 포괄적 인 개요Python의 주요 용도 : 포괄적 인 개요Apr 18, 2025 am 12:18 AM

Python은 데이터 과학, 웹 개발 및 자동화 스크립팅 필드에 널리 사용됩니다. 1) 데이터 과학에서 Python은 Numpy 및 Pandas와 같은 라이브러리를 통해 데이터 처리 및 분석을 단순화합니다. 2) 웹 개발에서 Django 및 Flask 프레임 워크를 통해 개발자는 응용 프로그램을 신속하게 구축 할 수 있습니다. 3) 자동 스크립트에서 Python의 단순성과 표준 라이브러리가 이상적입니다.

파이썬의 주요 목적 : 유연성과 사용 편의성파이썬의 주요 목적 : 유연성과 사용 편의성Apr 17, 2025 am 12:14 AM

Python의 유연성은 다중 파리가 지원 및 동적 유형 시스템에 반영되며, 사용 편의성은 간단한 구문 및 풍부한 표준 라이브러리에서 나옵니다. 유연성 : 객체 지향, 기능 및 절차 프로그래밍을 지원하며 동적 유형 시스템은 개발 효율성을 향상시킵니다. 2. 사용 편의성 : 문법은 자연 언어에 가깝고 표준 라이브러리는 광범위한 기능을 다루며 개발 프로세스를 단순화합니다.

파이썬 : 다목적 프로그래밍의 힘파이썬 : 다목적 프로그래밍의 힘Apr 17, 2025 am 12:09 AM

Python은 초보자부터 고급 개발자에 이르기까지 모든 요구에 적합한 단순성과 힘에 호의적입니다. 다목적 성은 다음과 같이 반영됩니다. 1) 배우고 사용하기 쉽고 간단한 구문; 2) Numpy, Pandas 등과 같은 풍부한 라이브러리 및 프레임 워크; 3) 다양한 운영 체제에서 실행할 수있는 크로스 플랫폼 지원; 4) 작업 효율성을 향상시키기위한 스크립팅 및 자동화 작업에 적합합니다.

하루 2 시간 안에 파이썬 학습 : 실용 가이드하루 2 시간 안에 파이썬 학습 : 실용 가이드Apr 17, 2025 am 12:05 AM

예, 하루에 2 시간 후에 파이썬을 배우십시오. 1. 합리적인 학습 계획 개발, 2. 올바른 학습 자원을 선택하십시오. 3. 실습을 통해 학습 된 지식을 통합하십시오. 이 단계는 짧은 시간 안에 Python을 마스터하는 데 도움이 될 수 있습니다.

See all articles

핫 AI 도구

Undresser.AI Undress

Undresser.AI Undress

사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover

AI Clothes Remover

사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool

Undress AI Tool

무료로 이미지를 벗다

Clothoff.io

Clothoff.io

AI 옷 제거제

AI Hentai Generator

AI Hentai Generator

AI Hentai를 무료로 생성하십시오.

뜨거운 도구

드림위버 CS6

드림위버 CS6

시각적 웹 개발 도구

Atom Editor Mac 버전 다운로드

Atom Editor Mac 버전 다운로드

가장 인기 있는 오픈 소스 편집기

스튜디오 13.0.1 보내기

스튜디오 13.0.1 보내기

강력한 PHP 통합 개발 환경

SublimeText3 Mac 버전

SublimeText3 Mac 버전

신 수준의 코드 편집 소프트웨어(SublimeText3)

DVWA

DVWA

DVWA(Damn Vulnerable Web App)는 매우 취약한 PHP/MySQL 웹 애플리케이션입니다. 주요 목표는 보안 전문가가 법적 환경에서 자신의 기술과 도구를 테스트하고, 웹 개발자가 웹 응용 프로그램 보안 프로세스를 더 잘 이해할 수 있도록 돕고, 교사/학생이 교실 환경 웹 응용 프로그램에서 가르치고 배울 수 있도록 돕는 것입니다. 보안. DVWA의 목표는 다양한 난이도의 간단하고 간단한 인터페이스를 통해 가장 일반적인 웹 취약점 중 일부를 연습하는 것입니다. 이 소프트웨어는