python中python 对象初始化化放在内存中什么位置

python之import机制详解
投稿:shichen2014
字体:[ ] 类型:转载 时间:
这篇文章主要介绍了python的import机制,需要的朋友可以参考下
本文详述了Python的import机制,对于理解Python的运行机制很有帮助!
1.标准import:
Python中所有加载到内存的模块都放在 sys.modules 。当 import 一个模块时首先会在这个列表中查找是否已经加载了此模块,如果加载了则只是将模块的名字加入到正在调用 import 的模块的 Local 名字空间中。如果没有加载则从 sys.path 目录中按照模块名称查找模块文件,模块可以是py、pyc、pyd,找到后将模块载入内存,并加到 sys.modules 中,并将名称导入到当前的 Local 名字空间。
一个模块不会重复载入。多个不同的模块都可以用 import 引入同一个模块到自己的 Local 名字空间,其实背后的 PyModuleObject 对象只有一个。这里说一个容易忽略的问题:import 只能导入模块,不能导入模块中的对象(类、函数、变量等)。例如:模块 A(A.py)中有个函数 getName,另一个模块不能通过 import A.getName 将 getName导入到本模块,只能用 from A import getName。
2.嵌套import:
1)顺序嵌套
例如:本模块导入 A 模块(import A),A 中又 import B,B 模块又可以 import 其他模块……
这中嵌套比较容易理解,需要注意的一点就是各个模块的 Local 名字空间是独立的。对于上面的例子,本模块 import A 之后本模块只能访问模块 A,不能访问模块 B 及其他模块。虽然模块 B 已经加载到内存了,如果访问还要再明确的在本模块中 import B。
2)循环嵌套
文件[A.py]
from B import D
class C:pass
文件[ B.py ]
from A import C
class D:pass
为什么执行 A 的时候不能加载 D 呢?
如果将 A.py 改为:import B 就可以了。
这是怎么回事呢?
RobertChen:这跟Python内部 import 的机制是有关的,具体到 from B import D,Python 内部会分成几个步骤:
(1)在 sys.modules 中查找符号 “B”
(2)如果符号 B 存在,则获得符号 B 对应的 module 对象。
& 从 &modult B& 的 __dict__ 中获得符号 “D” 对应的对象,如果 “D” 不存在,则抛出异常。
(3)如果符号 B 不存在,则创建一个新的 module 对象 &module B&,注意,此时,module 对象的 __dict__ 为空。
执行 B.py 中的表达式,填充 &module B& 的 __dict__。
从& &module B& 的 __dict__ 中获得 “D” 对应的对象,如果 “D” 不存在,则抛出异常。
所以这个例子的执行顺序如下:
1、执行 A.py 中的 from B import D 由于是执行的 python A.py,所以在 sys.modules 中并没有 &module B& 存在, 首先为 B.py 创建一个 module 对象 (&module B&) , 注意,这时创建的这个 module 对象是空的,里边啥也没有, 在 Python 内部创建了这个 module 对象之后,就会解析执行 B.py,其目的是填充 &module B& 这个 __dict__。
2、执行 B.py中的from A import C 在执行B.py的过程中,会碰到这一句, 首先检查sys.modules这个module缓存中是否已经存在&module A&了, 由于这时缓存还没有缓存&module A&, 所以类似的,Python内部会为A.py创建一个module对象(&module A&), 然后,同样地,执行A.py中的语句
3、再次执行A.py中的from B import D 这时,由于在第1步时,创建的&module B&对象已经缓存在了sys.modules中, 所以直接就得到了&module B&, 但是,注意,从整个过程来看,我们知道,这时&module B&还是一个空的对象,里面啥也没有, 所以从这个module中获得符号"D"的操作就会抛出异常。 如果这里只是import B,由于"B"这个符号在sys.modules中已经存在,所以是不会抛出异常的。
ZQ:图解如下:
3. 包 import
只要一个文件夹下面有个 __init__.py 文件,那么这个文件夹就可以看做是一个包。包导入的过程和模块的基本一致,只是导入包的时候会执行此包目录下的 __init__.py 而不是模块里面的语句了。另外,如果只是单纯的导入包,而包的 __init__.py 中又没有明确的其他初始化操作,那么此包下面的模块是不会自动导入的。
& 有下面的包结构:
& |---- __init__.py
& |---- wave.py
& |---- PB1
&&&&&&& |---- __init__.py
&&&&&&& |---- pb1_m.py
& |---- PB2
&&&&&&& |---- __init__.py
&&&&&&& |---- pb2_m.py
有如下程序:
import sys
import PA.wave
import PA.PB1
import PA.PB1.pb1_m as m1
import PA.PB2.pb2_m
PA.wave.getName()
m1.getName()
PA.PB.pb2_m.getName()
1) 当执行 #1 后,sys.modules 会同时存在 PA、PA.wave 两个模块,此时可以调用 PA.wave 的任何类或函数了。但不能调用 PA.PB1(2) 下的任何模块。当前 Local 中有了 PA 名字。
2) 当执行 #2 后,只是将 PA.PB1 载入内存,sys.modules 中会有 PA、 PA.wave、PA.PB1 三个模块,但是 PA.PB1 下的任何模块都没有自动载入内存,此时如果直接执行 PA.PB1.pb1_m.getName() 则会出错,因为 PA.PB1 中并没有 pb1_m 。当前 Local 中还是只有 PA 名字,并没有 PA.PB1 名 字。
3) 当执行 #3 后,会将 PA.PB1 下的 pb1_m 载入内存,sys.modules 中会有 PA、PA.wave、PA.PB1、PA.PB1.pb1_m 四个模块,此时可以执行 PA.PB1.pb1_m.getName() 了。由于使用了 as,当前 Local中除了 PA 名字,另外添加了 m1 作为 PA.PB1.pb1_m 的别名。
4) 当执行 #4 后,会将 PA.PB2、PA.PB2.pb2_m 载入内存,sys.modules 中会有 PA、PA.wave、PA.PB1、PA.PB1.pb1_m、PA.PB2、PA.PB2.pb2_m 六个模块。当前 Local 中还是只有 PA、m1。
下面的 #5,#6,#7 都是可以正确运行的。
注意的是:如果 PA.PB2.pb2_m 想导入 PA.PB1.pb1_m、PA.wave 是可以直接成功的。最好是采用明确的导入路径,对于 ./.. 相对导入路径还是不推荐用。
您可能感兴趣的文章:
大家感兴趣的内容
12345678910
最近更新的内容
常用在线小工具python使用内存zipfile对象在内存中打包文件示例
字体:[ ] 类型:转载 时间:
这篇文章主要介绍了python使用内存zipfile对象在内存中打包文件示例,需要的朋友可以参考下
代码如下:import zipfileimport StringIO
class InMemoryZip(object):&&& def __init__(self):&&&&&&& # Create the in-memory file-like object&&&&&&& self.in_memory_zip = StringIO.StringIO()
&&& def append(self, filename_in_zip, file_contents):&&&&&&& '''Appends a file with name filename_in_zip and contents of &&&&&&& file_contents to the in-memory zip.'''&&&&&&& # Get a handle to the in-memory zip in append mode&&&&&&& zf = zipfile.ZipFile(self.in_memory_zip, "a", zipfile.ZIP_DEFLATED, False)
&&&&&&& # Write the file to the in-memory zip&&&&&&& zf.writestr(filename_in_zip, file_contents)
&&&&&&& # Mark the files as having been created on Windows so that&&&&&&& # Unix permissions are not inferred as 0000&&&&&&& for zfile in zf.filelist:&&&&&&&&&&& zfile.create_system = 0&&&&&&&
&&&&&&& return self
&&& def read(self):&&&&&&& '''Returns a string with the contents of the in-memory zip.'''&&&&&&& self.in_memory_zip.seek(0)&&&&&&& return self.in_memory_zip.read()
&&& def writetofile(self, filename):&&&&&&& '''Writes the in-memory zip to a file.'''&&&&&&& f = file(filename, "w")&&&&&&& f.write(self.read())&&&&&&& f.close()
if __name__ == "__main__":&&& # Run a test&&& imz = InMemoryZip()&&& imz.append("test.txt", "Another test").append("test2.txt", "Still another")&&& imz.writetofile("test.zip")
您可能感兴趣的文章:
大家感兴趣的内容
12345678910
最近更新的内容
常用在线小工具  这篇博客的路线是由深入浅,所以尽管图画的花花绿绿的很好看,但是请先关注我的文字,因为初接触类的小伙伴直接看类的实现可能会觉得难度大,只要耐着性子看下去,就会有一种&拨开迷雾看未来&的感觉了。
一、python中类和对象的概念
&&&&& 首先,我们先来说说什么是类。看了很多关于python类的介绍,大多都介绍如何使用,但是对于概念却一笔带过,一个初学编程的小伙伴很难理解。
  概括的说:类可以比作是某种类型集合的描述。然而这中抽象的描述,对于初学者来说并没有什么卵用。
  今天就来详细的说说:
