python常用模块及面向对象(一)

时间:2021-10-20 13:19:14

目录:

  • 常用模块之time模块
  • 常用模块之random模块
  • 常用模块之os模块
  • 常用模块之sys模块
  • 常用模块之subprocess模块
  • 常用模块之json模块
  • 常用模块之pickle模块
  • 常用模块之shuelve模块
  • 常用模块之xml模块
  • 常用模块之configparser模块
  • 常用模块之hashlib模块
  • 常用模块之logging模块
  • 常用模块之shutil模块
  • 常用模块之re模块
  • 面向对象之类编程(一)

一、常用模块之time模块

  时间模块,import time 导入模块后使用

1、python中时间格式:

a. 时间戳(timestamp):通常来说,时间戳表示的是从1970年1月1日00:00:00开始按秒计算的偏移量。我们运行“type(time.time())”,返回的是float类型。

b.格式化的时间字符串(Format String)

c.结构化的时间(struct_time):struct_time元组共有9个元素共九个元素:(年,月,日,时,分,秒,一年中第几周,一年中第几天,夏令时)

 import time
#时间戳
print(time.time()) # 结果: 1496626275.947731 #结构化的时间
print(time.localtime())
print(time.localtime().tm_year)
print(time.gmtime()) # 等同于time.gmtime(time.time()),可以填入时间戳,转换为格林威治时间
'''
结果:
time.struct_time(tm_year=, tm_mon=, tm_mday=, tm_hour=, tm_min=, tm_sec=, tm_wday=, tm_yday=, tm_isdst=) time.struct_time(tm_year=, tm_mon=, tm_mday=, tm_hour=, tm_min=, tm_sec=, tm_wday=, tm_yday=, tm_isdst=)
''' #格式化的字符串
print(time.strftime('%Y-%m-%d %H:%M:%S'))
print(time.strftime('%Y-%m-%d %X'))
'''
结果:
-- ::
-- ::
'''

  2、时间格式转换关系图

a.timestamp<-->Format String/struct_time

python常用模块及面向对象(一)

 import time
#--------------------------按图1转换时间
# localtime([secs])
# 将一个时间戳转换为当前时区的struct_time。secs参数未提供,则以当前时间为准。
print(time.localtime())
print(time.localtime(1473525444.037215))
'''
结果:
time.struct_time(tm_year=2017, tm_mon=6, tm_mday=5, tm_hour=9, tm_min=57, tm_sec=44, tm_wday=0, tm_yday=156, tm_isdst=0)
time.struct_time(tm_year=2016, tm_mon=9, tm_mday=11, tm_hour=0, tm_min=37, tm_sec=24, tm_wday=6, tm_yday=255, tm_isdst=0)
''' # gmtime([secs]) 和localtime()方法类似,gmtime()方法是将一个时间戳转换为UTC时区(0时区)的struct_time。 # mktime(t) : 将一个struct_time转化为时间戳。
print(time.mktime(time.localtime()))#1473525749.0 # strftime(format[, t]) : 把一个代表时间的元组或者struct_time(如由time.localtime()和
# time.gmtime()返回)转化为格式化的时间字符串。如果t未指定,将传入time.localtime()。如果元组中任何一个
# 元素越界,ValueError的错误将会被抛出。
print(time.strftime("%Y-%m-%d %X", time.localtime()))#2016-09-11 00:49:56 # time.strptime(string[, format])
# 把一个格式化时间字符串转化为struct_time。实际上它和strftime()是逆操作。
print(time.strptime('2011-05-05 16:37:06', '%Y-%m-%d %X'))
# time.struct_time(tm_year=2011, tm_mon=5, tm_mday=5, tm_hour=16, tm_min=37, tm_sec=6, tm_wday=3, tm_yday=125, tm_isdst=-1)
#在这个函数中,format默认为:"%a %b %d %H:%M:%S %Y"。

b.国外一般时间格式转换asctime/cime

python常用模块及面向对象(一)

 import time
#--------------------------按图2转换时间
# asctime([t]) : 把一个表示时间的元组或者struct_time表示为这种形式:'Sun Jun 20 23:21:05 1993'。
# 如果没有参数,将会将time.localtime()作为参数传入。
print(time.asctime()) # Mon Jun 5 10:05:40 2017 # ctime([secs]) : 把一个时间戳(按秒计算的浮点数)转化为time.asctime()的形式。如果参数未给或者为
# None的时候,将会默认time.time()为参数。它的作用相当于time.asctime(time.localtime(secs))。
print(time.ctime()) # Mon Jun 5 10:05:40 2017
print(time.ctime(time.time())) # Mon Jun 5 10:05:40 2017

3、struct_time元组元素结构

属性                            值
tm_year(年) 比如2011
tm_mon(月) 1 - 12
tm_mday(日) 1 - 31
tm_hour(时) 0 - 23
tm_min(分) 0 - 59
tm_sec(秒) 0 - 61
tm_wday(weekday) 0 - 6(0表示周日)
tm_yday(一年中的第几天) 1 - 366
tm_isdst(是否是夏令时) 默认为-1

4、time加减

 # timestamp加减单位以秒为单位
import time
t1 = time.time()
t2 = t1+10 # 加十秒 print(time.ctime(t1)) # Wed Oct 26 21:15:30 2016
print(time.ctime(t2)) # Wed Oct 26 21:15:40 2016

5、其他用法

 sleep(secs) 线程推迟指定的时间运行,单位为秒。

二、常用模块之random模块

  随机取值模块,import random导入使用

1、random模块常用方法

 import random
print(random.random()) # (0,1)----float 大于0且小于1之间的小数
print(random.randint(1, 3)) # [1,3]大于等于1且小于等于3之间的整数
print(random.randrange(1, 3)) # (1,3)大于等于1且小于3之间的整数
print(random.choice([1, '', [4, 5]])) # 1或者23或者[4,5]
print(random.sample([1, '', [4, 5]], 2)) # 列表元素任意2个组合
print(random.uniform(1, 3)) # 大于1小于3的小数,如1.927109612082716 item = [1, 3, 5, 7, 9]
random.shuffle(item) # 打乱item的顺序,相当于"洗牌"
print(item)

2、random模块应用之生成随机验证码

 # 方式一
def v_code(n=5):
res = ''
for i in range(n):
num = random.randint(0,9)
s = chr(random.randint(65,90))
add = random.choice([num,s])
res += str(add)
return res
print(v_code(6)) # 方式2
import random, string
source = string.digits + string.ascii_lowercase
print(''.join(random.sample(source,6)))

三、常用模块之os模块

  与操作系统交互的接口模块,import os 导入模块后使用

1、os模块常用方法

 1、os模块常用方法
