前言
其实不太想写跟Java无关的东西,但是实在憋得难受,想想一个项目组的其他同事都回家过年了,就剩下我一个苦逼的还在坚守在战斗一线,酱油也打了一段时间了,再憋下去难受了,所以趁着过年前发一篇博文吧,也可以打发下时间,何乐而不为呢?
废话说了一箩筐,回到正题。Python相信有不少开发人员,尤其是运维人员应该是非常熟悉的,那么请大家听我好好掰扯下Python究竟能够做什么,如果你觉得Python是个好东西,那么也请你尝试着使用它为你的项目增添一点色彩。笔者本文所使用的Python版本为3.x,尽管和Python2.x相比,3.x 在语法层面的改变是比较大的,但是请大家不要去 纠结 这些问题,只需要听笔者为你一一道来即可。
目录
一、Python简介;
二、Python的下载与安装;
三、第一个Python程序;
四、基本语法的使用
五、函数的使用;
六、流程控制语句;
七、面向对象特性;
八、I/O操作;
九、线程操作;
一、Python简介
其实看笔者这篇博文的朋友,更关心的是Python是什么,以及究竟能够为我们的项目带来什么好处?其实笔者在第一次接触Python的时候,立马就被这 炫酷和简易 的语法吸引住了,因为使用Python所带来的好处太多了。简单来说,Python其实是一门基于 解释性/编译性 的动态、面向对象编程语言,这里笔者要稍微解释下所谓的解释性/编译性问题。对Java有所了解的开发人员应该知道,JIT编译器所带来的改变对于Java程序的运行性能是起到了 至关重要 的作用,使得Java程序的运行性能有了 质的飞跃 ,毫 不逊色 于C/C++编写的程序的执行性能,这是因为HotSpot VM中的JIT编译器会在运行时结合 热点探测功能 将频繁被调用的代码标记为“ 热点代码 ”然后经过 分层优化编译技术 将Java代码直接 编译为本地代码。这种运行时的编译技术,必然比静态编译拥有更好的 编译质量 ,毕竟 静态编译是无法准确预估程序在执行过程中所有的运行时热点的 。
和Java一样,Python的执行引擎究竟是基于解释执行呢,还是编译执行,或者是混合执行都取决于底层的VM(笔者博文全部统称为VM)。目前比较常见的Python VM有:CPython、IPython、PyPy,以及Jython(HotSpot VM)。关于这几个VM大家可以去官网了解下。简单来说,CPython是Python的官方缺省解释器,基于解释运行;而IPython是建立在CPython之上的一个交互式解释器;PyPy内置有JIT编译器,执行性能相对而言会比前几种高效许多倍;而Jython其实就是将Python代码编译为字节码后运行在HotSpot VM中,结合HotSpot VM的解释器+JIT编译器的 混合执行引擎 ,可以达到高效执行的效果,不过更重要的是使用Jython可以很好的与Java代码交互(并不仅限于特定的语言,CPython可以是C、C++)。是的,你没有听错,简单到你会以为Python天生就是为了粘合Java代码而生!因此Python还有一个很好听的名字,那就是“ 胶水语言 ”。
当然不是说Python语言的作用就是纯粹的粘合其他语言一起执行,尽管Python最大的优点确实是这个,但是任何高级语言能做的事情,Python都能够做到,而且 代码产出效率极快 。因此大部分企业都会在项目需求较紧的时候使用Python快速上线,然后后续逐渐使用其他适合的编程语言逐步替换之前由Python编写的功能模块,以此保证代码的 结构严谨性 。
二、Python的下载与安装
如果你Java功力很强,那么学习Python就是轻而易举,这就好比《倚天屠龙记》中的张无忌掌握九阳神功后,学习太极拳的轻车熟路,其实道理都是 一样 的。当然如果你本身骨子里并无任何编程语言基础,学习Python同样也 不会感觉到吃力 ,因为相对于Java\C\C++之类的编程语言,Python的学习可以算是相当简单的。如果按照笔者的经验来判断,除了比HTML稍微复杂点,几乎 是个人都能够轻而易举的掌握Python这门语言 。笔者甚至在考虑,过年回家的时候,是否有必要教老妈使用Python编写一个小程序?
又说了一大堆废话,回到主题,Python的下载和安装。大家可以登录 https://www.python.org/ 下载Python,笔者本文所使用的版本并没有采用最新的3.4.2,而是3.3.0,没有特殊的寓意,因此你可以自由选择和笔者保持一致的版本,同样也可以下载最新的版本,当然千万不要下载Python2.x版本,毕竟它们在语法层面上的差距是非常大的。
当成功下载好Python后,在安装的时候记得勾选选项“path”,否则只能够在安装好后,手动配置Python的环境变量(PATH=安装路径)。当大家成功安装好Python后,为了检验是否安装成功,大家可以通过控制台,输入命令“Python -V”(大写V, Python大小写敏感 )验收结果,如果控制台输出的是Python的版本号,则意味着安装成功,反之安装失败。
三、第一个Python程序
所谓工欲善其事必先利其器,在使用Python编写程序之前,首先要做的就是准备好Python的开发工具,当然笔者不建议新手一上来就是用各种IDE,而是建议你使用文本编辑器就可以了,比如Editplus,它会是你初次接触Python的利器,希望大家记住, 学习任何一门新技术,或者新语言之前,必然首先需要记住一些常用的函数、语法风格 ,而不是什么都是依靠IDE工具来“饭来张口,衣来伸手”,不要让你的大脑过度偷懒,会生锈的。
当然如果你使用Python有一断时间了,或者正在准备使用Python运用在项目中时,就有必要考虑工作效率的问题了,因为笔者也不希望你浪费过多的时间在回忆应该调用那个函数,以及函数的名字叫什么,否则你可能离打包走人不远了。简单来说,Python的IDE工具非常多,如果是JYthon,那么使用PyDEV是非常好的,以插件的形式集成在神器Eclipse中,无疑为Java开发人员带来了方便。当然本文只是单纯的讲解Python的使用,并且VM也是使用CPython,因此Pycharm不得不说是编写Python的好帮手。
笔者不打算啰嗦的为大家科普IDE工具应该怎么使用,请自行Google。当成功启动IDE工具或者文本编辑器后,接下来我们就开始编写我们的第一个Python程序,如下所示:
print("Hello World")
当执行上述程序时,控制台将会输出“Hello World”。纳尼,你没有看错,Python就是这么简单, 严格意义上按照模块进行划分,不需要显式的先编写一个类、在编写方法,再来写语句 。嗦嘎德斯捏。
Sorry,笔者忘记了一件事情,按照惯例不应该先讲如何在IDE工具中或者文本编辑器中编写Python代码,而是应该让大家知道Python的交互式运行环境。没关系,现在讲似乎也不迟。Python其实有2种类型的运行环境,一种是基于交互式环境,而另外一种则是我们刚才使用到的传统环境。这里笔者所指的交互式环境,其实更多应用在测试、练习上,适合刚接触Python的开发人员,毕竟在交互式环境中,写一行代码,立马就可以得到结果,如下所示:
除了在刚开始学习Python的时候,或者在测试练习上会使用到Python自带的交互式环境外,实际的项目开发过程中,这种做法并不常见,因为代码 无法固化 ,每次都要重新编写,意义何在?
四、基本语法的使用
笔者在本节中将会介绍Python的基本语法的使用,涵盖了:变量的定义、运算符、表达式、数据类型、数据结构等知识点。请不要责怪笔者的“ 不耐烦 ”,毕竟这些太过于基础的技术,笔者实在是不忍心 大费周章 ,浪费纸墨和口水去讲解,毕竟后续还有其它的知识点,因此快速讲解是笔者的风格,希望理解。
简单来说,变量其实就是属性(后续重点讲解);运算符其实用于计算,表达式由字面值、云算法和变量构成;数据类型很简单,跟Java一样,Python同样也是 强类型 的,不过在Python中定义一个变量,开发人员并不需要在变量标示符之前显式声明变量的类型( PS:不显式定义变量类型导致笔者曾经一度以为Python是弱类型,结果试了下10+“100”,运行期报错,OK,纠正下这个错误 );数据结构简单来说就是数据的存储结构和存储方式。下面笔者使用一段简单的代码来汇总笔者本节提及过的所有知识点,如下所示:
#encoding=gbk #Python的基本语法结构 userName="JohnGao" age=28 sex=True hobbys=["看书","写字","睡觉"] print("我的名字->" + userName) print("我的年纪->" + str(age)) print("我的性别->" + str(sex)) for hobby in hobbys: print("我的爱好->"+hobby,end="\t")
上述程序示例中,将会按照笔者书写的顺序串行执行print输出。可以发现,在Python中,确实是大小写敏感的,boolean类型的值,True和False首字母是必须要大写;而笔者在输出int类型和boolean类型的2个变量时,使用了强转,因为Python的一条语句输出, 只能是同一种数据类型 ,而不能够是多种(除非符号“,”分割)。关于笔者定义的线性表的数据结构来存储数据结果集,然后又使用for循环的方式将其迭代,关于这一点,笔者稍后会做出解释。
五、函数的使用
函数即方法 。除了可以在代码中使用Python提供的缺省内置函数外,开发人员也可以编写自定义函数来实现程序的功能。当然在正式开始讲解如何在程序中编写一个自定义函数之前,我们首先来看看Python究竟带给了我们哪些惊喜?笔者示例几个比较常用的Python内置函数,如下所示:
#encoding=gbk #求绝对值函数 print(abs(-100)) #强制转换函数 print(str(100)) print(int("200")) print(float(2000)) print(bool(1)) #isinstance函数 print(isinstance(100,(int,float)))
def testMethod1(): print("一个简单的自定义函数") #定义一个无任何操作的空函数 #pass关键字就是一个占位符 def testMethod2(): pass
def testMethod1(): value=100+1 return value print(testMethod1())
def testMethod1(): value1=100+1 value2="userName->JohnGao" return value1,value2 value1,value2=testMethod1() print(value1,value2) print(testMethod1())
#定义函数参数 def testMethod1(userName,age): return userName,age userName,age=testMethod1("JohnGao",28) print(userName,age) #定义可变参数 def testMethod1(*values): for value in values: print(value,end="\t") testMethod1(100,200,300)
#if-else语句 value = 50 if value < 10: pass else: pass #if-else-if多路分支语句 userName=input("猜猜我的名字:\n") if userName == "JohnGao": pass elif userName=="JohnGao1": pass else: pass #for循环语句 for i in range(10): pass value2=["1","2","3"] for j in value2: pass #while循环语句 value3=0 while value3<10: value3+=1
class Animal(object): pass
#继承示例 class Animal(object): pass class Tiger(Animal): pass class Pig(Animal): pass
#晚期绑定 class Animal(object): def getName(self): pass class Tiger(Animal): def getName(self): print("我的名字叫做Tiger") class Pig(Animal): def getName(self): print("我的名字叫做Pig") def getName(Animal): print(Animal.getName()) #创建对象实例 animal = Tiger() getName(animal)
class Demo(object): userName="张三" __passWord="123456" def getName(self): pass demo = Demo() print(demo.userName) #print(demo.passWord)
#读取目标数据源的数据 try: readValue=open("d:/test.txt","r") #读取一行字符串 print(readValue.readline()) finally: if readValue: readValue.close() #向目标数据源写入数据 try: writeValue=open("d:/test2.txt","w") #写入一行字符串 writeValue.write("test...") finally: if writeValue: writeValue.close()
readValue.read()
#读取目标数据源的二进制数据流 readValue=open("d:/test.txt","rw") #向目标数据源写入二进制数据流 writeValue=open("d:/test2.txt","w")
#文件复制操作 def copy_method(file_path, save_path): if not isinstance(file_path,(str)): print("只支持所传递的参数为字符串") else: startTime=time.time() with open(file_path,"rb") as read_value: context = read_value.read() print("数据全部读入完毕,数据大小为->" + str(len(context)/1024) + "KB") with open(save_path,"wb") as write_value: write_value.write(context) print("数据写入完成...") print("耗时->" + str((time.time() - startTime) * 1000) + "ms") #"E:\\迅雷下载\\move.rmvb", "d:\\move.rmvb" #copy_method("d:/fengtong.rar", "d:\\fengtong2.rar"); #E:\\迅雷下载\\move.rmvb #文件复制操作2(适合大文件的读写) def copy_method2(file_path, save_path): if not isinstance(file_path,(str)): print("只支持所传递的参数为字符串") else: try: startTime=time.time() write_value = open(save_path,"wb") for read_value in open(file_path,"rb"): write_value.write(read_value) print("数据写入完成...") print("耗时->" + str((time.time() - startTime) * 1000) + "ms") finally: if write_value: write_value.close()
import os def findFile(path): #列出当前目录下的所有文件及文件夹 files = os.listdir(path) for file in files: if os.path.isfile(file): print(file) else: os.chdir(os.path.abspath(file)) findFile(os.getcwd()) cwd=os.getcwd() parent="" for i in range(len(cwd.split("\\")) - 1): parent+=cwd.split("\\")[i] + "\\" #切换到上一级目录 os.chdir(parent) filePath="D:\\test" os.chdir(filePath) findFile(filePath)
九、线程操作
其实笔者写道这里,已经有顶乏力了,为了避免烂尾,笔者就不长篇大论了(今天最后一天上班,木有心情写了)。简单来说,多线程指的就是并发,当然并发跟并行的概念还是要区分下,并发是构建于单CPU上,而并行是构建于多CPU上的并发执行。因为我们知道多线程并不是真正意义上的多任务同时执行,而是CPU会不停的做任务切换,交叉运行,看起来貌似是一起执行(CPU切换平率快),但其实不是这样,只有并行才是真正意义上的多任务同时执行。
在Python中定义和使用线程很简单,Python的API提供了2个模块:thread和threading,threading对thread模块进行了封装。绝大多数情况下,我们只需要使用threading这个模块即可。启动一个线程就是把一个函数传入并创建Thread实例,然后调用start()开始执行即可,如下所示:
def run(): for i in range(10): print(i) thread1=threading.Thread(target=run,name="线程A") thread1.start() #主线程继续执行 print("........")
既然谈到线程,不得不提及的还有锁机制,因为在并发环境下,多线程同时对一个资源进行操作,会造成非线程安全问题,因此Python也提供有锁机制,如下所示:
#获取锁 value="资源" lock=threading.Lock() def run(): try: lock.acquire() for i in range(10): print(threading.current_thread().name,value) finally: lock.release() thread1=threading.Thread(target=run,name="线程A") thread1.start() thread2=threading.Thread(target=run,name="线程B") thread2.start()
上述程序示例中,多个线程持有同一把锁,只有当前一个前程使用完并释放锁,队列中的其他线程才能够正常的访问同一个资源,以此避免非线程安全问题。当然值得注意的,在Python中,锁的释放并非是自动的,而是需要开发人员手动显式的执行release()函数进行释放,所以大家千万要记得使用完之后 一定要记得解锁 ,否则其他线程就会一直阻塞。
在并发场景下,使用锁可以有效的避免线程安全问题,但是这也同时造成了另外一个问题的出现,那就容易造成 线程死锁 ,如下所示:
#encoding=gbk import threading,time resourceA="资源A" resourceB="资源B" #获取锁 lockA=threading.Lock() lockB=threading.Lock() def run1(): try: lockA.acquire() print("%s成功锁住"%threading.current_thread().name,resourceA) print("%s准备锁住"%threading.current_thread().name,resourceB) time.sleep(1) lockB.acquire() print("%s成功锁住"%threading.current_thread().name,resourceB) finally: lockB.release() lockA.release() def run2(): try: lockB.acquire() print("%s成功锁住"%threading.current_thread().name,resourceB) print("%s准备锁住"%threading.current_thread().name,resourceA) lockA.acquire() print("%s成功锁住"%threading.current_thread().name,resourceA) finally: lockA.release() lockB.release() thread1=threading.Thread(target=run1,name="线程A") thread1.start() thread2=threading.Thread(target=run2,name="线程B") thread2.start()
简单来说,就是A线程锁住A资源的时候,试图获取B锁,但是B线程已经抢先一步获取到B锁,这个时候A线程就必须等待,而B线程试图获取A锁时,发现A锁已经被A线程获取了,因此双方都在等待,这样一来就造成了永久等待,也就是线程死锁。
本章内容到此结束,由于时间仓库,本文或许有很多不尽人意的地方,希望各位能够理解和体谅。最后祝愿大家,在新的一年事事顺心,万事如意,羊年行大运。