赞
踩
目录
如何简单地理解Python中的if __name__ == '__main__'
2.2 修改const.py,添加if __name__ == "__main__"
import 和 from … import 模块的变量、方法引用差异
#示例代码基于py3.6
一直对Python程序的执行顺序有些疑惑,例如python程序是顺序执行的,那怎么还有main函数的出现呢?
在查阅了资料后,参见这里后,算是有点明白了:
1.python程序是顺序执行的,而C++中main()是程序的入口
例如以下代码,结果如注释所示,这里虽然有个main函数,但是最先输出的不是“main”而是“test1”:
- 1 #test1
- 2 print ("test1")
- 3 def Fun():
- 4 print ("Fun")
- 5 def main():
- 6 print ("main")
- 7 Fun()
- 8 if __name__ == '__main__':
- 9 main()
- 10 '''
- 11 test112 main13 Fun14 '''
2.一段python程序以py文件运行时,文件属性__name__为main;作为模块导入时,文件属性__name__为文件名:
- 1 #test.py
- 2 def Fun():
- 3 print ("Fun")
- 4 if __name__ == '__main__':
- 5 print ("main")
- 6 Fun()
- 7 '''
- 8 main
- 9 Fun
- 10 '''
3.总结
C++中一main函数为执行的起点;Python中首先执行最先出现的非函数定义和非类定义的没有缩进的代码,如示例一之中的第一行,一份程序为了区分主动执行还是被调用,Python引入了变量__name__,当文件是被调用时,__name__的值为模块名,当文件被执行时,__name__为'__main__'
所以会经常看到别人的代码这么写,同时也是典型的python文件结构:
- 1 #/usr/bin/env/ python #(1) 起始行
- 2 #"this is a test module" #(2) 模块文档(文档字符串)
- 3 import sys
- 4 import os #(3) 模块导入
- 5 6 debug = True #(4) (全局)变量定义
- 7 class FooClass (object):
- 8 'foo class'
- 9 pass #(5) 类定义(若有)
- 10 def main():
- 11 'test function'
- 12 foo = FooClass()
- 13 if debug:
- 14 print 'ran test()' #(6) 函数定义(若有)
- 15 if __name__ == '__main__':
- 16 main()
若是文件主动执行了,则最好写成跟上面的例子一样,main之前不要有可执行代码,这样做到程序从main()开始,流程逻辑性强,若是文件作为模块被调用,则可以不用写main(),从上而下顺序执行。
python 有两个内建的模块用于处理命令行参数:
add_option用来加入选项,action是有store,store_true,store_false等,dest是存储的变量,default是缺省值,help是帮助提示 ,最后通过parse_args()函数的解析,获得选项,如options.pdcl的值。使用时和flink的 ParameterTool 一样
使用案例:
- self._option_parser = optparse.OptionParser()
- self._option_parser.add_option("--app", help=u"应用程序列表,以逗号分隔", dest="user_app")
- self._option_parser.add_option("--phone", help=u"手机号", dest="phone")
- self._option_parser.add_option("--user_mail", help=u"接收邮箱账号,逗号分隔", dest="user_mail")
- self._option_parser.add_option("--title", help=u"邮箱标题", dest="title")
通俗的理解__name__ == '__main__':假如你叫小明.py,在朋友眼中,你是小明(__name__ == '小明');在你自己眼中,你是你自己(__name__ == '__main__')。
if __name__ == '__main__'的意思是:当.py文件被直接运行时,if __name__ == '__main__'之下的代码块将被运行;当.py文件以模块形式被导入时,if __name__ == '__main__'之下的代码块不被运行。
对于很多编程语言来说,程序都必须要有一个入口,比如C,C++,以及完全面向对象的编程语言Java,C#等。如果你接触过这些语言,对于程序入口这个概念应该很好理解,C,C++都需要有一个main函数作为程序的入口,也就是程序的运行会从main函数开始。同样,Java,C#必须要有一个包含Main方法的主类,作为程序入口。
而Python则不同,它属于脚本语言,不像编译型语言那样先将程序编译成二进制再运行,而是动态的逐行解释运行。也就是从脚本第一行开始运行,没有统一的入口。
一个Python源码文件(.py)除了可以被直接运行外,还可以作为模块(也就是库),被其他.py文件导入。不管是直接运行还是被导入,.py文件的最顶层代码都会被运行(Python用缩进来区分代码层次),而当一个.py文件作为模块被导入时,我们可能不希望一部分代码被运行。
假设我们有一个const.py文件,内容如下:
PI = 3.14
def main():
print("PI:", PI)
main()
# 运行结果:PI: 3.14
现在,我们写一个用于计算圆面积的area.py文件,area.py文件需要用到const.py文件中的PI变量。从const.py中,我们把PI变量导入area.py:
- from const import PI
- def calc_round_area(radius):
- return PI * (radius ** 2)
- def main():
- print("round area: ", calc_round_area(2))
- main()
- '''
- 运行结果:
- PI: 3.14
- round area: 12.56
- '''
-
2.2 修改const.py,添加if __name__ == "__main__"
我们看到const.py中的main函数也被运行了,实际上我们不希望它被运行,因为const.py提供的main函数只是为了测试常量定义。这时if __name__ == '__main__'派上了用场,我们把const.py改一下,添加if __name__ == "__main__":
- PI = 3.14
- def main():
- print("PI:", PI)
- if __name__ == "__main__":
- main()
- 运行const.py,输出如下:
- PI: 3.14
- 运行area.py,输出如下:
- round area: 12.56
-
如上,我们可以看到if __name__ == '__main__'相当于Python模拟的程序入口,Python本身并没有这么规定,这只是一种编码习惯。由于模块之间相互引用,不同模块可能有这样的定义,而程序入口只有一个。到底哪个程序入口被选中,这取决于__name__的值。
__name__是内置变量,可用于反映一个包的结构。假设我们有一个包a,包的结构如下:
a
├── b
│ ├── c.py
│ └── __init__.py
└── __init__.py
在包a中,文件c.py,__init__.py,__init__.py的内容都为:
print(__name__)
当一个.py文件(模块)被其他.py文件(模块)导入时,我们在命令行执行
python -c "import a.b.c"
输出结果:
aa.ba.b.c
由此可见,__name__可以清晰地反映一个模块在包中的层次。
__name__是内置变量,可用于表示当前模块的名字。我们直接运行一个.py文件(模块)
python a/b/c.py
输出结果:
__main__
由此我们可知:如果一个.py文件(模块)被直接运行时,则其没有包结构,其__name__值为__main__,即模块名为__main__。
所以,if __name__ == '__main__'的意思是:当.py文件被直接运行时,if __name__ == '__main__'之下的代码块将被运行;当.py文件以模块形式被导入时,if __name__ == '__main__'之下的代码块不被运行。
Python的-m参数用于将一个模块或者包作为一个脚本运行,而__main__.py文件相当于是一个包的“入口程序“。
假设我们有一个文件run.py,内容如下:
import sys
print(sys.path)
我们用直接运行的方式启动
python run.py
输出结果(为了说明问题,输出结果只截取了重要部分,下同):
['/home/huoty/aboutme/pythonstudy/main', ...]
然后以模块的方式运行:
python -m run.py
输出内容
['', ...]
/usr/bin/python: No module named run.py
由于输出结果只列出了关键的部分,应该很容易看出他们之间的差异:
直接运行方式是把run.py文件所在的目录放到了sys.path属性中
以模块方式运行是把你输入命令的目录(也就是当前工作路径),放到了 sys.path 属性中。
以模块方式运行还有一个不同的地方:多出了一行No module named run.py的错误。实际上以模块方式运行时,Python先对run.py执行一遍 import,所以print(sys.path)被成功执行,然后Python才尝试运行run.py模块,但是在path变量中并没有run.py这个模块,所以报错。正确的运行方式,应该是python -m run。
仍然先看例子,假设我们有如下一个包package:
package
├── __init__.py
└── __main__.py
其中,文件__init__.py的内容
import sys
print("__init__")
print(sys.path)
其中,文件__main__.py的内容
import sys
print("__main__")
print(sys.path)
接下来,我们运行这个package,使用python -m package运行,输出结果:
__init__
['', ...]
__main__
['', ...]
使用python package运行,输出结果:
__main__
['package', ...]
总结一下
当加上-m参数时,Python会把当前工作目录添加到sys.path中;而不加-m时,Python则会把脚本所在目录添加到sys.path中。
当加上-m参数时,Python会先将模块或者包导入,然后再执行。
__main__.py文件是一个包或者目录的入口程序。不管是用python package还是用python -m package运行,__main__.py文件总是被执行。
1、os.sep
获得当前操作系统使用的目录分隔符,比如 Windows 就会得到\而 Linux/Unix 就会得到/
os.name
获得当前使用的操作系统,Windows 是 NT 内核,所以会得到nt,而 Linux/Unix 用户则会得到posix
2、os.getcwd()
获得当前工作目录,即当前 Python 脚本工作的目录路径。
3、os.getenv()
用来获得环境变量
1 | os.getenv('PATH') |
4、os.environ
可以获取并修改环境变量
1 2 3 | print(os.environ['PATH']) os.environ += 'D:/testdir/bin/' print(os.environ["PATH"]) |
5、os.listdir()
列出某目录下所有的目录和文件
1 | print(os.listdir()) |
6、os.remove()
删除文件
1 | os.remove('D:/test.file') |
7、os.system()
运行 Shell 或者 CMD 命令
1 | os.system('ifconfig') |
8、os.linesep
获取当前平台使用的行终止符。例如,Windows 使用\r\n,Linux 使用\n而 Mac 使用\r。
9、os.path.split()
获得一个列表,list[0] 是路径的,list[1] 是文件名
1 2 3 | path = 'D:/game/gtav/bin/gtav.exe' print(os.path.split(path)[0]) print(os.path.split(path)[1]) |
10、os.path.isfile() 和 os.path.isdir()
判断路径是不是文件 / 目录
1 2 | print(os.path.isfile('D:/game/gtav/bin/gtav.exe')) print(os.path.isdir('D:/game/gtav/bin')) |
11、os.path.existe()
函数用来检验给出的路径是否真地存在
简述
就是新建一个管道执行一个命令。
方法是os.popen(命令,权限,缓冲大小)
比如
a = 'mkdir def'
b = os.popen(a,'r',1)
print b
就是等同于使用命令去创建了一个def的文件夹,r是其权限,1是缓冲大小。第二个第三个参数都是可选的。
sys.argv: 实现从程序外部向程序传递参数。
sys.exit([arg]): 程序中间的退出,arg=0为正常退出。
sys.getdefaultencoding(): 获取系统当前编码,一般默认为ascii。
sys.setdefaultencoding(): 设置系统默认编码,执行dir(sys)时不会看到这个方法,在解释器中执行不通过,可以先执行reload(sys),在执行 setdefaultencoding('utf8'),此时将系统默认编码设置为utf8。(见设置系统默认编码 )
sys.getfilesystemencoding(): 获取文件系统使用编码方式,Windows下返回'mbcs',mac下返回'utf-8'.
sys.path: 获取指定模块搜索路径的字符串集合,可以将写好的模块放在得到的某个路径下,就可以在程序中import时正确找到。
sys.platform: 获取当前系统平台。
sys.stdin,sys.stdout,sys.stderr: stdin , stdout , 以及stderr 变量包含与标准I/O 流对应的流对象. 如果需要更好地控制输出,而print 不能满足你的要求, 它们就是你所需要的. 你也可以替换它们, 这时候你就可以重定向输出和输入到其它设备( device ), 或者以非标准的方式处理它们
reload() 用于重新载入之前载入的模块。
reload() 函数语法:
reload(module)
module -- 模块对象。
返回模块对象。
以下实例展示了 reload() 的使用方法:
>>>import sys >>> sys.getdefaultencoding() # 当前默认编码 'ascii' >>> reload(sys) # 使用 reload <module 'sys' (built-in)> >>> sys.setdefaultencoding('utf8') # 设置编码 >>> sys.getdefaultencoding() 'utf8' >>>
reload 会重新加载已加载的模块,但原来已经使用的实例还是会使用旧的模块,而新生产的实例会使用新的模块;
reload 后还是用原来的内存地址;
reload 不支持 from ××× import ××× 格式的模块进行重新加载。
os 模块提供了很多与操作系统交互的函数:
>>> import os>>> os.getcwd() # Return the current working directory'C:\\Python27'>>> os.chdir('/server/accesslogs') # Change current working directory>>> os.system('mkdir today') # Run the command mkdir in the system shell0
应该用 import os 风格而非 from os import *。这样可以保证随操作系统不同而有所变化的 os.open() 不会覆盖内置函数 open()
在使用一些像 os 这样的大型模块时内置的 dir() 和 help() 函数非常有用:
>>> import os>>> dir(os)<returns a list of all module functions>>>> help(os)<returns an extensive manual page created from the module's docstrings>
针对日常的文件和目录管理任务,shutil 模块提供了一个易于使用的高级接口:
>>> import shutil>>> shutil.copyfile('data.db', 'archive.db')>>> shutil.move('/build/executables', 'installdir')
glob 模块提供了一个函数用于从目录通配符搜索中生成文件列表:
>>> import glob>>> glob.glob('*.py')['primes.py', 'random.py', 'quote.py']
通用工具脚本经常调用命令行参数。这些命令行参数以链表形式存储于 sys 模块的 argv 变量。例如在命令行中执行 python demo.py one two three 后可以得到以下输出结果:
>>> import sys>>> print sys.argv['demo.py', 'one', 'two', 'three']
getopt 模块使用 Unix getopt() 函数处理 sys.argv。更多的复杂命令行处理由 argparse 模块提供。
sys 还有 stdin, stdout 和 stderr 属性,即使在 stdout 被重定向时,后者也可以用于显示警告和错误信息:
>>> sys.stderr.write('Warning, log file not found starting a new one\n')Warning, log file not found starting a new one
大多脚本的定向终止都使用 sys.exit() 。
re 模块为高级字符串处理提供了正则表达式工具。对于复杂的匹配和处理,正则表达式提供了简洁、优化的解决方案:
>>> import re>>> re.findall(r'\bf[a-z]*', 'which foot or hand fell fastest')['foot', 'fell', 'fastest']>>> re.sub(r'(\b[a-z]+) \1', r'\1', 'cat in the the hat')'cat in the hat'
只需简单的操作时,字符串方法最好用,因为它们易读,又容易调试:
>>> 'tea for too'.replace('too', 'two')'tea for two'
math 模块为浮点运算提供了对底层 C 函数库的访问:
>>> import math>>> math.cos(math.pi / 4.0)0.70710678118654757>>> math.log(1024, 2)10.0
random 提供了生成随机数的工具:
>>> import random>>> random.choice(['apple', 'pear', 'banana'])'apple'>>> random.sample(xrange(100), 10) # sampling without replacement[30, 83, 16, 4, 8, 81, 41, 50, 18, 33]>>> random.random() # random float0.17970987693706186>>> random.randrange(6) # random integer chosen from range(6)4
有几个模块用于访问互联网以及处理网络通信协议。其中最简单的两个是用于处理从 urls 接收的数据的 urllib2 以及用于发送电子邮件的 smtplib:
>>> import urllib2>>> for line in urllib2.urlopen('http://tycho.usno.navy.mil/cgi-bin/timer.pl'):... line = line.decode('utf-8') # Decoding the binary data to text.... if 'EST' in line or 'EDT' in line: # look for Eastern Time... print line
<BR>Nov. 25, 09:43:32 PM EST
>>> import smtplib>>> server = smtplib.SMTP('localhost')>>> server.sendmail('soothsayer@example.org', 'jcaesar@example.org',... """To: jcaesar@example.org... From: soothsayer@example.org...... Beware the Ides of March.... """)>>> server.quit()
(注意第二个例子需要在 localhost 运行一个邮件服务器。)
datetime 模块为日期和时间处理同时提供了简单和复杂的方法。支持日期和时间算法的同时,实现的重点放在更有效的处理和格式化输出。该模块还支持时区处理:
>>> # dates are easily constructed and formatted>>> from datetime import date>>> now = date.today()>>> nowdatetime.date(2003, 12, 2)>>> now.strftime("%m-%d-%y. %d %b %Y is a %A on the %d day of %B.")'12-02-03. 02 Dec 2003 is a Tuesday on the 02 day of December.'
>>> # dates support calendar arithmetic>>> birthday = date(1964, 7, 31)>>> age = now - birthday>>> age.days14368
以下模块直接支持通用的数据打包和压缩格式:zlib,gzip,bz2,zipfile 以及 tarfile:
>>> import zlib>>> s = b'witch which has which witches wrist watch'>>> len(s)41>>> t = zlib.compress(s)>>> len(t)37>>> zlib.decompress(t)b'witch which has which witches wrist watch'>>> zlib.crc32(s)226805979
有些用户对了解解决同一问题的不同方法之间的性能差异很感兴趣。Python 提供了一个度量工具,为这些问题提供了直接答案。
例如,使用元组封装和拆封来交换元素看起来要比使用传统的方法要诱人的多。timeit 证明了后者更快一些:
>>> from timeit import Timer>>> Timer('t=a; a=b; b=t', 'a=1; b=2').timeit()0.57535828626024577>>> Timer('a,b = b,a', 'a=1; b=2').timeit()0.54962537085770791
相对于 timeit 的细粒度,profile 和 pstats 模块提供了针对更大代码块的时间度量工具。
开发高质量软件的方法之一是为每一个函数开发测试代码,并且在开发过程中经常进行测试。
doctest 模块提供了一个工具,扫描模块并根据程序中内嵌的文档字符串执行测试。测试构造如同简单的将它的输出结果剪切并粘贴到文档字符串中。通过用户提供的例子,它发展了文档,允许 doctest 模块确认代码的结果是否与文档一致:
def average(values):
"""Computes the arithmetic mean of a list of numbers.
>>> print average([20, 30, 70]) 40.0 """
return sum(values, 0.0) / len(values)
import doctestdoctest.testmod() # automatically validate the embedded tests
unittest 模块不像 doctest 模块那么容易使用,不过它可以在一个独立的文件里提供一个更全面的测试集:
import unittest
class TestStatisticalFunctions(unittest.TestCase):
def test_average(self):
self.assertEqual(average([20, 30, 70]), 40.0)
self.assertEqual(round(average([1, 5, 7]), 1), 4.3)
self.assertRaises(ZeroDivisionError, average, [])
self.assertRaises(TypeError, average, 20, 30, 70)
unittest.main() # Calling from the command line invokes all tests
Python 展现了“瑞士军刀”的哲学。这可以通过它更大的包的高级和健壮的功能来得到最好的展现。例如:
xmlrpclib 和 SimpleXMLRPCServer 模块让远程过程调用变得轻而易举。
尽管模块有这样的名字,用户无需拥有XML的知识或处理 XML。
email 包是一个管理邮件信息的库,包括MIME和其它基于 RFC2822 的信息文档
不同于实际发送和接收信息的 smtplib 和 poplib 模块,email 包包含一个构造或解析复杂消息结构(包括附件)及实现互联网编码和头协议的完整工具集。
xml.dom 和 xml.sax 包为流行的信息交换格式提供了强大的支持。
同样,csv 模块支持在通用数据库格式中直接读写。综合起来,这些模块和包大大简化了 Python 应用程序和其它工具之间的数据交换。
国际化由 gettext, locale 和 codecs 包支持。
还是上面例子中的模块 support.py:
def print_func( par ):
print "Hello : ", par
return
使用 import 引入并调用 support 模块的正确方法:
#!/usr/bin/python# -*- coding: UTF-8 -*-
# 导入模块import support
# 现在可以调用模块里包含的函数了
support.print_func("Runoob")
提示:并不能直接使用 print_func() 实现调用,必须将引入的模块名称当作一个对象,调用这个模块对象下的方法 print_func,这时才能实现调用。
使用 from … import 模块的正确方法:
#!/usr/bin/python# -*- coding: UTF-8 -*-
# 导入模块from support import *
# 现在可以调用模块里包含的函数了
print_func("Runoob")
提示:可以直接使用 print_func() 实现调用。
笔者建议:一般来说,推荐使用 import 语句,避免使用 from … import,因为这样可以使你的程序更加易读,也可以避免名称冲突。
from 文件夹名/py文件名 import 类名
#第一种情况
from spider.models import *
Product.objects.get(productId = 1)
#第二种情况
import spider.models
spider.models.Product.objects.get()
引用知乎大神的解释:
from import : 从车里把矿泉水拿出来,给我
import : 把车给我
repr 模块为大型的或深度嵌套的容器缩写显示提供了 repr() 函数的一个定制版本:
>>> import repr>>> repr.repr(set('supercalifragilisticexpialidocious'))"set(['a', 'c', 'd', 'e', 'f', 'g', ...])"
pprint 模块给老手提供了一种解释器可读的方式深入控制内置和用户自定义对象的打印。当输出超过一行的时候,“美化打印(pretty printer)”添加断行和标识符,使得数据结构显示的更清晰:
>>> import pprint>>> t = [[[['black', 'cyan'], 'white', ['green', 'red']], [['magenta',... 'yellow'], 'blue']]]...>>> pprint.pprint(t, width=30)[[[['black', 'cyan'], 'white', ['green', 'red']], [['magenta', 'yellow'], 'blue']]]
textwrap 模块格式化文本段落以适应设定的屏宽:
>>> import textwrap>>> doc = """The wrap() method is just like fill() except that it returns... a list of strings instead of one big string with newlines to separate... the wrapped lines."""...>>> print textwrap.fill(doc, width=40)The wrap() method is just like fill()except that it returns a list of stringsinstead of one big string with newlinesto separate the wrapped lines.
locale 模块按访问预定好的国家信息数据库。locale 的格式化函数属性集提供了一个直接方式以分组标示格式化数字:
>>> import locale>>> locale.setlocale(locale.LC_ALL, 'English_United States.1252')'English_United States.1252'>>> conv = locale.localeconv() # get a mapping of conventions>>> x = 1234567.8>>> locale.format("%d", x, grouping=True)'1,234,567'>>> locale.format_string("%s%.*f", (conv['currency_symbol'],... conv['frac_digits'], x), grouping=True)'$1,234,567.80'
string 提供了一个灵活多变的模版类 Template ,使用它最终用户可以简单地进行编辑。这使用户可以在不进行改变的情况下定制他们的应用程序。
格式使用 $ 为开头的 Python 合法标识(数字、字母和下划线)作为占位符。占位符外面的大括号使它可以和其它的字符不加空格混在一起。$$ 创建一个单独的 $:
>>> from string import Template>>> t = Template('${village}folk send $$10 to $cause.')>>> t.substitute(village='Nottingham', cause='the ditch fund')'Nottinghamfolk send $10 to the ditch fund.'
当一个占位符在字典或关键字参数中没有被提供时,substitute() 方法就会抛出一个 KeyError 异常。对于邮件合并风格的应用程序,用户提供的数据可能并不完整,这时使用 safe_substitute() 方法可能更适合。如果数据不完整,它就不会改变占位符:
>>> t = Template('Return the $item to $owner.')>>> d = dict(item='unladen swallow')>>> t.substitute(d)Traceback (most recent call last): . . .KeyError: 'owner'>>> t.safe_substitute(d)'Return the unladen swallow to $owner.'
模板子类可以指定一个自定义分隔符。例如,图像查看器的批量重命名工具可能选择使用百分号作为占位符,像当前日期,图片序列号或文件格式:
>>> import time, os.path>>> photofiles = ['img_1074.jpg', 'img_1076.jpg', 'img_1077.jpg']>>> class BatchRename(Template):... delimiter = '%'>>> fmt = input('Enter rename style (%d-date %n-seqnum %f-format): ')Enter rename style (%d-date %n-seqnum %f-format): Ashley_%n%f
>>> t = BatchRename(fmt)>>> date = time.strftime('%d%b%y')>>> for i, filename in enumerate(photofiles):... base, ext = os.path.splitext(filename)... newname = t.substitute(d=date, n=i, f=ext)... print('{0} --> {1}'.format(filename, newname))
img_1074.jpg --> Ashley_0.jpgimg_1076.jpg --> Ashley_1.jpgimg_1077.jpg --> Ashley_2.jpg
模板的另一个应用是把多样的输出格式细节从程序逻辑中分类出来。这便使得 XML 文件,纯文本报表和 HTML WEB 报表定制模板成为可能。
struct 模块为使用变长的二进制记录格式提供了 pack() 和 unpack() 函数。下面的示例演示了在不使用 zipfile 模块的情况下如何迭代一个 ZIP 文件的头信息。压缩码 "H" 和 "I" 分别表示2和4字节无符号数字,"<" 表明它们都是标准大小并且按照 little-endian 字节排序:
import struct
with open('myfile.zip', 'rb') as f:
data = f.read()
start = 0for i in range(3): # show the first 3 file headers
start += 14
fields = struct.unpack('<IIIHH', data[start:start+16])
crc32, comp_size, uncomp_size, filenamesize, extra_size = fields
start += 16
filename = data[start:start+filenamesize]
start += filenamesize
extra = data[start:start+extra_size]
print filename, hex(crc32), comp_size, uncomp_size
start += extra_size + comp_size # skip to the next header
线程是一个分离无顺序依赖关系任务的技术。在某些任务运行于后台的时候应用程序会变得迟缓,线程可以提升其速度。一个有关的用途是在 I/O 的同时其它线程可以并行计算。
下面的代码显示了高级模块 threading 如何在主程序运行的同时运行任务:
import threading, zipfile
class AsyncZip(threading.Thread):
def __init__(self, infile, outfile):
threading.Thread.__init__(self)
self.infile = infile
self.outfile = outfile
def run(self):
f = zipfile.ZipFile(self.outfile, 'w', zipfile.ZIP_DEFLATED)
f.write(self.infile)
f.close()
print 'Finished background zip of:', self.infile
background = AsyncZip('mydata.txt', 'myarchive.zip')background.start()print 'The main program continues to run in foreground.'
background.join() # Wait for the background task to finishprint 'Main program waited until background was done.'
多线程应用程序的主要挑战是协调线程,诸如线程间共享数据或其它资源。为了达到那个目的,线程模块提供了许多同步化的原生支持,包括:锁,事件,条件变量和信号灯。
尽管这些工具很强大,微小的设计错误也可能造成难以挽回的故障。因此,任务协调的首选方法是把对一个资源的所有访问集中在一个单独的线程中,然后使用 Queue 模块用那个线程服务其他线程的请求。为内部线程通信和协调而使用 Queue.Queue 对象的应用程序更易于设计,更可读,并且更可靠。
logging 模块提供了完整和灵活的日志系统。它最简单的用法是记录信息并发送到一个文件或 sys.stderr:
import logginglogging.debug('Debugging information')logging.info('Informational message')logging.warning('Warning:config file %s not found', 'server.conf')logging.error('Error occurred')logging.critical('Critical error -- shutting down')
输出如下:
WARNING:root:Warning:config file server.conf not foundERROR:root:Error occurredCRITICAL:root:Critical error -- shutting down
默认情况下捕获信息和调试消息并将输出发送到标准错误流。其它可选的路由信息方式通过 email,数据报文,socket 或者 HTTP Server。基于消息属性,新的过滤器可以选择不同的路由:DEBUG,INFO,WARNING,ERROR 和 CRITICAL 。
日志系统可以直接在 Python 代码中定制,也可以不经过应用程序直接在一个用户可编辑的配置文件中加载。
Python 自动进行内存管理(对大多数的对象进行引用计数和垃圾回收 garbage collection 以循环利用)在最后一个引用消失后,内存会很快释放。
这个工作方式对大多数应用程序工作良好,但是偶尔会需要跟踪对象来做一些事。不幸的是,仅仅为跟踪它们创建引用也会使其长期存在。weakref 模块提供了不用创建引用的跟踪对象工具,一旦对象不再存在,它自动从弱引用表上删除并触发回调。典型的应用包括捕获难以构造的对象:
>>> import weakref, gc>>> class A:... def __init__(self, value):... self.value = value... def __repr__(self):... return str(self.value)...>>> a = A(10) # create a reference>>> d = weakref.WeakValueDictionary()>>> d['primary'] = a # does not create a reference>>> d['primary'] # fetch the object if it is still alive10>>> del a # remove the one reference>>> gc.collect() # run garbage collection right away0>>> d['primary'] # entry was automatically removedTraceback (most recent call last):
File "<stdin>", line 1, in <module>
d['primary'] # entry was automatically removed
File "C:/python33/lib/weakref.py", line 46, in __getitem__
o = self.data[key]()KeyError: 'primary'
很多数据结构可能会用到内置列表类型。然而,有时可能需要不同性能代价的实现。
array 模块提供了一个类似列表的 array() 对象,它仅仅是存储数据,更为紧凑。以下的示例演示了一个存储双字节无符号整数的数组(类型编码 "H" )而非存储 16 字节 Python 整数对象的普通正规列表:
>>> from array import array>>> a = array('H', [4000, 10, 700, 22222])>>> sum(a)26932>>> a[1:3]array('H', [10, 700])
collections 模块提供了类似列表的 deque() 对象,它从左边添加(append)和弹出(pop)更快,但是在内部查询更慢。这些对象更适用于队列实现和广度优先的树搜索:
>>> from collections import deque>>> d = deque(["task1", "task2", "task3"])>>> d.append("task4")>>> print "Handling", d.popleft()Handling task1
unsearched = deque([starting_node])def breadth_first_search(unsearched): node = unsearched.popleft() for m in gen_moves(node): if is_goal(m): return m unsearched.append(m)
除了链表的替代实现,该库还提供了 bisect 这样的模块以操作存储链表:
>>> import bisect>>> scores = [(100, 'perl'), (200, 'tcl'), (400, 'lua'), (500, 'python')]>>> bisect.insort(scores, (300, 'ruby'))>>> scores[(100, 'perl'), (200, 'tcl'), (300, 'ruby'), (400, 'lua'), (500, 'python')]
heapq 提供了基于正规链表的堆实现。最小的值总是保持在 0 点。这在希望循环访问最小元素但是不想执行完整堆排序的时候非常有用:
>>> from heapq import heapify, heappop, heappush>>> data = [1, 3, 5, 7, 9, 2, 4, 6, 8, 0]>>> heapify(data) # rearrange the list into heap order>>> heappush(data, -5) # add a new entry>>> [heappop(data) for i in range(3)] # fetch the three smallest entries[-5, 0, 1]
decimal 模块提供了一个 Decimal 数据类型用于浮点数计算。相比内置的二进制浮点数实现 float,这个类型有助于:
金融应用和其它需要精确十进制表达的场合,
控制精度,
控制舍入以适应法律或者规定要求,
确保十进制数位精度,
或者
用户希望计算结果与手算相符的场合。
例如,计算 70 分电话费的 5% 税计算,十进制浮点数和二进制浮点数计算结果的差别如下。如果在分值上舍入,这个差别就很重要了:
>>> from decimal import *>>> round(Decimal('0.70') * Decimal('1.05'), 2)Decimal('0.74')>>> round(.70 * 1.05, 2)0.73
Decimal 的结果总是保有结尾的 0,自动从两位精度延伸到4位。Decimal 重现了手工的数学运算,这就确保了二进制浮点数无法精确保有的数据精度。
高精度使 Decimal 可以执行二进制浮点数无法进行的模运算和等值测试:
>>> Decimal('1.00') % Decimal('.10')Decimal('0.00')>>> 1.00 % 0.100.09999999999999995
>>> sum([Decimal('0.1')]*10) == Decimal('1.0')True>>> sum([0.1]*10) == 1.0False
decimal 提供了必须的高精度算法:
>>> getcontext().prec = 36>>> Decimal(1) / Decimal(7)Decimal('0.142857142857142857142857142857142857')
在讲is和==这两种运算符区别之前,首先要知道Python中对象包含的三个基本要素
分别是:id(身份标识)、type(数据类型)和value(值)。
is和==都是对对象进行比较判断作用的,但对对象比较判断的内容并不相同。下面来看看具体区别在哪。
==比较操作符和is同一性运算符区别
==是python标准操作符中的比较操作符,用来比较判断两个对象的value(值)是否相等,例如下面两个字符串间的比较:
注意:Python里和None比较时,为什么是 is None 而不是 == None
例1.
- >>> a = 'cheesezh'
- >>> b = 'cheesezh'
- >>> a == b
- True
is也被叫做同一性运算符,这个运算符比较判断的是对象间的唯一身份标识,也就是id是否相同。通过对下面几个list间的比较,你就会明白is同一性运算符的工作原理:
例2.
- >>> x = y = [4,5,6]
- >>> z = [4,5,6]
- >>> x == y True
- >>> x == z True
- >>> x is y True
- >>> x is z False
- >>> print id(x) 3075326572
- >>> print id(y) 3075326572
- >>> print id(z) 3075328140
Python中有可变对象和不可变对象之分。可变对象创建后可改变但地址不会改变,即变量指向的还是原来的变量;
不可变对象创建之后便不能改变,如果改变则会指向一个新的对象。Python中dict、list是可变对象,str、int、tuple、float是不可变对象
可变对象和不可变对象中讲过字符串是不可变对象,当用操作符+连接字符串的时候,每执行一次+都会申请一块新的内存,然后复制上一个+操作的结果和本次操作的右操作符到这块内存空间,因此用+连接字符串的时候会涉及好几次内存申请和复制。而join在连接字符串的时候,会先计算需要多大的内存存放结果,然后一次性申请所需内存并将字符串复制过去,这是为什么join的性能优于+的原因。所以在连接字符串数组的时候,我们应考虑优先使用join
join() 方法:
用于将序列中的元素以指定的字符连接生成一个新的字符串。
join()方法语法:
str.join(sequence):sequence -- 要连接的元素序列,str指定的字符串符
返回通过指定字符连接序列中元素后生成的新字符串。
实例
- #!/usr/bin/python # -*- coding:
- UTF-8 -*- str = "-";
- seq = ("a", "b", "c");
- # 字符串序列 print str.join( seq );
- 以上实例输出结果如下:
- a-b-c
sys.path是Python的搜索模块的路径集,是一个list可以在python 环境下使用sys.path.append(path)添加相关的路径, 比如,经常遇到这样一种情况,自己编写的一些模块,想比较清晰地管理不同的模块,所以在当前目录下面建立了不同的子目录,在子目录mod里包含着要使用的py文件,如果想要使用它,可以按模块的方式来导入,但是有一种更简单的方法,就是让python搜索到mod目录,即可以使用了
- import sys
- sys.path.append("mod/")
- import test2
- print(test2.test)
但在退出python环境后自己添加的路径就会自动消失了,有没有更好的方式能找到python文件额路径呢?有的是有python环境变量?
pycharm中运行代码,它自动就为你设置好了项目的路径到sys.path中,而我们的项目往往要到服务器运行,而在用python命令执 行时,项目的路径需要我们自己配置使用PYTHONPATH环境变量,在这个环境变量中输入相关的路径,不同的路径之间用逗号(英文的!)分开,如果PYTHONPATH 变量还不存在,可以创建它!路径会自动加入到sys.path中,而且可以在不同的python版本中共享,应该是一样较为方便的方法。
export PYTHONPATH=/Users/wangzh/PycharmProjects/cloud_platform_script/monitor_yarn
import copy
a = [1,2,3,4,5]
b = a #浅拷贝,a,b同时指向一个id,当其中一个修改时,另外一个也会被修改。
c = copy.deepcopy(a) #深拷贝,c单独开辟一个id,用来存储和a一样的内容。
d =a[:] #这样也是深拷贝。
e = copy.copy(a) #当拷贝内容是可变类型时,那么就会进行深拷贝,如果是不可变类型时,那么就会进行浅拷贝。
注意:深拷贝指的是复制内容,单独开辟一个内存,浅拷贝指的是两个变量同时指向一个内存ID。
扫一扫加入大数据公众号和技术交流群,了解更多大数据技术,还有免费资料等你哦
扫一扫加入大数据公众号和技术交流群,了解更多大数据技术,还有免费资料等你哦
扫一扫加入大数据公众号和技术交流群,了解更多大数据技术,还有免费资料等你哦
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。