os.getcwd() 获取当前工作目录,即当前python脚本工作的目录路径
os.chdir("dirname") 改变当前脚本工作目录;相当于shell下cd
os.curdir 返回当前目录: ('.')
os.pardir 获取当前目录的父目录字符串名:('..')
os.makedirs('dirname1/dirname2') 可生成多层递归目录
os.removedirs('dirname1') 若目录为空,则删除,并递归到上一级目录,如若也为空,则删除,依此类推
os.mkdir('dirname') 生成单级目录;相当于shell中mkdir dirname
os.rmdir('dirname') 删除单级空目录,若目录不为空则无法删除,报错;相当于shell中rmdir dirname
os.listdir('dirname') 列出指定目录下的所有文件和子目录,包括隐藏文件,并以列表方式打印
os.remove() 删除一个文件
os.rename("oldname","newname") 重命名文件/目录
os.stat('path/filename') 获取文件/目录信息
os.sep 输出操作系统特定的路径分隔符,win下为"\\",Linux下为"/"
os.linesep 输出当前平台使用的行终止符,win下为"\t\n",Linux下为"\n"
os.pathsep 输出用于分割文件路径的字符串 win下为;,Linux下为:
os.name 输出字符串指示当前使用平台。win->'nt'; Linux->'posix'
os.system("bash command") 运行shell命令,直接显示
os.environ 获取系统环境变量
os.path.abspath(path) 返回path规范化的绝对路径
os.path.split(path) 将path分割成目录和文件名二元组返回
os.path.dirname(path) 返回path的目录。其实就是os.path.split(path)的第一个元素
os.path.basename(path) 返回path最后的文件名。如何path以/或\结尾,那么就会返回空值。即os.path.split(path)的第二个元素
os.path.exists(path) 如果path存在,返回True;如果path不存在,返回False
os.path.isabs(path) 如果path是绝对路径,返回True
os.path.isfile(path) 如果path是一个存在的文件,返回True。否则返回False
os.path.isdir(path) 如果path是一个存在的目录,则返回True。否则返回False
os.path.join(path1[, path2[, ...]]) 将多个路径组合后返回,第一个绝对路径之前的参数将被忽略
os.path.getatime(path) 返回path所指向的文件或者目录的最后存取时间
os.path.getmtime(path) 返回path所指向的文件或者目录的最后修改时间
os.path.getsize(path) 返回path的大小
#在Linux和Mac平台上,该函数会原样返回path,在windows平台上会将路径中所有字符转换为小写,并将所有斜杠转换为饭斜杠。
os.path.normcase('c:/windows\\system32\\') 返回'c:\\windows\\system32\\',
#规范化路径,如..和/
os.path.normpath('c://windows\\System32\\../Temp/') 返回'c:\\windows\\Temp'
ex1:
a='/Users/jieli/test1/\\\a1/\\\\aa.py/../..'
print(os.path.normpath(a))
结果:
/Users/jieli/test1

2、os模块应用之系统路径拼接使用

 #方式一:推荐使用
import os
#具体应用
import os,sys
possible_topdir = os.path.normpath(os.path.join(
os.path.abspath(__file__),
os.pardir, #上一级
os.pardir,
os.pardir
))
sys.path.insert(0,possible_topdir)
print(sys.path) #方式二:不推荐使用
print(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))
'''
结果:
['D:\\',...]
D:\
'''

四、常用模块之sys模块

与操作系统交互的接口模块,import sys导入模块后使用, 与os模块配合使用

1、sys模块常用方法

 '''
sys.argv 命令行参数List,第一个元素是程序本身路径
sys.exit(n) 退出程序,正常退出时exit(0)
sys.version 获取Python解释程序的版本信息
sys.maxint 最大的Int值
sys.path 返回模块的搜索路径,初始化时使用PYTHONPATH环境变量的值
sys.platform 返回操作系统平台名称
'''

2、sys模块应用之进度条

 import sys,time

 for i in range(50):
sys.stdout.write('%s\r' %('#'*i))
sys.stdout.flush()
time.sleep(0.1) '''
注意:在pycharm中执行无效,请到命令行中以脚本的方式执行
'''

五、常用模块之subprocess模块

subprocess意在替代其他几个老的模块或者函数,比如: os.system、os.spawn、os.popen、commands。

a. call执行命令,返回状态码

b. check_call 执行命令,状态码为0返回0,否则抛出异常。

c. check_output 如果状态码为0,返回执行后结果,如果状态码非0,抛出异常。

d. Popen 用于执行更复杂的系统命令。

1、subprocess参数详解

 '''
args可是字符串或者序列类型(如:list,元组),如果是字符串,要加上shell=True。
bufsize:指定缓冲。0 无缓冲,1 行缓冲,其他 缓冲区大小,负值 系统缓冲(全缓冲)
stdin, stdout, stderr分别表示程序的标准输入、输出、错误文件句柄。他们可以是PIPE,一个存在的文件描述符或存在的文件对象,也可以设置为None,表示从父进程继承。
preexec_fn只在Unix平台下有效,用于指定一个可执行对象(callable object),它将在子进程运行之前被调用。
Close_sfs:在windows平台下,如果close_fds被设置为True,则新创建的子进程将不会继承父进程的输入、输出、错误管道。所以不能将close_fds设置为True同时重定向子进程的标准输入、输出与错误(stdin, stdout, stderr)。
shell设为true,程序将通过shell来执行。
cwd用于设置子进程的当前目录
env是字典类型,用于指定子进程的环境变量。如果env = None,子进程的环境变量将从父进程中继承。
Universal_newlines不同操作系统下,文本的换行符是不一样的。如:windows下用'/r/n'表示换,而Linux下用'/n'。如果将此参数设置为True,Python统一把这些换行符当作'/n'来处理。
startupinfo与createionflags只在windows下有效,它们将被传递给底层的CreateProcess()函数,用于设置子进程的一些属性,如:主窗口的外观,进程的优先级等等。
'''

2、subprocess常用方法

 '''
Popen.poll():用于检查子进程是否已经结束。设置并返回returncode属性。 Popen.wait():等待子进程结束。设置并返回returncode属性。 Popen.communicate(input=None):与子进程进行交互。向stdin发送数据,或从stdout和stderr中读取数据。可选参数input指定发送到子进程的参数。Communicate()返回一个元组:(stdoutdata, stderrdata)。注意:如果希望通过进程的stdin向其发送数据,在创建Popen对象的时候,参数stdin必须被设置为PIPE。同样,如果希望从stdout和stderr获取数据,必须将stdout和stderr设置为PIPE。 Popen.send_signal(signal):向子进程发送信号。 Popen.terminate():停止(stop)子进程。在windows平台下,该方法将调用Windows API TerminateProcess()来结束子进程。 Popen.kill():杀死子进程。 Popen.stdin:如果在创建Popen对象是,参数stdin被设置为PIPE,Popen.stdin将返回一个文件对象用于策子进程发送指令。否则返回None。 Popen.stdout:如果在创建Popen对象是,参数stdout被设置为PIPE,Popen.stdout将返回一个文件对象用于策子进程发送指令。否则返回None。 Popen.stderr:如果在创建Popen对象是,参数stdout被设置为PIPE,Popen.stdout将返回一个文件对象用于策子进程发送指令。否则返回None。 Popen.pid:获取子进程的进程ID。 Popen.returncode:获取进程的返回值。如果进程还没有结束,返回None。 subprocess.call(*popenargs, **kwargs):运行命令。该函数将一直等待到子进程运行结束,并返回进程的returncode。文章一开始的例子就演示了call函数。如果子进程不需要进行交互,就可以使用该函数来创建。 subprocess.check_call(*popenargs, **kwargs):与subprocess.call(*popenargs, **kwargs)功能一样,只是如果子进程返回的returncode不为0的话,将触发CalledProcessError异常。在异常对象中,包括进程的returncode信息。
'''

3、subprocess应用之管道

 import subprocess

 # res=subprocess.Popen('diasdfasdfr',shell=True,
