一:起因
(1)作为胶水语言的Python,可谓无处不在,快速开发原型网站;大数据处理等领域应用甚广
(2)学过c/c++ 或者 Java的ITers 很容易学习Python,特别是对于上手入门级的Python语法
(3)刚刚开始学习Python,练习Python时,可能感觉特别别扭 —— 完全没有方法{} ,近几年靠:和严格的缩进来进行代码段,程序段的分隔
二:Python 进阶语言
(1)python中%r和%s的区别 —— %r用rper()方法处理对象 —— %s用str()方法处理对象
有些情况下,两者处理的结果是一样的,比如说处理int型对象:
- text = "I am %d years old." % 22
- print "I said: %s." % text
- print "I said: %r." % text
- I said: I am 22 years old..
- I said: 'I am 22 years old.'. // %r 给字符串加了单引号
- #hello.py
- def sayHello():
- str="hello"
- print(str);
- if __name__ == "__main__":
- print ('This is main of module "hello.py"')
- sayHello()
1)当单独执行该module时,比如单独执行以上hello.py: python hello.py,则输出
This is main of module "hello.py"
hello
可以理解为"if __name__=="__main__":" 这一句与c中的main()函数所表述的是一致的,即作为入口;
2)当该module被其它module 引入使用时,其中的"if __name__=="__main__":"所表示的Block不会被执行,这是因为此时module被其它module引用时,其__name__的值将发生变化,__name__的值将会是module的名字。比如在python shell中import hello后,查看hello.__name__:
>>> import hello
>>> hello.__name__
'hello'
>>>
3)因此,在python中,当一个module作为整体被执行时,moduel.__name__的值将是"__main__";而当一个module被其它module引用时,module.__name__将是module自己的名字,当然一个module被其它module引用时,其本身并不需要一个可执行的入口main了
- if __name__ == '__main__':
- print 'This program is being run by itself'
- else:
- print 'I am being imported from another module'
(3)我自己的疑问:我能明白面向对象编程的概念,感觉python用模块就能解决,为啥还要有class之类的东西?
1)先回答__:由于python的类成员都是公有、公开的被存取public,缺少像正统面向对象语言的私有private属性,于是就用__来将就一下,模拟私有属性。这些__属性往往是内部使用,通常情况下不用改写。也不用读取。加上2个下划线的目的,一是不和普通公有属性重名冲突,二是不让对象的使用者(非开发者)随意使用。
2)面向对象是一种方法学的提高,不用对象用模块的确能行,就像C语言也用类似的、没有对象的方式提供模块,也能开发任何东西。但用了对象能提高代码复用、提高开发效率,减轻开发者的劳动。简单说,面向对象就类似于工厂做一个石膏雕塑:
class类就相当于模具,object对象相当于模具倒出来的雕塑,雕塑可以大量被复制。要修改雕塑,是去修改模具,而不是改雕塑成品。
从数据的角度,一个雕塑可能由多个基础部件组成,手、脚、头,这些是数据,当然对象也有动作,对象所有的函数都是它的动作,比如跑、吃、叫。
最常见的,学生类,规定一些数据,姓名、电话、年龄、这些是数据,学生会“答题” “吃饭”,“消费”,“联系”“动手”这些是传递消息的动作。
这种把数据和动作结合就是一个对象,类拿来规范这些数据和动作。再次使用这同一类的对象,就不需要重复开发。
(4)Python中__init__(初始化操作) 和 __del__(结束操作,如文件的关闭和数据库的关闭等)的作用:
1)Python中没有专用的构造和析构函数,但是一般可以在__init__和__del__分别完成初始化和删除操作,可用这个替代构造和析构。还有一个__new__用来定制类的创建过程,不过需要一定的配置,此处不做讨论。
2)类的成员函数默认都相当于是public的,但是默认开头为__的为私有变量,虽然是私有,但是我们还可以通过一定的手段访问到,即Python不存在真正的私有变量。如:
由于Python的特殊性,全局成员变量是共享的,所以类的实例不会为它专门分配内容空间,类似于static,具体使用参看下面的例子。
- 测试1:
- # encoding:utf8
- class NewClass(object):
- num_count = 0 # 所有的实例都共享此变量,即不单独为每个实例分配
- def __init__(self,name):
- self.name = name
- NewClass.num_count += 1
- print name,NewClass.num_count
- def __del__(self):
- NewClass.num_count -= 1
- print "Del",self.name,NewClass.num_count
- def test():
- print "aa"
- aa = NewClass("Hello")
- bb = NewClass("World")
- cc = NewClass("aaaa")
- print "Over"
- Hello 1
- World 2
- aaaa 3
- Over
- DeException l Hello 2
- AttributeError: "'NoneType' object has no attribute 'num_count'" in <bound method NewClass.__del__ of <__main__.NewClass object at 0x01AF18D0>> ignored
- Exception AttributeError: "'NoneType' object has no attribute 'num_count'" in <bound method NewClass.__del__ of <__main__.NewClass object at 0x01AF1970>> ignored
但是,疑问来了?为什么会这样?按照C/C++等语言的经验,不应该这样啊!经过查找资料,发现: Python的垃圾回收过程与常用语言的不一样,Python按照字典顺序进行垃圾回收,而不是按照创建顺序进行。所以当系统进行回收资源时,会按照类名A-Za-z的顺序,依次进行,我们无法掌控这里的流程。
SO,继续查找,我们还可以通过self.__class__访问到类本身,然后再访问自身的共享成员变量,即 self.__class__.num_count , 将类中的NewClass.num_count替换为self.__class__.num_count 编译运行,如下:
- # encoding:utf8
- class NewClass(object):
- num_count = 0 # 所有的实例都共享此变量,即不单独为每个实例分配
- def __init__(self,name):
- self.name = name
- self.__class__.num_count += 1
- print name,NewClass.num_count
- def __del__(self):
- self.__class__.num_count -= 1
- print "Del",self.name,self.__class__.num_count
- def test():
- print "aa"
- aa = NewClass("Hello")
- bb = NewClass("World")
- cc = NewClass("aaaa")
- print "Over"
- Perfect!我们完美地处理了这个问题!
函数内部的和函数外部的不共享一个变量,特别是出现 = (等号)时;但是同一个函数内的不同代码块之间可以共享一个变量详见
(6)Python高效读写文件
1)写入多行 —— file_object.writelines(list_of_text_strings)
注意,调用writelines写入多行在性能上会比使用write一次性写入要高。
2)在处理日志文件的时候,常常会遇到这样的情况:日志文件巨大,不可能一次性把整个文件读入到内存中进行处理,例如需要在一台物理内存为 2GB 的机器上处理一个 2GB 的日志文件,我们可能希望每次只处理其中 200MB 的内容。
在 Python 中,内置的 File 对象直接提供了一个 readlines(sizehint) 函数来完成这样的事情。以下面的代码为例:
- file = open('test.log', 'r')
- sizehint = 209715200 # 200M
- position = 0
- lines = file.readlines(sizehint)
- while not file.tell() - position < 0:
- position = file.tell()#Python文件操作tell()方法:这种方法简单地返回文件的当前位置读/写指针在文件。
- lines = file.readlines(sizehint)
每次调用 readlines(sizehint) 函数,会返回大约 200MB 的数据,而且所返回的必然都是完整的行数据,大多数情况下,返回的数据的字节数会稍微比 sizehint 指定的值大一点(除最后一次调用 readlines(sizehint) 函数的时候)。通常情况下,Python 会自动将用户指定的 sizehint 的值调整成内部缓存大小的整数倍。
(7)Python 的文件读取方式
Python提供了基本的函数和必要在默认情况下对文件进行操作的方法。可以使用一个文件对象file来做大部分文件操作。
open 函数:想要读取或写入文件,必须使用Python内置的open()函数来打开它。该函数创建一个文件对象,这将用来调用与之关联的其他支持方式:
语法:file object = open(file_name [, access_mode][, buffering])
1)参数的详细信息:
file_name: file_name参数是一个字符串值,包含您要访问的文件的名称。
access_mode: access_mode决定了文件必须被打开,即,读,写,追加等的可能值是下表中给定的一个完整的列表的模式。这是可选参数,默认文件存取方式为read (r)。
buffering: 如果缓冲值被设置为0时,没有缓冲将发生。如果该缓冲值是1,行缓冲会在访问一个文件来执行。如果指定的缓冲值为大于1的整数,则缓冲作用将与所指示的缓冲区的大小进行。如果为负,则缓冲区的大小是系统默认(默认行为)。
2)模式 描述
r 打开一个文件为只读。文件指针置于该文件的开头。这是默认模式。
rb 打开一个文件只能以二进制格式读取。文件指针置于该文件的开头。这是默认模式。
r+ 打开用于读取和写入文件。文件指针将会在文件的开头。
rb+ 打开用于读取和写入二进制格式的文件。文件指针将会在文件的开头。
w 打开一个文件只写。覆盖该文件,如果该文件存在。如果该文件不存在,则创建用于写入一个新的文件。
wb 打开一个文件只能以二进制格式写入。覆盖该文件,如果该文件存在。如果该文件不存在,则创建用于写入一个新的文件。
w+ 打开用于写入和读取的文件。覆盖现有的文件,如果文件存在。如果该文件不存在,则创建读取和写入新的文件。
wb+ 打开用于写入和读取的二进制格式的文件。覆盖现有的文件,如果文件存在。如果该文件不存在,则创建读取和写入新的文件。
a 将打开追加文件。文件指针是在文件的结尾。也就是说,该文件是在附加模式。如果该文件不存在,它创造了写入一个新的文件。
ab 将打开追加的二进制格式的文件。文件指针在该文件的结束。也就是说,该文件为追加模式。如果该文件不存在,它创建并写入一个新的文件。
a+ 打开为追加和读取文件。文件指针在该文件的结束。该文件将为追加模式。如果该文件不存在,它创建并读取和写入的新文件。
ab+ 打开两个追加和读取的二进制格式的文件。文件指针在该文件的结束。该文件将在追加模式。如果该文件不存在,它创建并读取和写入的新文件。
3)文件操作:
os.mknod("test.txt") 创建空文件
fp = open("test.txt","w+") 直接打开一个文件,如果文件不存在则创建文件
fp.read([size]) #size为读取的长度,以byte为单位
fp.readline([size]) #读一行,如果定义了size,有可能返回的只是一行的一部分
fp.readlines([size]) #把文件每一行作为一个list的一个成员,并返回这个list。其实它的内部是通过循环调用readline()来实现的。如果提供size参数,size是表示读取内容的总长,也就是说可能只读到文件的一部分。
fp.write(str) #把str写到文件中,write()并不会在str后加上一个换行符
fp.writelines(seq) #把seq的内容全部写到文件中(多行一次性写入)。这个函数也只是忠实地写入,不会在每行后面加上任何东西。
fp.close() #关闭文件。python会在一个文件不用后自动关闭文件,不过这一功能没有保证,最好还是养成自己关闭的习惯。 如果一个文件在关闭后还对其进行操作会产生ValueError
fp.flush() #把缓冲区的内容写入硬盘
fp.fileno() #返回一个长整型的”文件标签“
fp.isatty() #文件是否是一个终端设备文件(unix系统中的)
fp.tell() #返回文件操作标记的当前位置,以文件的开头为原点
fp.next() #返回下一行,并将文件操作标记位移到下一行。把一个file用于for … in file这样的语句时,就是调用next()函数来实现遍历的。
fp.seek(offset[,whence]) #将文件打操作标记移到offset的位置。这个offset一般是相对于文件的开头来计算的,一般为正数。但如果提供了whence参数就不一定了,whence可以为0表示从头开始计算,1表示以当前位置为原点计算。2表示以文件末尾为原点进行计算。需要注意,如果文件以a或a+的模式打开,每次进行写操作时,文件操作标记会自动返回到文件末尾。
fp.truncate([size]) #把文件裁成规定的大小,默认的是裁到当前文件操作标记的位置。如果size比文件的大小还要大,依据系统的不同可能是不改变文件,也可能是用0把文件补到相应的大小,也可能是以一些随机的内容加上去。
(8)目录操作:
os.mkdir("file") 创建目录
复制文件:
shutil.copyfile("oldfile","newfile") oldfile和newfile都只能是文件
shutil.copy("oldfile","newfile") oldfile只能是文件夹,newfile可以是文件,也可以是目标目录
复制文件夹:
shutil.copytree("olddir","newdir") olddir和newdir都只能是目录,且newdir必须不存在
重命名文件(目录)
os.rename("oldname","newname") 文件或目录都是使用这条命令
移动文件(目录)
shutil.move("oldpos","newpos")
删除文件
os.remove("file")
删除目录
os.rmdir("dir")只能删除空目录
shutil.rmtree("dir") 空目录、有内容的目录都可以删
转换目录
os.chdir("path") 换路径
2)将文件夹下所有图片名称加上'_fc'
python代码:
- # -*- coding:utf-8 -*-
- import re
- import os
- import time
- #str.split(string)分割字符串
- #'连接符'.join(list) 将列表组成字符串
- def change_name(path):
- global i
- if not os.path.isdir(path) and not os.path.isfile(path):
- return False
- if os.path.isfile(path):
- file_path = os.path.split(path) #分割出目录与文件
- lists = file_path[1].split('.') #分割出文件与文件扩展名
- file_ext = lists[-1] #取出后缀名(列表切片操作)
- img_ext = ['bmp','jpeg','gif','psd','png','jpg']
- if file_ext in img_ext:
- os.rename(path,file_path[0]+'/'+lists[0]+'_fc.'+file_ext)
- i+=1 #注意这里的i是一个陷阱
- #或者
- #img_ext = 'bmp|jpeg|gif|psd|png|jpg'
- #if file_ext in img_ext:
- # print('ok---'+file_ext)
- elif os.path.isdir(path):
- for x in os.listdir(path):
- change_name(os.path.join(path,x)) #os.path.join()在路径处理上很有用