栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Python

Python变量的理解与内存管理

Python 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Python变量的理解与内存管理

Python变量与内存管理

  –与C语言中的变量做对比,更好的理解Python的变量。

变量

变量在C语言中
  全局变量:其存放在内存的静态变量区中。
  局部变量:代码块中存放在内存的代码区当中,当被调用后存放在内存栈区。

而Python的变量存储,则是使用类似堆的方式管理内存,由Python内部机制统一分配回收内存。

Python中的变量与变量存储–引用与对象

  Python作为OOP(面向对象)编程,一直信奉着一个信条,就是万物皆对象。
  所谓对象,它可以看成经过一系列的抽象以后,将具有共性的一类物体进行实例化(具象化)的个体,就如同我们每个人就是人类里面的一个对象。

class A():
    name = "123"
    def __init__(self):
        pass

    def funa(self):
        pass
def funa():
    pass

if __name__ == "__main__":
    Fun = funa
    Variable = 1
    ClassA = A()
    ListA = [1,2,3]
    DictA = {'d':1,'e':2}
    TupleA = (1,2,3)
    Str = "python"
    print(type(Fun))
    print(type(Variable))
    print(type(ClassA))
    print(type(ListA))
    print(type(DictA))
    print(type(TupleA))
    print(type(Str))

输出的是:
class ‘function’
class ‘int’
class ‘main.A’
class ‘list’
class ‘dict’
class ‘tuple’
class ‘str’

  很明显,Python中不管是基础数据类型,类,函数,所有的一切都是作为一个类的对象存储在内存,也可以单纯的看做一个值。

  而Python的变量就是作为一个引用,读取对象所存储的信息,与C面向过程所不同,Python变量即对象的引用,通俗来说就是指向值的名称。
  

  所以Python的变量只是不过对于一块指定内存的引用,也即对对象的引用,或者称为指向值的名称,相对于全局变量,局部变量的赋值只是引用另一块内存。C语言中一个变量代表一块特定的内存,而Python不像C语言,可以看成数据已经存放在内存之中了,被Python的变量对内存进行引用。即使变量不存在了,内存里值也不会受到任何影响。

if __name__ == "__main__":

    a = 1
    b = 2
    print(id(a))
    print(id(b))

    a = b
    print(id(a))
    print(id(1))
    print(id(2))

    sys.exit(0)

输出的是:
10919424
10919456
10919456
10919424
10919456
  从输出结果来看,很明显同一块内存数据其实是可以被多个变量引用,且常量和变量的内存地址是相对应的。
  
 

def funa():
    a = 1
    print(id(a))

if __name__ == "__main__":

    a = 1
    funa()
    print(id(a))
    a = 2
    print(id(a))
    funa()

    sys.exit(0)

输出结果:
10919424
10919424
10919456
10919424

  从输出结果可以看出,若是当全局变量和局部变量的数值一致时,其对应的内存地址是一致的,当全局变量被赋予其他值时,其内存地址发生改变,而局部变量未有变化。
  
  
  总结:Python变量的定义和赋值是同时进行的,Python的全局变量和局部变量的定义声明时,是基于内存已有数据的基础上,为变量分配地址进行引用,变量即对象的引用,而不是分别分配一块内存进行赋值,所以变量不进行赋值的话就会出现未定义的错误,,这时就会出现一个问题,这将会造成一个问题就是对象和数据将会越来越多,会消耗很大的内存空间,这时将会启动Python的垃圾回收机制,当某一段内存块的引用计数为0时进行回收,这个是后话了。

变量的作用域—看不见的字典

  C语言中每一对大括号作为一个代码块,if,for,while,switch语句是可以加上大括号的作为一个块级作用域,for,while()语句在括号中定义的变量是包含在大括号里面的,就是包含在大括号的作用域里,而每一个代码块就是一个局部的作用域,所有代码块内部变量优先级大于代码块外的同名变量。
  
  Python的作用域,就如同是Python的基础类型中的一部字典,在这部字典里记录着值(对象)与指向值的名称(变量),不同的作用域组成了不同的字典,而Python中能改变变量作用域的关键字只有class,def,lamba,所以在Python的关键语句(if,for,while…)中是不进行作用域的划分的,所以在(if,for,while…)语句对变量进行赋值,其变量的作用域可以被外部所引用。
  并且Python不存在块级作用域,在嵌套作用域中会生成作用域链,由内到外,引用时优先选取内部同名变量。
  在类与实例的作用域中
  