# stderr=subprocess.PIPE,
# stdout=subprocess.PIPE) # print('=====>',res.stdout.read())
# print('=====>',res.stderr.read().decode('gbk')) #ls |grep txt$
res1=subprocess.Popen(r'dir E:\wupeiqi\s17\day06',shell=True,stdout=subprocess.PIPE)
# print(res1.stdout.read()) res=subprocess.Popen(r'findstr txt*',shell=True,
stdin=res1.stdout,
stderr=subprocess.PIPE,
stdout=subprocess.PIPE) print('===>',res.stdout.read().decode('gbk')) # 管道取一次就空了
# print('===>',res.stdout.read().decode('gbk'))
# print('===>',res.stdout.read().decode('gbk'))
# print('===>',res.stdout.read().decode('gbk'))
# print('===>',res.stdout.read().decode('gbk'))
# print('===>',res.stdout.read().decode('gbk'))
# print('===>',res.stdout.read().decode('gbk'))

六、常用模块之json模块

json、pickle、shuelve为python提供的用于序列化的模块,eval内置方法可以将一个字符串转成python对象,不过,eval方法是有局限性的,对于普通的数据类型,json.loads和eval都能用,但遇到特殊类型的时候,eval就不管用了,所以eval的重点还是通常用来执行一个字符串表达式,并返回表达式的值。

import json 导入模块后使用

1、序列化概念:

我们把对象(变量)从内存中变成可存储或传输的过程称之为序列化,在Python中叫pickling,在其他语言中也被称之为serialization,marshalling,flattening等等,都是一个意思。

2、为什么要用序列化:

a. 保证系统和应用的用户操作状态

b. 跨平台数据交互

3、json序列化:

如果我们要在不同的编程语言之间传递对象,就必须把对象序列化为标准格式,比如XML,但更好的方法是序列化为JSON,因为JSON表示出来就是一个字符串,可以被所有语言读取,也可以方便地存储到磁盘或者通过网络传输。JSON不仅是标准格式,并且比XML更快,而且可以直接在Web页面中读取,非常方便。

JSON表示的对象就是标准的JavaScript语言的对象,JSON和Python内置的数据类型对应如下:

python常用模块及面向对象(一)

4、python的json应用流程图:

python常用模块及面向对象(一)

 import json
dic = {
'name':'alex',
'age':9000,
'height':'150cm',
} # 写入dumps
res = json.dumps(dic)
with open('a.json', 'w') as f:
f.write(res) # 读取loads
with open('a.json', 'r') as f:
dic = json.loads(f.read())
print(dic, type(dic))

  简单写法:

 import json
dic = {
'name':'alex',
'age':9000,
'height':'150cm',
}
# json.dump(dic,open('a.json', 'w')) 写入dump
# res = json.load(open('a.json', 'r')) 读取/赋值load
# print(res)

  ps.注意''and"":无论数据是怎样创建的,只要满足json格式,就可以json.loads出来,不一定非要dumps的数据才能loads

 import json
#dct="{'1':111}"#json 不认单引号
#dct=str({"1":111})#报错,因为生成的数据还是单引号:{'one': 1} dct='{"1":"111"}'
print(json.loads(dct)) #conclusion:
# 无论数据是怎样创建的,只要满足json格式,就可以json.loads出来,不一定非要dumps的数据才能loads

七、常用模块之pickle模块

import pickle 导入模块后使用,仅仅能对python数据类型进行序列化,不能满足跨平台数据交互

1、pickle应用流程图:

python常用模块及面向对象(一)

 import pickle

 dic={'name':'alvin','age':23,'sex':'male'}

 print(type(dic))#<class 'dict'>

 j=pickle.dumps(dic)
print(type(j))#<class 'bytes'> f=open('序列化对象_pickle','wb')#注意是w是写入str,wb是写入bytes,j是'bytes'
f.write(j) #-------------------等价于pickle.dump(dic,f) f.close()
#-------------------------反序列化
import pickle
f=open('序列化对象_pickle','rb') data=pickle.loads(f.read())# 等价于data=pickle.load(f) print(data['age'])

ps.Pickle的问题和所有其他编程语言特有的序列化问题一样,就是它只能用于Python,并且可能不同版本的Python彼此都不兼容,因此,只能用Pickle保存那些不重要的数据,不能成功地反序列化也没关系。

2、pickle应用局限性:

a.pickle不能与json通用(pickle序列化后,内容为python的字节码)

b.pickle序列化def函数时,子序列化执行函数时的内存地址,程序结束后,def函数内存地址失效,不能被再次调用。

 # a.pickle不能与json通用(pickle序列化后,内容为python的字节码)
import json
import pickle
# def func():
# print('from func') # json.dumps(func)# 报错,json不支持python的函数类型
# f=pickle.dumps(func)
# print(f) # pickle序列化def函数时,子序列化执行函数时的内存地址,程序结束后,def函数内存地址失效,不能被再次调用。
import json
import pickle
# def func():
# print('from func')
# pickle.dump(func,open('c.pkl','wb'))
# res=pickle.load(open('c.pkl','rb'))
# print(res)
# res()

八、常用模块之shuelve模块

import shuelve 导入模块后使用,仅仅能对python数据类型进行序列化,不能满足跨平台数据交互。shelve模块比pickle模块简单,只有一个open函数,返回类似字典的对象,可读可写;key必须为字符串,而值可以是python所支持的数据类型。shelve其实用anydbm去创建DB并且管理持久化对象的。

 import shelve

 f=shelve.open(r'sheve.txt')
f['stu1_info']={'name':'egon','age':18,'hobby':['piao','smoking','drinking']}
f['stu2_info']={'name':'gangdan','age':53}
f['school_info']={'website':'http://www.pypy.org','city':'beijing'} print(f['stu1_info']['hobby'])
f.close()

结果:

['piao', 'smoking', 'drinking']

九、常用模块之xml模块

  xml是实现不同语言或程序之间进行数据交换的协议,跟json差不多,但json使用起来更简单,不过,古时候,在json还没诞生的黑暗年代,大家只能选择用xml呀,至今很多传统公司如金融行业的很多系统的接口还主要是xml。xml的格式如下,就是通过<>节点来区别数据结构的:

 <?xml version="1.0"?>
<data>
<country name="Liechtenstein">
<rank updated="yes">2</rank>
<year>2008</year>
<gdppc>141100</gdppc>
<neighbor name="Austria" direction="E"/>
<neighbor name="Switzerland" direction="W"/>
</country>
<country name="Singapore">
<rank updated="yes">5</rank>
<year>2011</year>
<gdppc>59900</gdppc>
<neighbor name="Malaysia" direction="N"/>
</country>
<country name="Panama">
<rank updated="yes">69</rank>
<year>2011</year>
<gdppc>13600</gdppc>
<neighbor name="Costa Rica" direction="W"/>
<neighbor name="Colombia" direction="E"/>
</country>
</data>

xml示例

1、遍历XML文档的所有内容

 from xml.etree import ElementTree as ET

 ############ 解析方式一 ############
"""
# 打开文件,读取XML内容
str_xml = open('xo.xml', 'r').read() # 将字符串解析成xml特殊对象,root代指xml文件的根节点
root = ET.XML(str_xml)
# 全文搜索
# print(root.iter('year'))
# 在root的子节点找,只找一个
# print(root.find('country'))
# 在root的子节点找,找所有
# print(root.findall('country'))
"""
############ 解析方式二 ############ # 直接解析xml文件
tree = ET.parse("test.xml")
# 获取xml文件的根节点
root = tree.getroot()
### 操作
# 顶层标签
print(root.tag)
# 遍历XML文档的第二层
for child in root:
# 第二层节点的标签名称和标签属性
print(child.tag, child.attrib)
# 遍历XML文档的第三层
for i in child:
# 第二层节点的标签名称和内容
print(i.tag,i.text)
'''
data
country {'name': 'Liechtenstein'}
rank 2
year 2008
gdppc 141100
neighbor None
neighbor None
country {'name': 'Singapore'}
rank 5
year 2011
gdppc 59900
neighbor None
country {'name': 'Panama'}
rank 69
year 2011
gdppc 13600
neighbor None
neighbor None
'''

