一、python以及pycharm的安装
我用的python版本为3.6版本,pycharm使用的是社区版。
二、python的基础语法
2.1 python的书写规则
if(10-9>0):
print("10>9")
一个语句块可以写在一行,但为了直观,若一个语句块写在两行,则要进行缩进,缩进的格式为4个空格。
2.2python的基本数据结构
注:在python里单引号和双引号都可以表示字符串,如果一个字符串包含单引号则表示必须用双引号,其他情况单引号双引号没有区别。
除此之外,python中类型转换也非常方便
2.3变量的常用定义和操作
2.3.1 变量定义
python中变量可直接命名,不需要先定义该变量的属于那种基本数据结构
a=100
b=8
print(a/b)
2.3.2变量命名规范
通常将单词首字母大写或单词之间有下划线分开,一般命名用字母开头即可,下划线开头一般用于python中特殊含义。
三、序列
序列中的所有成员都是按序排列的,用户可以按照下标去访问序列。字符串、列表、元组都属于序列。
3.1字符串
3.1.1下标访问
stringgg='鼠牛虎兔龙马蛇羊'
print(stringgg[0:4])
访问连续的几个成员
stringgg='鼠牛虎兔龙马蛇羊'
print(stringgg[-1])
访问最后一个成员
3.1.2常用操作
成员关系操作符(in or not in)
stringgg='鼠牛虎兔龙马蛇羊'
print('羊'in stringgg)
连接操作符(序列+序列)
stringgg='鼠牛虎兔龙马蛇羊'
print(stringgg+'猪')
结果为
重复操作符
stringgg='鼠牛虎兔龙马蛇羊'
print(stringgg*3)
结果为
切片操作符(序列[0:整数])
3.2 元组
元组的格式如下图所示,外面由括号围成,其中元素由逗号隔开。
其中元组还可以进行嵌套
code=((1,2),(3,4),(5,6),(7,8),(9,10))
如上所示每个括号里面都是一个元组,最外层的括号括起来就形成了一个新的元组,这便是元组的嵌套。
3.3 列表
列表的定义域元组很想,区别是列表的成员可以修改,也就是可以进行增加、删除和修改。
stringgg=['X','Y','Z']
stringgg.remove('Y')//删除元素
stringgg.append('F')//增加元素
三、条件与循环
1、条件语句
与c语言的if语句逻辑相同,但语句格式稍有差别
2、for循环
逻辑与C语言相同,语句格式与类C语言相似。
stringgg=(1,2,3,4,5,6,7,8,9,10,11,12)
for cz in stringgg:
print(cz)
for cz in range(100,105):
print(cz)//cz的取值为100-104,即range(i,j),从i到j-1
3、while循环
num=5
while True:
if(num==10):
break
print(num)
num+=1//num为10时终止while循环
四、映射与字典
1、字典的定义与操作
其格式为{“哈希值”:“对象”},例如{‘小明’:175}可表示小明身高为175厘米。
向字典里添加元素时可之间用下标填入
dict={}
dict['z']=3
print(dict)
2、列表推导式与字典推导式
若我们想得到从1到10偶数的平方
dict={}
dict=[i*i for i in range(1,11) if(i%2)==0]
print(dict)
将字典的元素初始化为0
dict={}
dict={i:0 for i in range(1,11)}
print(dict)
五、文件的输入和输出
1、使用python对文件进行基本的读写操作
写入文件
file=open('pre.txt','w')
file.write('小张')
file.close()
读取文件
file1=open('pre.txt')
print(file1.read())
file1.close()
对已经写过的文件继续进行写操作
file2=open('pre.txt','a')
file2.write('小王')
file2.close()
逐行读取文件的内容
file=open('pre.txt')
for cz in file.readlines():
print(cz)
对文件的指针进行操作
file=open('pre.txt')
print(file.tell())//返回文件指针目前所在的位置
file.read(1)//读取一个字符
file.seek(0)//指针返回到第0个字符
注:real和seek的单位都是字节,ASCII码中,一个英文字母占一个字节,中文汉字占两个字节;UTF-8编码中,一个英文字母占一个字节,中文占三个字节;Unicode编码应为和中文都是两个字节。
六、错误和异常
错误不等于异常
try:
file=open('pre.txt')
except Exception as s://其中 exception是可以抛出所以异常信息,若想具体让程序抛出某种异常信息
//比如除0异常。可将exception替换为ZeroDivisionError,可抛出某一类具体异常
print('异常信息为'%s,s)
finally:
file.close()
七、函数
1、定义函数和调用函数的方法
例子:计算三国文本中,各人物名字出现的次数
import re
def item_num(hero):#定义一个计算出现次数函数
with open('sanguo.txt',encoding='utf-8') as f:
data=f.read().replace('\n','')
num=re.findall(hero,data)
return len(num)
with open('name.txt',encoding='UTF-8') as f:
for line in f:
names=line.split('|')
for n in names:
item_num(n)
print('%s出现了%s次'%(n,item_num(n)))
2、函数的可变长参数
例如在打开文件的函数中
在open函数中,其完整格式为
我们可以看到,我们只用到了第一个参数和第三个参数,如何跳过第二个参数直接给第三个参数赋值?则需要如下调用,直接使用参数的名字并赋给其值
file= open('weapon.txt',encoding='utf-8')
再举一个具体的例子
def func(a,b,c):
print(a,b,c)
func(1,c=2,b=0)
其输出结果为
3、函数的变量作用域
在函数内部用一个变量,在函数外部也有一个同名的变量,会出现什么情况?
val1=123
def func():
print(val1)
func()
其输出结果为
val1=123
def func():
val1=456
print(val1)
func()
print(val1)
其输出结果为
可以看出函数内部的值不受外部影响,函数内部的变量也仅仅作用于函数内部
如何让内部变量可以影响外部?
val1=123
def func():
global val1
val1=456
print(val1)
func()
print(val1)
4、函数的迭代器和生成器
使用系统提供的迭代器
list1={1,2,3}
it=iter(list1)
print(next(it))
print(next(it))
print(next(it))
自己做一个迭代器,叫做生成器
for i in range(10,20,1)
该函数段实现的是i的值取自10开始,按1增加。直到19。但可以将1改为0.5吗,显然不能,因为编译时提示参数不能为浮点数
但可以通过自己制作一个迭代器完成上述功能
def frange(star,end,step):
x=star
while x<end:
yield x
x+=step
for i in frange(10,20,0.5):
print(i)
关于yield,yield的主要用途是需要一个数据时,才产生一个,而不是把数据线一次性存入内存;相对于把数据提前定义成列表来使用,要极为节省系统资源。
5、lambda表达式
lambda表达式,通常是在需要一个函数,但是又不想费神去命名一个函数的场合下使用,也就是指匿名函数。
比如我们写一个lambda的加法函数
lambda x,y:x+y
我们再定义一个加法函数
def func(x,y)
{
return x+y
}
我们可以看出,lambda表示式省略了函数的命名,在lambda后面直接跟上函数的参数,并在“:”号后面省略了return关键字并直接返回函数的结果。
6、python的内建函数
关于python的内建函数,一共有四个,分别是filter、map、reduce、zip
1、filter
它的功能是可以从一组值中把满足设定条件的值取出来
比如我们可以在一组值里面找出大于2的数
a=[1,2,3,4,5]
b=list(filter(lambda x:x>2,a))#在python3中filter返回值必须强制转换为list,否则不会执行
print(b)
2、map
map的功能是将我们传入的多个参数依次处理
比如我们可以将传入的列表的每个值加1
a=[1,2,3,4,5]
b=list(map(lambda x:x+1,a))//同样也需要强制装换
print(b)
也可以完成将两个列表的对应值相加
a=[1,2,3,4,5]
b=[6,7,8,9,10]
c=list(map(lambda x,y:x+y,a,b))
print(c)
所以传入map 的参数是多个,是可变的
3、reduce
从上图我们可以看到reduce的功能是把一个序列squence和初始值按照函数function的方法进行处理,其中只能处理一个序列且初始值是可以省略的
比如我们看这样一个程序
from functools import reduce
a=[2,3,4]
print(reduce(lambda x,y:x+y,a,1))
其执行结果为 10,我们便知道它其实是将初始值1与列表的第一个元素相加,然后再列表剩下的所有元素相加并返回结果
4、zip
zip的功能是对赋给其的参数进行竖向整合
比如我们可以设置两个元组,然后将其整合成新的元组
若两个元组不一样长,多出的部分将自动被剔除
同理,zip还可以将字典的关键字和值进行调换
dict1={'a':'aa','b':'bb'}
c=dict(zip(dict1.values(),dict1.keys()))
print(c)
7、闭包
闭包作为python函数的高级功能,如果在一个内部函数里,对在外部作用域(但不是在全局作用域)的变量进行引用,那么内部函数就被认为是闭包(closure)。
举个例子,比如我们用闭包实现一个加法功能
def func(x):
def func1(y):
return x+y
return func1
a=func(1)
print(a(2))
其输出结果为3
在这段函数里,func1就是内部函数,x就是被引用的变量(不再全局作用域中),则这个func1就是一个闭包。闭包=函数块+定义函数时的环境,func1就是函数块,x就是环境,当然这个环境可以有很多,不止一个简单的x。
使用闭包的需要注意的是:闭包不能修改外部作用域的的局部变量
那如何避免这一问题尼?比如我们写一个加法器
def func():
a=[0]
def func1():
a[0]+=1
return a[0]
return func1
b=func()
print(b())
print(b())
print(b())
print(b())
print(b())
其执行结果为
所以我们可以看出,如果我们把外部作用域的局部变量用列表来代替便可解决这一问题
我们也可以实现更复杂的闭包程序,比如计算a*x+b=y的值
def func(a,b):
def func1(x):
return a*x+b
return func1
b=func(3,5)
c=func(7,8)
print(b(10))
print(c(9))
执行结果为
8装饰器
有时我们希望给一个函数添加一些功能,但我们又不想给它添加代码,这时就可以用到装饰器这样的方式实现。
比如我们用装饰器写一个计算时间差函数
import time
def timer(func):
def func1():
start=time.time()
func()
end=time.time()
print("函数运行了%s秒"%(end-start))
return func1
@timer
def func():
time.sleep(3)
func()
其运行的结果为
那么这个函数我们如何理解尼?
首先,@timer这个语法糖就是装饰器,是用来修饰被装饰的func函数的,其次当我们调用func()时,程序发现这个func是被装饰器修饰的,便将该句调用变为timer(func),然后再传回我们开头定义的那个函数运行,那么开头那个函数是不是闭包尼,显然形式上有点像,明显的区别就是闭包传的是变量,而这个函数传的是一个函数名,也就是一个函数的指针。那么装饰器和闭包的区别是什么,那就是装饰器就是闭包,但是装饰器强调不修改原函数的基础上增加功能,关注的是嵌套函数的外部函数。
现在,我们看一个更复杂的例子,如何func()带有参数我们该怎么做?我们如何用一个装饰器来实现多个功能?看如下的例子
def cal(func):
def func1(a,b):#将参数传递到这个函数里面
print('开始')
func(a,b)
print('结束')
return func1
@cal
def add(a,b):
print(a+b)
@cal
def sub(a,b):
print(a-b)
add(4,5)
sub(5,4)
执行结果为
这个例子中即完成了对含参函数的传递,又完成了让一个装饰器函数可以实现不同的功能
那如何让装饰器对应实现的不同的功能时装饰器有些变化,看如下的例子
def new_cal(str):#只需要再嵌套一个函数
def cal(func):
def func1(a,b):
print('开始%s'%(str))
func(a,b)
print('结束%s'%(str))
return func1
return cal#返回第二层的函数名
@new_cal('add')
def add(a,b):
print(a+b)
@new_cal('sub')
def sub(a,b):
print(a-b)
add(4,5)
sub(5,4)
执行结果为
八、模块
如何写一个自己的模块尼,我们先写自己模块中的函数
def func():
print('123')
然后再调用自己的模块即可
import mymole
mymole.func()
输出结果为
九、PEP8编码规范
1、规范的变量命名方式
十、面向对象编程
类是描述具有相同属性、相同方法的属性的集合
面向对象的三大特征有:封装、继承、多态
1、封装
我们将一类事务的属性和方法封装成一个类来表示这类事务
比如我们简单封装一个游戏里怪物属性
class monster:
def __init__(self,hp=100):
self.hp=hp
def run(self):
print("移动到某一位置")
a1=monster(1000)
print(a1.hp)
其中,我们可以随意访问属性hp,就像我们学C语言结构体时,设置的属性变量一律被当做公共变量,如果我们不想变量被轻易访问该如何做?我们只需要在属性前面加两个个下划线就可以防止随意修该属性值。
class monster:
def __init__(self,hp=100):
self.__hp=hp
def run(self):
print("移动到某一位置")
def out(self):
print(self.__hp)
def updata(self,hp):
self.__hp=hp
a1=monster(1000)
a1.hp=100
a1.out()
a1.updata(100)
a1.out()
其执行结果为
2、继承
我们首先先写一个怪物类,然后有具体划分小怪和小boss和大boss
class monster:
def __init__(self,hp=100):
self.hp=hp
def run(self):
print("我是怪物的父类")
def out(self):
print(self.hp)
class Critters(monster):
def __init__(self,hp=10):
super().__init__(hp)#同名属性防止多次初始化
def run(self):
print("我是小怪物")
def out(self):
print(self.hp)
class boss(monster):
def __init__(self,hp=1000):
super().__init__(hp)#同名属性防止多次初始化
def run(self):
print("我是终极BOSS")
def out(self):
print(self.hp)
a1=monster()
a1.run()
a2=Critters()
a2.run()
a3=boss()
a3.run()
执行结果为
可以看出,子类同名函数和以覆盖父类的同名函数,这就叫多态,也就是以在继承类中一个函数名根据调用的环境不同可以有不同的执行结果
类的使用-自定义with函数
class withClass():
def __init__(self):
pass
def __enter__(self):
print("进入函数")
def __exit__(self, exc_type, exc_val, exc_tb):
if exc_tb is None:
print("无异常")
else:
print("产生的异常为%s" %exc_tb)
with withClass():
print("正常运行")
raise NameError('testNameError')
十一、多线程编程
如果我们学过操作系统的话,我们就可以知道,在传统的操作系统里我们执行一个程序,系统将其调入内存并为其分配一个进程让其有抢占CPU的权利,在引入线程的操作系统中,我们可以在一个进程下创建多个线程,这些线程不拥由资源(除了少量运行所必须的资源),他们共享其父进程的所有资源,在执行时,这些线程并发执行,同一时间只有一个线程占用处理机,但由于CPU的执行速度太快,所以我们会认为这些线程是“并行”执行的。
我们来实现一个消费者生产者问题
import time
from threading import current_thread,Thread
import random
from queue import Queue
queue=Queue(5)#Queue是线程安全的
class producer(Thread):
def run(self):
name=current_thread().getName()
nums=range(100)
global queue
while True:
num=random.choice(nums)
queue.put(num)
print("生产者%s生产了数据%s"%(name,num))
t=random.randint(1,3)
time.sleep(t)
print("生产者休息了%s秒"%(t))
class consumer(Thread):
def run(self):
name=current_thread().getName()
global queue
while True:
num=queue.get()
queue.task_done()
print("消费者%s消费了数据%s"%(name,num))
t=random.randint(1,3)
time.sleep(t)
print("生产者休息了%s秒"%(t))
p1=producer(name='p1')
p1.start()
p2=producer(name='p2')
p2.start()
p3=consumer(name='p3')
p3.start()
其中部分的执行结果为
其中,新创建的线程处于新建状态,但并不立即会得到执行,只有调用start()方法(一个线程智能调用一次start)时,线程才会处于就绪状态,但具体什么时候执行,取决于CPU什么时候调用。当我们调用sleep()方法时,线程会处于阻塞状态,直到阻塞时间完成后,该线程便从新进入就绪队列等待CPU调度。
task_done()的作用是当消费者吧队列处理完,即队列为空时,才解除生产者的阻塞,不然生产者就会一直等待消费者把生产的任务消费完之前一直阻塞
十二、python 的标准库
1、正则表达式re(文字处理)
正则表达式的元字符
‘.’:一个点匹配任意的单个字符,n个‘.’匹配任意n个元字符
import re
p=re.compile('.')
print(p.match('a'))
‘^’:表示以什么样的内容做开头,主要用于搜索和替换
‘$’:表示以什么样的内容做结尾,含义为从后面向前面匹配 (与search方法搭配)
import re
p=re.compile('jpg$')
print(p.search('match.jpg'))
‘*’表示在匹配时它前面的字符出现了0次或者多次
import re
p=re.compile('ca*t')
print(p.search('caaaaat'))
import re
p=re.compile('ca*t')
print(p.search('ct'))
‘?’:表示这个‘?’前面的字母出现0次或1次
import re
p=re.compile('ca?t')
print(p.search('ct'))
{m,n}表示{}前面的字符可以出现在n到m之间都可以匹配成功,其中,n可以省略,单m表示可以出现m次便算匹配成功
import re
p=re.compile('ca{4}t')
print(p.search('caaaaat'))
import re
p=re.compile('ca{4,6}t')
print(p.search('caaaaat'))
也可以与‘.’进行组合使用
import re
p=re.compile('.{3}')
print(p.search('cbt'))
[]:若出现字符cat、cbt、cct、cdt这些字符我们都算匹配成功,便可使用c[abcd]来进行匹配
import re
p=re.compile('c[abcd]t')
print(p.search('cbt'))
\d:是表示用来匹配数字的字符
\D:是用来匹配非数字的字符
\s:是用来匹配只包括从a到z的字符
():表示用来分组
结合以上几种特殊字符来实现识别年月日功能
import re
p=re.compile('(\d+)-(\d+)-(\d+)')#‘+’号表示匹配多个数字
print(p.search('2012-08-31').groups())
year,month,day=p.search('2012-08-31').groups()#groups()表示实现分组
print(year)
print(month)
print(day)
^$:表示这一行为空行
.?:表示不适用贪婪模式,比如我们要匹配的字符串是accccccd,我们用模式串ac来匹配时,尽可能更长的字符,这便叫贪婪模式 ,而我们用模式串ac*?来匹配时,便只匹配第一个我们匹配上的内容,也就是ac
2、search和match以及findall的区别
我们先来看一种情况
import re
p=re.compile(r'(\d+)-(\d+)-(\d+)')
print(p.match('aa2012-08-31bb').groups())
我们在报错中可以看出,在match中我们无法对含有其他字符的年月日进行匹配分组。但我们用search进行匹配时
import re
p=re.compile(r'(\d+)-(\d+)-(\d+)')
print(p.search('aa2012-08-31bb').groups())
所以,match是完全匹配之后用来分组,而search是用来搜索指定字符串,但search和match只能匹配到我们搜素的第一个字符,但findall可以匹配多次。
3、sub的用法
在使用中sub(‘a’,‘b’,‘c’)说的是我们把c字符或字符串中的‘a’字符替换为‘b’字符。
用一个例子就简单明了了
import re
phone='0197-12345678910 #这是我的电话号码'
print(re.sub('#.*$','',phone))# .*$表示从#开始到字符串尾的所有元素都会被‘’字符替代
4日期和时间函数库
常用的时间和日期函数库
import time
print(time.time())#表示从1970.1.1到现在所经历的一些秒数
print(time.localtime())#当前的年月日时间,一直精确到了秒数
print(time.strftime('%y-%m-%d %H:%M:%S'))#设定输出格式
import datetime
print(datetime.datetime.now())#输出当前时间
newtime=datetime.timedelta(minutes=10)#输出10分钟后的时间
print(datetime.datetime.now()+newtime)
one_day=datetime.datetime(2020,2,1)#输出指定时间的偏移时间
new_day=datetime.timedelta(minutes=10)
print(one_day+new_day)
5数学相关库
6文件夹相关操作库
import os
print(os.path.abspath('.'))#获取当前的绝对路径地址
print(os.path.exists('c:\\users'))#获取地址是否存在
print(os.path.isdir('c:\\users'))#判断是否是目录
print(os.path.isfile('c:\\users'))#判断是否是文件
print(os.path.join('c:\\users\\','f\\e'))#地址拼接
from pathlib import Path
p=Path('.')
print(p.resolve())#获取绝对路径地址
print(p.is_dir())#判断是否是目录
q=Path('E:\\u')
q.mkdir(parents=True)#根据路径创建文件夹