举例说明在python中内存和变量的管理方式,python采用的是基于值的内存管理方式
Python变量和内存管理——与C语言中的变量进行比较,以便更好地理解Python变量。
变量在C语言中
全局变量:它存储在内存的静态变量区。
局部变量:代码块存储在内存的代码区,被调用后存储在内存堆栈区。
而Python的变量存储则是以类似堆的方式管理内存,Python的内部机制统一分配回收的内存。Python中的变量和变量存储——引用和对象Python作为OOP(面向对象)编程,一直信奉一个信条,即一切都是对象。
所谓对象,可以看作是经过一系列抽象后,将一类常见对象实例化(具体化)的个体,就像我们每个人都是人类中的一个对象。
class A():name= 123 def _ _ init _ _(self): pass def付娜(self):pass def付娜():passif _ _ name _ _= _ _ main _ _ :Fun=付娜Variable=1 ClassA=A() ListA=[1,2,3]dicat={ d :1, e :2 } TupleA= python print(type(Fun))print(type(Variable))print(type(A))print(type(ListA))print(type(dicat))print(type(type(dica))
类别“功能”
类“int”
等级main。一个
类别列表
类别“字典”
类“元组”
类别“str”
很明显,Python中的一切,无论是基本的数据类型、类、函数,都是作为类对象存储在内存中的,或者可以简单地看作一个值。
Python的变量作为引用来读取对象中存储的信息,与面向C的流程不同,Python变量即对象的引用,通俗来说就是指向值的名称。。
所以Python变量只是对指定内存的引用,也就是对对象的引用,或者指向值的名称。与全局变量相比,局部变量的赋值只是引用另一个内存。C语言中的一个变量代表一个特定的内存,而Python不像C语言,可以看作是已经存储在内存中的数据,被Python变量引用。即使变量不存在,内存中的值也不会受到任何影响。
if _ _ name _ _= _ _ main _ _ :a=1b=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))付娜()sys.exit (0)输出
10919424
10919424
10919456
10919424
从输出结果可以看出,如果全局变量和局部变量的值相同,则它们对应的内存地址相同;当全局变量被赋予其他值时,它们的内存地址会改变,但局部变量不会。
总结:Python变量是同时定义和赋值的。在定义和声明Python全局变量和局部变量时,会根据内存中的现有数据为变量分配引用地址。变量是对对象的引用,而不是为赋值分配一块内存。所以不赋变量就会出现未定义的错误,然后就会出现问题。这样会造成一个问题,对象和数据会越来越多,会消耗大量内存空间。这时Python的垃圾收集机制就会启动,当某个内存块的引用计数为0时,就会进行收集。这是后话。
变量的作用域——看不见的字典在C语言中,每一对花括号都是一个代码块,if、for、while、switch语句都可以加上花括号作为块级作用域。for,while()语句中定义的变量包含在花括号中,也就是花括号的作用域内,每个代码块都是一个局部作用域。所有代码块内变量的优先级高于代码块外同名变量的优先级。
Python的范围就像是Python基本类型的字典。在这个字典中,记录了值(对象)和指向值的名称(变量),不同的作用域形成不同的字典。但是,只有class、def和lambda是Python中可以改变变量范围的关键字。所以在Python的关键语句(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= xx print( set global name=,Id(name))#与A.what print(set.name=,self.name)#作用域是变量而不是内存if _ _ name _=. 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)输出:
姓名id=140654891768216
设置全局名称=140654890720536
set.name=xxx
A id=20336920
a id=140654890787168
A.name=140654891768216
a.name id=140654890720704
a .什么id=140654890720536
a .什么id=140654890720536
A.set id=140654690844744
a.set id=140654891845576
所以,作用域是对于变量而言的而不是内存而言,类与实例的作用域也是嵌套的
参考莱格布定律:
局部(局部范围)封闭(闭包范围)全局(全局范围)内置(内置范围)
函数内部嵌套函数内部模块内部Python内置
LEGB规则:当函数中使用了一个未确定的变量名时,Python会按照优先级顺序搜索四个作用域来确定变量名的含义。先搜索局部作用域(L),再搜索前面嵌套结构中def或lambda函数的闭包作用域(E),然后是全局作用域(G),最后是内置作用域(B)。按照这个搜索原则,在第一个找到的地方停下来。如果找不到,将发出一个错误。
变量的范围在定义的时候就已经设置好了,不管调用的位置在哪里。
name=?Def付娜():print (name) def funb (): name= 123 付娜()if _ _ name _ _= _ _ main _ :付娜()sys.exit (0)输出:
?
所以变量的作用域与是否调用无关。当变量被定义时,它的作用域就已经设定好了。
变量的生命周期——C语言中只要需要就存在的局部变量在函数被调用后自动销毁并释放堆栈区。
由于Python存储模式的特殊性,变量在函数被调用后不会立即销毁。对于Python的变量和变量引用的对象,内存采用类似堆的方式管理,Python的内部机制统一分配和回收内存。当内存中某个对象或变量的引用计数为0时,Python的内存管理机制会回收内存,或者手动del对象释放内存,但是被丢弃的对象不会影响外部变量仍然引用的值。
class A():def _ _ init _ _(self):self . A=123 def付娜(self):c=A 1 Print(id(c))variable=None class A=None def initA():global class A全局变量e=A()variable=e . A class A=e Print(id(e))Print(id(e))if _ _ name _ _= _ _ main _ _ :A=1 e=None initA()Print(id(类a)) print (id(变量))del class a # print (id(类A))Print(id(id(类)
39697096
1409448784
39697096
1409448784
1409448784
调用函数时,只要类实例仍被引用,类实例仍有一个新的like C,使用del对象时,不影响仍被外部变量引用的对象的值。
如果我们在del删除a类后输入print (ID (classA)),将出现以下错误:
Traceback(最近一次调用last):文件“C:/Users/Administrator/PycharmProjects/pysidests/demo . py”,第69行,在模块print(id(classA))名称中错误:未定义名称“classA”
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。