2、遍历XML中指定的节点

 '''
2、遍历XML中指定的节点
'''
from xml.etree import ElementTree as ET
############ 解析方式一 ############
# 直接解析xml文件
tree = ET.parse("test.xml")
# 获取xml文件的根节点
root = tree.getroot()
### 操作 # 顶层标签
print(root.tag) # 遍历XML中所有的year节点
for node in root.iter('year'):
# 节点的标签名称和内容
print(node.tag, node.text)
'''
结果:
data
year 2008
year 2011
year 2011
'''

3、修改节点内容

a.解析字符串方式,修改,保存

 from xml.etree import ElementTree as ET

 ############ 解析方式一 ############

 # 打开文件,读取XML内容
str_xml = open('test.xml', 'r').read()
# 将字符串解析成xml特殊对象,root代指xml文件的根节点
root = ET.XML(str_xml)
############ 操作 ############
# 顶层标签
print(root.tag) # 循环所有的year节点
for node in root.iter('year'):
# 将year节点中的内容自增一
new_year = int(node.text) + 1
node.text = str(new_year) # 设置属性
node.set('name', 'alex')
node.set('age', '')
# 删除属性
del node.attrib['name'] ############ 保存文件 ############
# 因为root是ElementTree.Element对象,没有write方法,只有ElementTree有write方法,可以将root对应的内存地址内容
# 传给ElementTree,实例化成ElementTree对象,就有write方法了
tree = ET.ElementTree(root)
tree.write("text_new.xml", encoding='utf-8') # 如果更改内容有中文就需要指定编码了 '''
结果:
cat text_new.xml
<year age="18">2009</year>
'''

b.解析文件方式,修改,保存

 from xml.etree import ElementTree as ET

 ############ 解析方式二 ############

 # 直接解析xml文件
tree = ET.parse("test.xml")
# 获取xml文件的根节点
root = tree.getroot()
############ 操作 ############ # 顶层标签
print(root.tag)
# 循环所有的year节点
for node in root.iter('year'):
# 将year节点中的内容自增一
new_year = int(node.text) + 1
node.text = str(new_year)
# 设置属性
node.set('name', 'alex')
node.set('age', '')
# 删除属性
del node.attrib['name'] ############ 保存文件 ############
tree.write("newnew.xml", encoding='utf-8')

4、删除节点

a.解析字符串方式打开,删除,保存

 from xml.etree import ElementTree as ET

 ############ 解析字符串方式打开 ############

 # 打开文件,读取XML内容
str_xml = open('test.xml', 'r').read()
# 将字符串解析成xml特殊对象,root代指xml文件的根节点
root = ET.XML(str_xml)
############ 操作 ############
# 顶层标签
print(root.tag)
# 遍历data下的所有country节点
for country in root.findall('country'):
# 获取每一个country节点下rank节点的内容
rank = int(country.find('rank').text)
if rank > 50:
# 删除指定country节点
root.remove(country)
############ 保存文件 ############
tree = ET.ElementTree(root)
tree.write("test_new.xml", encoding='utf-8')

b.解析文件方式打开,删除,保存

 from xml.etree import ElementTree as ET

 ############ 解析文件方式 ############

 # 直接解析xml文件
tree = ET.parse("test.xml") # 获取xml文件的根节点
root = tree.getroot() ############ 操作 ############ # 顶层标签
print(root.tag) # 遍历data下的所有country节点
for country in root.findall('country'):
# 获取每一个country节点下rank节点的内容
rank = int(country.find('rank').text) if rank > 50:
# 删除指定country节点
root.remove(country) ############ 保存文件 ############
tree.write("newnew.xml", encoding='utf-8')

5、创建xml文件:类型str 等类 创建字符串有两种方式生成  a = 'name'  a = str("name")

a.创建方式(一):类 Element(标签,{属性:值})

 # 方式一
from xml.etree import ElementTree as ET
# 创建根节点
root = ET.Element("famliy")
# 创建节点大儿子
son1 = ET.Element('son', {'name': '儿1'})
# 创建小儿子
son2 = ET.Element('son', {"name": '儿2'})
# 在大儿子中创建两个孙子
grandson1 = ET.Element('grandson', {'name': '儿11'})
grandson2 = ET.Element('grandson', {'name': '儿12'})
son1.append(grandson1)
son1.append(grandson2)
# 把儿子添加到根节点中
root.append(son1)
root.append(son1)
tree = ET.ElementTree(root)
tree.write('test_new.xml',encoding='utf-8', short_empty_elements=False)
 # 已有文件,二次创建子节点
from xml.etree import ElementTree as ET
tree = ET.parse("first.xml") # 直接解析xml格式文件
root = tree.getroot() #利用getroot方法获取根节点
# print(root.tag)
# print(root.attrib)
# print(root.text)
# 同 字符串创建的两种方式来看 xml也有两种方式创建
# 利用 Element类直接创建 ======
son = ET.Element("Biaoqian2",{"key":"value"})
son.text="zhi"
ele1 = ET.Element("qq",key2="value2", )
ele1.text="woshizhi"
root.append(son)
son.append(ele1)
tree.write("out2.xml")

b.创建方式(二):利用 makeelement创建 Element类的对象 创建一个新文件

 # 方式二
from xml.etree import ElementTree as ET
# 创建根节点
root = ET.Element("famliy")
# 创建大儿子
# son1 = ET.Element('son', {'name': '儿1'})
son1 = root.makeelement('son', {'name': '儿1'})
# 创建小儿子
# son2 = ET.Element('son', {"name": '儿2'})
son2 = root.makeelement('son', {"name": '儿2'})
# 在大儿子中创建两个孙子
# grandson1 = ET.Element('grandson', {'name': '儿11'})
grandson1 = son1.makeelement('grandson', {'name': '儿11'})
# grandson2 = ET.Element('grandson', {'name': '儿12'})
grandson2 = son1.makeelement('grandson', {'name': '儿12'})
son1.append(grandson1)
son1.append(grandson2)
# 把儿子添加到根节点中
root.append(son1)
root.append(son1)
tree = ET.ElementTree(root)
tree.write('oooo.xml',encoding='utf-8', short_empty_elements=False)
 # 已有文件,二次创建子节点
from xml.etree import ElementTree as ET
tree = ET.parse("first.xml") # 直接解析xml格式文件 root = tree.getroot() #利用getroot方法获取根节点
print(root.tag)
print(root.attrib)
print(root.text) # 同 字符串创建的两种方式来看 xml也有两种方式创建
#
# 1 利用 makeelement创建 Element类的对象 =====
son = root.makeelement("biaoqian",{"key":"value"}) s = son.makeelement("biaoqian2",{"key2":"value"}) #Element类的对象 son.append(s) #传入根的儿子的儿子
root.append(son) # 传入根节点下,作为儿子 tree.write("out.xml")

c.创建方式(三):SubElement创建

 from xml.etree import ElementTree as ET

 # 创建根节点
root = ET.Element("famliy") # 创建节点大儿子
son1 = ET.SubElement(root, "son", attrib={'name': '儿1'})
# 创建小儿子
son2 = ET.SubElement(root, "son", attrib={"name": "儿2"}) # 在大儿子中创建一个孙子
grandson1 = ET.SubElement(son1, "age", attrib={'name': '儿11'})
grandson1.text = '孙子' et = ET.ElementTree(root) #生成文档对象
et.write("test.xml", encoding="utf-8", xml_declaration=True, short_empty_elements=False)

6、将生成的xml的标签加缩进后写入新文件

由于原生保存的XML时默认无缩进,如果想要设置缩进的话, 需要修改保存方式:

 from xml.etree import ElementTree as ET
from xml.dom import minidom def prettify(elem):
"""将节点转换成字符串,并添加缩进。
"""
rough_string = ET.tostring(elem, 'utf-8')
reparsed = minidom.parseString(rough_string)
return reparsed.toprettyxml(indent="\t") # 创建根节点
root = ET.Element("famliy") # 创建大儿子
# son1 = ET.Element('son', {'name': '儿1'})
son1 = root.makeelement('son', {'name': '儿1'})
# 创建小儿子
# son2 = ET.Element('son', {"name": '儿2'})
son2 = root.makeelement('son', {"name": '儿2'}) # 在大儿子中创建两个孙子
# grandson1 = ET.Element('grandson', {'name': '儿11'})
grandson1 = son1.makeelement('grandson', {'name': '儿11'})
# grandson2 = ET.Element('grandson', {'name': '儿12'})
grandson2 = son1.makeelement('grandson', {'name': '儿12'}) son1.append(grandson1)
son1.append(grandson2) # 把儿子添加到根节点中
root.append(son1)
root.append(son1) raw_str = prettify(root) f = open("xxxoo.xml",'w',encoding='utf-8')
f.write(raw_str)
f.close()

优化封装写入文件

 # 函数封装了 缩进和写入文件的功能
from xml.etree import ElementTree as ET
from xml.dom import minidom def MyWrite(root, file_path): rough_string = ET.tostring(root, 'utf-8')
reparsed = minidom.parseString(rough_string)
new_str = reparsed.toprettyxml(indent="\t")
f = open(file_path, 'w', encoding='utf-8')
f.write(new_str)
f.close() root = ET.Element('family', {"age": ""}) # son = ET.Element('family', {"age": "18"})
# son = root.makeelement('family', {"age": "18"})
# root.append(son)
ET.SubElement(root,'family', {"age": ""})
son = ET.SubElement(root,'family', {"age": "十一"})
ET.SubElement(son,'family', {"age": ""}) # tree = ET.ElementTree(root)
# tree.write("out.xml", encoding='utf-8', short_empty_elements=False)
# tree.write("out.xml", encoding='utf-8', xml_declaration=True)
# ET.tostring() MyWrite(root, "nnnnn.xml")

十、常用模块之configparser模块

configparser用于处理特定格式的文件,其本质上是利用open来操作文件。import configparser之后调用

配置文件:

# 注释1
; 注释2 [section1]
k1 = v1
k2:v2
user=egon
age=18
is_admin=true
salary=31 [section2]
k1 = v1

1、获取所有节点

 import configparser
obj = configparser.ConfigParser() # 创建编辑对象 obj.read("test.conf",encoding="utf-8") #读取 文件
ret = obj.sections() # 选项
print(ret)

2、获取指定节点下所有的键值对

 import configparser

 # 获取指定节点下的键值
obj = configparser.ConfigParser() # 创建编辑对象 obj.read("ini",encoding="utf-8") #读取 文件
ret = obj.items("mysql") # 键值 # [('client_ip', '10.0.0.1'), ('port', '3306')]
print(ret)

3、获取指定节点下所有的建

 import configparser
obj = configparser.ConfigParser() # 创建编辑对象
obj.read("ini",encoding="utf-8") #读取 文件
ret = obj.options("mysql") # 选项下的key ['client_ip', 'port']
print(ret)

4、获取指定节点下指定key的值

 obj = configparser.ConfigParser() # 创建编辑对象

 obj.read("ini",encoding="utf-8") #读取 文件
ret = obj.get("mysql","client_ip") # 选项下的key 10.0.0.1
# ret = obj.getint("mysql","client_ip") # 选项下的key 10.0.0.1
# ret = obj.getfloat("mysql","client_ip") # 选项下的key 值为float类型
# ret = obj.getboolean("mysql","client_ip") # 选项下的的所有key必须都是布尔类型
print(ret)

ps.

ret = obj.getfloat("mysql","client_ip") # 选项下的key 值为float类型
ret = obj.getboolean("mysql","client_ip") # 选项下的的所有key必须是布尔类型

5、检查、删除、添加节点

 import configparser
# 检查 删除 添加节点
obj = configparser.ConfigParser() # 创建编辑对象
obj.read("ini",encoding="utf-8") #读取 文件 # 检查
has_sec = obj.has_section("mysql1") # false
print(has_sec) # 添加节点
obj.add_section("liujianzuo")
obj.add_section("liujianzuo1")
obj.add_section("liujianzuo2")
obj.write(open("ini","w",encoding="utf-8")) # ['section1', 'section2', 'mysql', 'mysqld', 'liujianzuo', 'liujianzuo1', 'liujianzuo2']
obj.read("ini",encoding="utf-8")
ret = obj.sections()
print(ret)
# 删除节点
obj.remove_section("liujianzuo")
obj.remove_section("liujianzuo1")
obj.write(open("ini","w",encoding="utf-8")) # ['section1', 'section2', 'mysql', 'mysqld', 'liujianzuo2']
obj.read("ini",encoding="utf-8")
ret = obj.sections()
print(ret)

6、检查、删除、设置指定组内的键值对

 import configparser
# 检查 删除 添加 指定组内的键值对 obj = configparser.ConfigParser() # 创建编辑对象
obj.read("ini",encoding="utf-8") #读取 文件 # 检查
has_opt = obj.has_option("mysql","port")
print(has_opt) # 删除
obj.remove_option("mysql","port")
obj.write(open("ini","w",encoding="utf-8"))
ret = obj.sections()
print(ret) # # 设置
obj.set("mysql","port","")
obj.write(open("ini","w",encoding="utf-8"))
ret = obj.values()
print(ret)

十一、常用模块之hashlib模块

  用于加密数据,对比认证。import hashlib之后调用

1、hash:一种算法 ,3.x里代替了md5模块和sha模块,主要提供 SHA1, SHA224, SHA256, SHA384, SHA512 ,MD5 算法。 

2、hash特点:

a.内容相同则hash运算结果相同,内容稍微改变则hash值则变
b.不可逆推
c.相同算法:无论校验多长的数据,得到的哈希值长度固定。

3、hashlib用法

 import hashlib

 m = hashlib.md5()  # m=hashlib.sha256()

 m.update('hello'.encode('utf8'))
print(m.hexdigest()) # 5d41402abc4b2a76b9719d911017c592 m.update('alvin'.encode('utf8')) print(m.hexdigest()) # 92a7e713c30abbb0319fa07da2a5c4af m2 = hashlib.md5()
m2.update('helloalvin'.encode('utf8'))
print(m2.hexdigest()) # 92a7e713c30abbb0319fa07da2a5c4af

ps.
注意:把一段很长的数据update多次,与一次update这段长数据,得到的结果一样
但是update多次为校验大文件提供了可能。

4、加盐及模拟撞库反解密

以上加密算法虽然依然非常厉害,但时候存在缺陷,即:通过撞库可以反解。所以,有必要对加密算法中添加自定义key再来做加密。

a.加盐

 import hashlib
# ######## md5 ########
# hash = hashlib.md5('898oaFs09f')
######## 256 ########
hash = hashlib.sha256('898oaFs09f'.encode('utf8')) # 加盐
hash.update('admin') # 更新哈希对象以字符串参数 其实就是你的明文密码 # import hashlib
#
# obj = hashlib.md5(
# bytes("salt;%#%salt", encoding="utf-8")) # 这里是输入的盐值 ##创建hash对象,md5:(message-Digest Algorithm 5)消息摘要算法,得出一个128位的密文
# print(obj) # <md5 HASH object @ 0x0000000000A1F800>
# obj.update(bytes("mypasswd123", encoding="utf-8")) # 更新哈希对象以字符串参数 其实就是你的明文密码
# print(obj.digest()) ##返回摘要,作为二进制数据字符串值 b'\x04\x80)\x17\\\xf8dPA\xbc\xd9@e\xeb&\x0f'
# print(obj.hexdigest()) # 返回十六进制数字字符串 048029175cf8645041bcd94065eb260f

b.模拟撞库反解密

5、 hmac 模块:消息认证算法:MAC (Message Authentication Codes)  消息认证码

python 还有一个 hmac 模块,它内部对我们创建 key 和 内容 进行进一步的处理然后再加密

 import hmac
h = hmac.new('wueiqi')
h.update('hellowo')
print h.hexdigest()

十二、常用模块之logging模块

用于便捷记录日志且线程安全的模块。import logging之后调用

1、日志级别种类:

CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0

2、日志模块写法

a.如果不指定filename,则默认打印到终端
b.指定日志级别:

指定方式:

1:level=10
2:level=logging.ERROR

c.指定日志级别为ERROR,则只有ERROR及其以上级别的日志会被打印

 import logging

 logging.basicConfig(filename='access.log',
format='%(asctime)s - %(name)s - %(levelname)s -%(module)s: %(message)s',
datefmt='%Y-%m-%d %H:%M:%S %p',
level=10) logging.debug('debug')
logging.info('info')
logging.warning('warning')
logging.error('error')
logging.critical('critical')
logging.log(10,'log') #如果level=40,则只有logging.critical和loggin.error的日志会被打印

3、日志模块可用参数

可在logging.basicConfig()函数中通过具体参数来更改logging模块默认行为,可用参数有
filename:用指定的文件名创建FiledHandler(后边会具体讲解handler的概念),这样日志会被存储在指定的文件中。
filemode:文件打开方式,在指定了filename时使用这个参数,默认值为“a”还可指定为“w”。
format:指定handler使用的日志显示格式。
datefmt:指定日期时间格式。
level:设置rootlogger(后边会讲解具体概念)的日志级别
stream:用指定的stream创建StreamHandler。可以指定输出到sys.stderr,sys.stdout或者文件,默认为sys.stderr。若同时列出了filename和stream两个参数,则stream参数会被忽略。点击查看更详细

4、日志格式详细:

%(name)s

Logger的名字,并非用户名,详细查看

%(levelno)s

数字形式的日志级别

%(levelname)s

文本形式的日志级别

%(pathname)s

调用日志输出函数的模块的完整路径名,可能没有

%(filename)s

调用日志输出函数的模块的文件名

%(module)s

调用日志输出函数的模块名

%(funcName)s

调用日志输出函数的函数名

%(lineno)d

调用日志输出函数的语句所在的代码行

%(created)f

当前时间,用UNIX标准的表示时间的浮 点数表示

%(relativeCreated)d

输出日志信息时的,自Logger创建以 来的毫秒数

%(asctime)s

字符串形式的当前时间。默认格式是 “2003-07-08 16:49:45,896”。逗号后面的是毫秒

%(thread)d

线程ID。可能没有

%(threadName)s

线程名。可能没有

%(process)d

进程ID。可能没有

%(message)s

用户输出的消息

十三、常用模块之shutil模块

高级的 文件、文件夹、压缩包 处理模块。import shutil之后调用

1、shutil.copyfileobj(fsrc, fdst[, length]):将文件内容拷贝到另一个文件中

 '''