&&&&& 我们把一类相同的事物叫做类,其中用相同的属性(其实就是变量)描述,里面封装了相同的方法。比如,汽车是一个类,它包括价格、品牌等属性。那么我们需要打印某一辆车的价格和品牌,只需要使用一句代码 print "the car's type &ford&,price:280000",但是当我们需要对一百个品种的车打印这句话的时候,怎么办呢?
&&&&& 这个问题我们通过以前学过的函数式编程就可以实现啦!我们只需要写一个函数,然后将不同的车品牌和价格以参数的方式传到函数里就好了。这样大大的提高了代码的重用性,我们就不需要把同样的print这句话写100次了。
&&&&& 但是同样的功能,我们用类也是可以实现的,怎么实现呢?先上一张图,再来讲具体的。这里只需要大致知道这两种实现方式其实实现的功能是一样的就可以了。
1 def CarInfo(type,price):
print "the car's type %s,price:%d"%(type,price)
5 CarInfo('passat',250000)
6 CarInfo('ford',280000)
11 class Car:
def __init__(self,type,price):
self.type = type
self.price = price
def printCarInfo(self):
print "the car's Info in class:type %s,price:%d"%(self.type,self.price)
19 carOne = Car('passat',250000)
20 carTwo = Car('ford',250000)
21 carOne.printCarInfo()
22 carTwo.printCarInfo()
fnction_class_CompareCode
  我们先忽略类里面那些没见过的鬼东西,只是把这两段代码都分别拿到python里去执行,我们发现实现的功能是一样的。这说明了什么呢?其实类能实现的功能,函数几乎都可以实现,我们都知道C语言中也是没有对象的,但是它还是很腻害的写出了linux操作系统!!!知道了这一点,我们就知道,类是让我们的程序锦上添花的产物,并没那么可怕。
  接下来我们来解析这段内容,左右两边的代码是完全一样的,右边是加了解释的。
  这里结合代码来解释什么叫做类和对象,我们知道,ford和passat都是一种车,不同的车又有不同的品牌、价格。
  所以在这里,&car&就是&类&,表示&车&这一类事物,它有很多属性,比如型号、价格等等。而passat和ford都是车的一种,它是具体的,有固定的品牌和价格,所以passat是car的一个对象,ford是car的另一个对象。