class A():
    name = 'x'
    what = 'xx'
    print('A name id =',id(name))
    def __init__(self,name,age):
        self.name = 'xxx'
        self.age = 18

    def set(self):
        self.name = 'xxx'
        self.age = 18
        global name
        name = 'xx'
        print('set global name = ',id(name))#与A.what的内存地址相同
        print('set.name = ',self.name)#作用域是对于变量而言的而不是内存而言

if __name__ == "__main__":
    a = A('xx',18)
    a.set()
    print('A id = ', id(A))
    print('a id = ', id(a))
    print('A.name = ',id(A.name))
    print('a.name id = ',id(a.name))
    print('A.what id = ', id(A.what))
    print('a.what id = ',id(a.what))
    print('A.set id = ', id(A.set))
    print('a.set id = ', id(a.set))
    sys.exit(0)

输出的是:
A name id = 140654891768216
set global name = 140654890720536
set.name = xxx
A id = 20336920
a id = 140654890787168
A.name = 140654891768216
a.name id = 140654890720704
A.what id = 140654890720536
a.what id = 140654890720536
A.set id = 140654690844744
a.set id = 140654891845576

  所以,作用域是对于变量而言的而不是内存而言,类与实例的作用域也是嵌套的
  
  
  参考LEGB法则:
  Local(本地作用域)–>Enclosing(闭包作用域)–>Global(全局作用域)–>Built-in(内建作用域)
  函数内部–>嵌套函数内部–>模块内部–>Python内建
  LEGB法则: 当在函数中使用未确定的变量名时,Python会按照优先级依次搜索4个作用域,以此来确定该变量名的意义。首先搜索局部作用域(L),之后是上一层嵌套结构中def或lambda函数的闭包作用域(E),之后是全局作用域(G),最后是内建作用域(B)。按这个查找原则,在第一处找到的地方停止。如果没有找到,则会发出错误。
  变量作用域在定义时已经设定好,与调用的位置无关。

name ="???"
def funa():
    print(name)

def funb():
    name = "123"
    funa()

if __name__ == "__main__":

    funa()
    sys.exit(0)

输出的是:
???
  所以变量的作用域与是否调用无关,在变量定义时所处作用域已经设定完成。
  

变量的生命周期—只要被需要便存在

  C语言的局部变量是在函数调用完毕后进行自动销毁,释放栈区。
  
   而基于Python存储方式的特殊性,所以变量在函数调用完毕之后,并未立刻销毁,对于Python的变量和变量所引用的对象,是使用类似堆的方式管理内存,由Python内部机制统一分配回收内存,当内存的某一对象或者变量的引用计数为0时则由Python的内存管理机制收回内存,或者对对象手动del掉对象以释放内存,不过del掉的对象不影响对象中依然被外部变量有引用的值。
  
  

class A():
    def __init__(self):
        self.a = 123
    def funa(self):
        c = a+1
        print(id(c))
variable = None
classA = None

def initA():

    global classA
    global variable
    e = A()
    variable = e.a
    classA = e
    print(id(e))
    print(id(e.a))

if __name__ == "__main__":

    a = 1
    e = None
    initA()
    print(id(classA))
    print(id(variable))
    del classA
    #print(id(classA))
    print(id(variable))

    sys.exit(0)

输出结果是:
39697096
1409448784
39697096
1409448784
1409448784
   当函数被调用完,只要类实例还被引用,那么类实例依然存在类似c++的new,当del对象时,不影响对象还在被外部变量引用的值。
   
  当我们若是del掉classA后,再输入print(id(classA)),会出现如下错误:

Traceback (most recent call last):
  File "C:/Users/Administrator/PycharmProjects/pysidetest/demo.py", line 69, in 
    print(id(classA))
NameError: name 'classA' is not defined

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/833659.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号