1、shutil.copyfileobj(fsrc, fdst[, length]):将文件内容拷贝到另一个文件中
'''
import shutil
shutil.copyfileobj(open('old.xml', 'r'), open('new.xml', 'w'))

2、shutil.copyfile(src, dst):拷贝文件

 '''
2、shutil.copyfile(src, dst):拷贝文件
'''
import shutil
shutil.copyfile('f1.log', 'f2.log')

3、shutil.copymode(src, dst):仅拷贝权限。内容、组、用户均不变

 '''
3、shutil.copymode(src, dst):仅拷贝权限。内容、组、用户均不变
'''
import shutil
shutil.copymode('f1.log', 'f2.log')

4、shutil.copystat(src, dst):拷贝状态的信息,包括:mode bits, atime, mtime, flags

 '''
4、shutil.copystat(src, dst):拷贝状态的信息,包括:mode bits, atime, mtime, flags
'''
import shutil
shutil.copystat('f1.log', 'f2.log')

5、shutil.copy(src, dst):拷贝文件和权限

 '''
5、shutil.copy(src, dst):拷贝文件和权限
'''
import shutil
shutil.copy('f1.log', 'f2.log')

6、shutil.copy2(src, dst):拷贝文件和状态信息

 '''
6、shutil.copy2(src, dst):拷贝文件和状态信息
'''
import shutil
shutil.copy2('f1.log', 'f2.log')

7、shutil.ignore_patterns(*patterns)

8、shutil.copytree(src, dst, symlinks=False, ignore=None):递归的去拷贝文件夹

 '''