二、python类中的函数和普通函数的对比
  从刚刚的讲解中,我们知道,类能实现的功能我们用函数也完全可以实现,但是我们可以看到他们的实现方式是不同的,现在我们就逐一对比一下。先上图!
  上图中的printCarInfo和CarInfo两个方法都实现了同样的功能,那么他们的差别在哪里呢?
  1.我们看到两个方法的缩进不同,printCarInfo这个方法是被包裹在car这个类里面的
  2.两个函数的参数是不同的,CarInfo方法很直接的传了cartype和price这两个参数,而在printCarInfo方法中只传递了一个self。这也直接导致了后面在函数中使用变量的时候也是不同的。
三、python类语法的初识
  使用类中的方法
 && CarInfo中的方法我们都知道是什么了,那么printCarInfo里面传递的这个&self&是个什么鬼?
  当当当,揭晓答案,这里的self就表示对象。看上面的图,我们是怎么调用car类中的printCarInfo方法的?好像和我们之前调用普通方法不一样了,前面加了一个passat和ford(使用了car的对象),而且后面根本就没有加参数,就可以在方法中直接打印出cartype和price两个变量的值。magic!这又是为什么呢?
  这里我们再来巩固一下类和对象的概念,car是一个类,它拥有品牌和价格两个属性;passat和ford是两个品牌的车,是车的一种,那么他们就拥有车的属性:品牌和价格,不仅拥有,他们的属性还是具体的、有值得,比如passat的品牌是passat,价格就是250000。
  所以当我们使用passat这个对象去调用printCarInfo这个方法的时候,其实是做了这样一部操作printCarInfo(passat),把passat这个对象传给了printCarInfo方法,passat这个对象又包含了两个属性cartype、price,我们在python规定这样使用一个对象中的变量:passat.cartype、passat.price。不要问为什么,这是语法,你这么写python就认识,不这么写它就不认识!
  此时我们就可以整理一下思路了:我们调用函数时传的passat对象的参数passat.cartype、passat.price被类中printCarInfo函数以self的身份接收,所以我们在使用参数的时候自然就变成了self.cartype、self.price。
  类的初始化
  但是计算机很傻,你要想使用这两个变量,不能上来就用呀,得先告诉python每个对象对应的属性,我们叫做对象的初始化,如下图:
  其实这两句话每句话都完成了两个功能:第一,从car类中实例化出了一个对象&&passat/ford;第二:给新对象的属性赋了值。其实passat = Car('passat',25000)还可以写成这样:
  像上左图这样写也许比较有助于我们理解类和对象,我把以前的写法放在右侧作对比。我们让passat = Car(),就是创建了car的一个对象,不要问为什么,这是语法!后面的两句话就是给passat的两个属性赋值,哈哈,感觉有点儿像字典的。就像passat = {&cartype&:&passat&,&price&:250000},只不过表现方式不同,而且类的作用可不仅仅是对对象的抽象,还封装了方法啦!呃,扯远了。。。现在我们仔细观察一下上左图的代码就会发现,下面初始化和赋值过程的写法变了,__init__方法也和右图不同,以前方法的三个参数只剩下了一个self,这是因为我们在创建对象的时候:passat = Car(),只是做了这样一件事Car(passat),把对象传给了类,并没有进行赋值,所以我们看__init__方法里,这个时候passat对象的的cattype和price都是空值,直到后面赋值之后,passat的属性才有了属于它的意义。这样我们也应该知道__init__是什么了,这个方法就是我们在创建对象的时候会自动执行的方法,当我们通过car类实例化一个对象的时候,程序会自动执行这个类的__init__方法。然后也会自动的按照init方法中的代码给这个对象中的属性赋值。