8、shutil.copytree(src, dst, symlinks=False, ignore=None):递归的去拷贝文件夹
'''
import shutil
shutil.copytree('folder1', 'folder2', ignore=shutil.ignore_patterns('*.pyc', 'tmp*')) #目标目录不能存在,注意对folder2目录父级目录要有可写权限,ignore的意思是排除
 import shutil
shutil.copytree('f1', 'f2', symlinks=True, ignore=shutil.ignore_patterns('*.pyc', 'tmp*'))#通常的拷贝都把软连接拷贝成硬链接,即对待软连接来说,创建新的文件

9、shutil.rmtree(path[, ignore_errors[, onerror]]):递归的去删除文件

 '''
9、shutil.rmtree(path[, ignore_errors[, onerror]]):递归的去删除文件
'''
import shutil
shutil.rmtree('folder1') # import os,sys
# shutil.rmtree(os.path.dirname(__file__)+"/c") # 删除 c目录 类似 rm -fr 不存在目录则报错

10、shutil.move(src, dst):递归的去移动文件,它类似mv命令,其实就是重命名。

 '''
10、shutil.move(src, dst):递归的去移动文件,它类似mv命令,其实就是重命名。
'''
import shutil shutil.move('folder1', 'folder3')
# shutil.move("c","b1") # 剪切c目录到b目录下 ,src即c目录不存在则报错 ,dst即b目录不存在就是重命名

11、shutil.make_archive(base_name, format,...)

a.创建压缩包并返回文件路径,例如:zip、tar

b.创建压缩包并返回文件路径,例如:zip、tar

    • base_name: 压缩包的文件名,也可以是压缩包的路径。只是文件名时,则保存至当前目录,否则保存至指定路径,
      如:www                        =>保存至当前路径
      如:/Users/wupeiqi/www =>保存至/Users/wupeiqi/
    • format: 压缩包种类,“zip”, “tar”, “bztar”,“gztar”
    • root_dir: 要压缩的文件夹路径(默认当前目录)
    • owner: 用户,默认当前用户
    • group: 组,默认当前组
    • logger: 用于记录日志,通常是logging.Logger对象
 # 将 /Users/wupeiqi/Downloads/test 下的文件打包放置当前程序目录
import shutil ret = shutil.make_archive("wwwwwwwwww", 'gztar', root_dir='/Users/wupeiqi/Downloads/test') # 将 /Users/wupeiqi/Downloads/test 下的文件打包放置 /Users/wupeiqi/目录
import shutil ret = shutil.make_archive("/Users/wupeiqi/wwwwwwwwww", 'gztar', root_dir='/Users/wupeiqi/Downloads/test')
# import os,sys
# shutil.make_archive("my_bak","gztar",root_dir=os.path.dirname(__file__)+"/b1")
# shutil.make_archive(os.path.dirname(__file__)+"/a/my_bak","gztar",root_dir=os.path.dirname(__file__)+"/b1")

  c.shutil 对压缩包的处理是调用 ZipFile 和 TarFile 两个模块来进行的,详细:

zipfile模块处理

 import zipfile

 # 压缩
# z = zipfile.ZipFile('laxi.zip', 'w')
# z.write('log.log')
# z.write('first.xml')
# z.close() # 添加一个文件
# z = zipfile.ZipFile('laxi.zip', 'a')
# z.write('first1.xml')
# z.write('a/a') # 将a目和其下面的a文件一同录压缩到里面 如果存在会保存,但是仍然压缩进入
# z.write('b/c') # 将b目录和其下面的c文件一同压缩到里面
# z.write('b/b') # 将b目录和其下面的c文件一同压缩到里面
# z.close() # 解压
# z = zipfile.ZipFile('laxi.zip', 'r')
# z.extractall("log.log") # 解药所有文件到log.log目录
# z.extract("log.log") # 解压单个文件log.log到当前目录 文件如果存在也无报错
# z.extract("first.xml") # 解压单个文件log.log到当前目录 文件如果存在也无报错
# z.close()

tarfile模块处理

 import tarfile,os
# 压缩
# tar = tarfile.open("your.tar",'w') # 已存在不报错
# tar.add(os.path.dirname(__file__),arcname="nonosd") #将前面的目录重新改名为nonosd目录名 归档到your.tar中
# tar.add("first.xml",arcname="first.xml") #将前面的目录重新改名为nonosd目录名 归档到your.tar中
# tar.close() # tar = zipfile.ZipFile('laxi.zip', 'a')
# tar.write('first1.xml')
# tar.write('a/a') # 将a目和其下面的a文件一同录压缩到里面 如果存在会保存,但是仍然压缩进入
# tar.write('b/c') # 将b目录和其下面的c文件一同压缩到里面
# tar.write('b/b') # 将b目录和其下面的c文件一同压缩到里面
# tar.close() # 压缩
# tar = tarfile.open('your.tar','r')
# # print(tar.getmembers())
# print(tar.getnames()) #查看所有的文件名
# tar.extract('first.xml') #解压单个文件
# tar.extractall(path="a/") # 解压所有到 path
# tar.close()

十四、常用模块之re模块

详见http://www.cnblogs.com/wangshuyang/p/6922636.html

十五、面向对象之类编程(一)

1、简介

面向过程的程序设计的核心是过程(流水线式思维),过程即解决问题的步骤,面向过程的设计就好比精心设计好一条流水线,考虑周全什么时候处理什么东西。

优点是:极大的降低了程序的复杂度

缺点是:一套流水线或者流程就是用来解决一个问题,生产汽水的流水线无法生产汽车,即便是能,也得是大改,改一个组件,牵一发而动全身。

应用场景:一旦完成基本很少改变的场景,著名的例子有Linux內核,git,以及Apache HTTP Server等。

面向对象的程序设计的核心是对象(上帝式思维),要理解对象为何物,必须把自己当成上帝,上帝眼里世间存在的万物皆为对象,不存在的也可以创造出来。面向对象的程序设计好比如来设计西游记,如来要解决的问题是把经书传给东土大唐,如来想了想解决这个问题需要四个人:唐僧,沙和尚,猪八戒,孙悟空,每个人都有各自的特征和技能(这就是对象的概念,特征和技能分别对应对象的数据属性和方法属性),然而这并不好玩,于是如来又安排了一群妖魔鬼怪,为了防止师徒四人在取经路上被搞死,又安排了一群神仙保驾护航,这些都是对象。然后取经开始,师徒四人与妖魔鬼怪神仙交互着直到最后取得真经。如来根本不会管师徒四人按照什么流程去取。

面向对象的程序设计的

优点是:解决了程序的扩展性。对某一个对象单独修改,会立刻反映到整个体系中,如对游戏中一个人物参数的特征和技能修改都很容易。

缺点:可控性差,无法向面向过程的程序设计流水线式的可以很精准的预测问题的处理流程与结果,面向对象的程序一旦开始就由对象之间的交互解决问题,即便是上帝也无法预测最终结果。于是我们经常看到一个游戏人某一参数的修改极有可能导致阴霸的技能出现,一刀砍死3个人,这个游戏就失去平衡。

应用场景:需求经常变化的软件,一般需求的变化都集中在用户层,互联网应用,企业内部软件,游戏等都是面向对象的程序设计大显身手的好地方

面向对象的程序设计并不是全部。对于一个软件质量来说,面向对象的程序设计只是用来解决扩展性。

python常用模块及面向对象(一)

2、类和对象概念

提示:python的class术语与c++有一定区别,与 Modula-3更像。

python中一切皆为对象,且python3统一了类与类型的概念,类型就是类,所以,不管你信不信,你已经使用了很长时间的类了。

基于面向对象设计一个款游戏:英雄联盟,每个玩家选一个英雄,每个英雄都有自己的特征和和技能,特征即数据属性,技能即方法属性,特征与技能的结合体就一个对象。

  从一组对象中提取相似的部分就是类所有对象都具有的特征和技能的结合体

  在python中,用变量表示特征,用函数表示技能,因而类是变量与函数的结合体,对象是变量与方法(指向类的函数)的结合体

  补充几个有意思的点:

  garen_hero.Q()称为向garen_hero这个对象发送了一条消息,让他去执行Q这个函数,完成一个功能,类似的有:

  garen_hero.W()

  garen_hero.E()

  garen_hero.R()

  一个英雄可以攻击另外一个英雄,这就是对象之间的交互

  garen_hero.attack(Riven)

3、初识类:类是数据与函数的结合,二者称为类的属性

a.声明一个类:

 '''