&&&&& 类中方法的定义和使用
  在最开始,我们已经知道使用类的对象就可以调用类中的方法,其实在类中的方法和普通函数的却别很小,先上图对比一下:
  我们根据上图来比较,先来看函数的定义,从图中很明显就可以看出,CarInfo中的参数在printCarInfo方法中的换成了self,在方法的调用中,就是用self.属性名来调用了。
  再来看方法的调用,普通函数的调用直接调用就可以了,而类中的函数调用之前应该先进行类的实例化&&创建一个对象,然后给这个对象的属性赋值,然后才可以调用类中的方法,调用方式是 对象名.方法名()。
四、类存在的意义及对象的应用
  我们在本文的开篇就说过,类能实现的功能,用函数也可以实现,那么类的存在还有什么特殊的意义呢?我们都知道函数存在的意义是为了避免代码的重用,我们举个栗子:我有一辆车passat,你有一辆车ford,他们都有计算里程这个功能,因此我们写了一个方法,叫做&DriveDistance&,passat和ford都可以调用它,那么问题来了,我们怎么知道是谁跑了多少里程呢?从函数的角度来讲,我们当然可以自己定义变量来解决这个问题,但是类又是怎么实现的呢?
  好了,来看实现,上面是函数方法实现,下面是类方法实现,左图我画出了所有的区别,为了看着不闹心右边放了原图对比。先看方法的定义,我们看到橘色框框中标出了两个方法的参数不同,现在我们已经知道self是对象,在类方法中,对象是必须的参数,因为我们在之前讲到过,都是使用 对象名.方法名 调用方法,passat.DriverDistance()的意思是DriverDistance(passat),那么&passat.DriverDistance(20)的意思翻译过来就是DriverDistance(passat,20),所以无论如何self参数是必须的,这个记着就行。然后我们再来看函数的实现,灰框框里面的内容,是用车从前跑的距离加上新跑的距离就是总共的行驶里程。函数里的实现方法很好理解,我们现在来看看类中的实现方式,是用对象原本的dictance加上新参数的dictance,并赋值给了这个对象的dictance属性。所以我们看黄色框框里面的内容,在函数的实现中我们需要将函数的执行结果返回调用者,但是在类的实现过程中,却不需要,因为我们修改的是对象的属性,在其类方法中修改了,我们再使用的时候就是使用了修改后的值。这里首先解释了红框框中不需要返回值的现象,然后解释了蓝框框中在我们打印现在的形式里程的时候,直接用 passat.dictance就可以了。
五、内存眼中的类与对象
  类和对象的基础概念和使用方法到这里就差不多了,然,总会有很多文艺小青年儿在不停的追逐,所以在这里站在内存的角度上来解释一下,如果对前面的内容还有疑问,请慎入。先上图!
  看上面的图,左侧是代码,右侧是执行结果。一时抽风,把能打印的都打印了,我们挑有意义的来说,首先我们看passat,ford初始化之后,我分别打印了两个对象的地址,发现两个对象虽然都是Car实例化的结果,但是实例化之后,都分别有了自己的内存地址,但是在at之前有表明了是car的实例。这说明什么?同一个类实例化出来对象之间的内存是独立哒,所以passat.cartype和ford.cartype是两个独立的变量,他们都和自己的对象放在一起,不会混乱。接下来我们来看这两个变量调用方法的地址,我们看到at前面的内容都是一样哒,表示是Car类中的printCarInfo方法,而at后面的内容我们仔细对比之后就可以发现是和前面对象的地址一样的,那么这个时候我们就知道,尽管函数我们只定义了一个,但是函数确是和对象绑定的,函数里面用到的参数也是对象地址中存储的参数。这样看来,其实类也没有什么难,nie?
阅读(...) 评论()}

我要回帖

更多关于 python 对象内存大小 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信