class 类名:
'类的文档字符串'
类体
''' #我们创建一个类
class Data:
pass

b.类的分类:经典类和新式类

 大前提:
1.只有在python2中才分新式类和经典类,python3中统一都是新式类
2.新式类和经典类声明的最大不同在于,所有新式类必须继承至少一个父类
3.所有类甭管是否显式声明父类,都有一个默认继承object父类(讲继承时会讲,先记住)
在python2中的区分
经典类:
class 类名:
pass 新式类:
class 类名(父类):
pass 在python3中,上述两种定义方式全都是新式类

c.一个类的示例:

 class Garen:        #定义英雄盖伦的类,不同的玩家可以用它实例出自己英雄;
camp='Demacia' #所有玩家的英雄(盖伦)的阵营都是Demacia;
def attack(self,enemy): #普通攻击技能,enemy是敌人;
enemy.life_value-=self.aggressivity #根据自己的攻击力,攻击敌人就减掉敌人的生命值。

4、类的两种作用:属性引用和实例化

a.属性引用

 # class Chinese:
# country='China'
#
# # Chinese.__init__(p1,'shuyang','18','male')
# def __init__(self,name,age,sex):
# #p1.Name=name;p1.Age=age,p1.Sex=sex
# self.Name=name
# self.Age=age
# self.Sex=sex
#
#
# def talk(self):
# print('talking',self) #属性的引用
# print(Chinese.country)
# print(Chinese.talk)
# Chinese.talk(123)
# Chinese.x=1
# print(Chinese.x)
# Chinese.country=123123123123123
# print(Chinese.country)

b.实例化

 class Garen:        #定义英雄盖伦的类,不同的玩家可以用它实例出自己英雄;
camp='Demacia' #所有玩家的英雄(盖伦)的阵营都是Demacia;
def __init__(self,nickname,aggressivity=58,life_value=455): #英雄的初始攻击力58...;
self.nickname=nickname #为自己的盖伦起个别名;
self.aggressivity=aggressivity #英雄都有自己的攻击力;
self.life_value=life_value #英雄都有自己的生命值;
def attack(self,enemy): #普通攻击技能,enemy是敌人;
enemy.life_value-=self.aggressivity #根据自己的攻击力,攻击敌人就减掉敌人的生命值。 g1=Garen('草丛伦') #就是在执行Garen.__init__(g1,'草丛伦'),然后执行__init__内的代码g1.nickname=‘草丛伦’等

ps.self其实就是对象名,实例化成什么对象,self就代表什么对象

self的作用是在实例化时自动将对象/实例本身传给__init__的第一个参数,self可以是任意名字,但是瞎几把写别人就看不懂了。

这种自动传递的机制还体现在g1.attack的调用上

5、类的属性

a.类的属性查看的两种方式:

dir(类名):查出的是一个名字列表

类名.__dict__:查出的是一个字典,key为属性名,value为属性值

b.特殊的类属性

 类名.__name__# 类的名字(字符串)
类名.__doc__# 类的文档字符串
类名.__base__# 类的第一个父类(在讲继承时会讲)
类名.__bases__# 类所有父类构成的元组(在讲继承时会讲)
类名.__dict__# 类的字典属性
类名.__module__# 类定义所在的模块
类名.__class__# 实例对应的类(仅新式类中)

6、对象相关:

对象是关于类而实际存在的一个例子,即实例

 >>> g1=Garen('草丛伦') #类实例化得到g1这个实例,基于该实例我们讲解实例相关知识
>>> type(g1) #查看g1的类型就是类Garen
<class '__main__.Garen'>
>>> isinstance(g1,Garen) #g1就是Garen的实例
True

  a.对象/实例只有一种作用:属性引用

 #对象/实例本身其实只有数据属性
>>> g1.nickname
'草丛伦'
>>> g1.aggressivity
58
>>> g1.life_value
455
'''
查看实例属性
同样是dir和内置__dict__两种方式
特殊实例属性
__class__
__dict__
....
'''

b.绑定方法:对象/实例本身只有数据属性,但是python的class机制会将类的函数绑定到对象上,称为对象的方法,或者叫绑定方法,绑定方法唯一绑定一个对象,同一个类的方法绑定到不同的对象上,属于不同的方法,内存地址都不会一样.

 >>> g1.attack #对象的绑定方法
<bound method Garen.attack of <__main__.Garen object at 0x101348dd8>> >>> Garen.attack #对象的绑定方法attack本质就是调用类的函数attack的功能,二者是一种绑定关系
<function Garen.attack at 0x101356620>

  ps.对象的绑定方法的特别之处在于:obj.func()会把obj传给func的第一个参数。

  c.对象之间的交互:

 class Riven:
camp='Noxus' #所有玩家的英雄(锐雯)的阵营都是Noxus;
def __init__(self,nickname,aggressivity=54,life_value=414): #英雄的初始攻击力54;
self.nickname=nickname #为自己的锐雯起个别名;
self.aggressivity=aggressivity #英雄都有自己的攻击力;
self.life_value=life_value #英雄都有自己的生命值;
def attack(self,enemy): #普通攻击技能,enemy是敌人;
enemy.life_value-=self.aggressivity #根据自己的攻击力,攻击敌人就减掉敌人的生命值。 #实例出一个Riven来
r1=Riven('锐雯雯') #交互:锐雯雯攻击草丛伦,反之一样
g1.life_value # 结果:455
r1.attack(g1)
g1.life_value # 结果:401

d.类名称空间与对象/实例名称空间

创建一个类就会创建一个类的名称空间,用来存储类中定义的所有名字,这些名字称为类的属性

而类有两种属性:数据属性和函数属性

其中类的数据属性是共享给所有对象的

 >>> id(r1.camp) #本质就是在引用类的camp属性,二者id一样
4315241024
>>> id(Riven.camp)
4315241024

  而类的函数属性是绑定到所有对象的:

 >>> id(r1.attack)
4302501512
>>> id(Riven.attack)
4315244200 '''
r1.attack就是在执行Riven.attack的功能,python的class机制会将Riven的函数属性attack绑定给r1,r1相当于拿到了一个指针,指向Riven类的attack功能 除此之外r1.attack()会将r1传给attack的第一个参数
'''

  ps.

创建一个对象/实例就会创建一个对象/实例的名称空间,存放对象/实例的名字,称为对象/实例的属性

在obj.name会先从obj自己的名称空间里找name,找不到则去类中找,类也找不到就找父类...最后都找不到就抛出异常

7、应用实例:

定义锐雯类:

python常用模块及面向对象(一)

python常用模块及面向对象(一)

 class Riven:
camp='Noxus'
def __init__(self,nickname,
aggressivity=54,
life_value=414,
money=1001,
armor=3):
self.nickname=nickname
self.aggressivity=aggressivity
self.life_value=life_value
self.money=money
self.armor=armor
def attack(self,enemy):
damage_value=self.aggressivity-enemy.armor
enemy.life_value-=damage_value

  定义盖文类:

python常用模块及面向对象(一)

python常用模块及面向对象(一)

 class Garen:
camp='Demacia'
def __init__(self,nickname,
aggressivity=58,
life_value=455,
money=100,
armor=10):
self.nickname=nickname
self.aggressivity=aggressivity
self.life_value=life_value
self.money=money
self.armor=armor
def attack(self,enemy):
damage_value=self.aggressivity-enemy.armor
enemy.life_value-=damage_value

  定义装备:

  python常用模块及面向对象(一)

 class BlackCleaver:
def __init__(self,price=475,aggrev=9,life_value=100):
self.price=price
self.aggrev=aggrev
self.life_value=life_value
def update(self,obj):
obj.money-=self.price #减钱
obj.aggressivity+=self.aggrev #加攻击
obj.life_value+=self.life_value #加生命值
def fire(self,obj): #这是该装备的主动技能,喷火,烧死对方
obj.life_value-=1000 #假设火烧的攻击力是1000

测试交互:

 r1=Riven('草丛伦')
g1=Garen('盖文')
b1=BlackCleaver() print(r1.aggressivity,r1.life_value,r1.money) #r1的攻击力,生命值,护甲 if r1.money > b1.price:
r1.b1=b1
b1.update(r1) print(r1.aggressivity,r1.life_value,r1.money) #r1的攻击力,生命值,护甲 print(g1.life_value)
r1.attack(g1) #普通攻击
print(g1.life_value)
r1.b1.fire(g1) #用装备攻击
print(g1.life_value) #g1的生命值小于0就死了