【莫烦Python】Python 基础教程学习笔记与代码

2 print

print(1)

字符串 print(‘’) print(“”)

print('I\‘m yan’) 斜杠后加个单引号就不会被判为字符串的结束单引号

括号内绿色表示字符串,黑色表示命令

a = 2
b = a*3
print(a,b)
>>> print(1)
1
>>> print('We are')
We are
>>> print("we are going")
we are going
>>> print('I\'m yan')
I'm yan
>>> print('apple'+'car')
applecar
>>> print('apple'+4)
Traceback (most recent call last):
  File "<pyshell#11>", line 1, in <module>
    print('apple'+4)
TypeError: can only concatenate str (not "int") to str
>>> print('apple'+'4')
apple4
>>> print('apple'+str(4))
apple4
>>> print(1+2)
3
>>> print('1+2')
1+2
>>> print(int('1')+2)
3
>>> print('1.2'+2)
Traceback (most recent call last):
  File "<pyshell#17>", line 1, in <module>
    print('1.2'+2)
TypeError: can only concatenate str (not "int") to str
>>> print(float('2.3')+2)
4.3

3 数学

加+ 减- 乘* 除/ 幂** 取余数% 取整//
>>> 1+1
2
>>> 1-1
0
>>> 2*2
4
>>> 3**2
9
>>> 2**4
16
>>> 8%2
0
>>> 8%3
2
>>> 7/3
2.3333333333333335
>>> 9//4
2
>>> 10//3
3
>>> 10/2
5.0

4 自变量

File-New file

a = 1
b = 2
c = 3
print(a,b,c)

或写成

a,b,c=1,2,3
print(a,b,c)

自变量运算

a=2
b=a*3
print(a,b)

运行时Run-Run Module

5 while循环

condition = 1
while condition < 10:
    print (condition)
    condition = condition + 1

持续循环时,用ctrl+c跳出

while True:
    print("I'm True")

6 for循环

在for循环之内的语句是在四个空格后写,如下面的print和inner语句 ,后面的outer语句在for之外。

另外 i 在列表中用for ,i会自动加1?

examp1e_1ist = [1,2,3,4,5,6,7,12,254,564,23,4,5,6]

for i in examp1e_1ist:
    print(i)
    print (' inner of for')
    
print (' outrt of for')

运行结果:

1
 inner of for
2
 inner of for
3
 inner of for
4
 inner of for
5
 inner of for
6
 inner of for
7
 inner of for
12
 inner of for
254
 inner of for
564
 inner of for
23
 inner of for
4
 inner of for
5
 inner of for
6
 inner of for
 outrt of for

选中for中包含的语句,按住CTRL+[ 或 CTRL+] 可以讲语句整体左右移动。

range含头不含尾(4,10)输出的是4-9

for i in range(4,10):
    print(i)

运行结果:

4
5
6
7
8
9

range(a,b,step) 表示从a到b,并且步进为step

for i in range(4,10,4):
    print(i)

运行结果:

4
8

打出左括号后显示黄色使用介绍框
在这里插入图片描述

7 if 条件

大小可以做连续的判断,而不是像C语言先判断x<y为1后再判断1>z.

而是判断 x<y,y>z是否同时成立。

x=1
y = 2
z= 1

if x < y >z:
    print ('yes')

运行结果为yes。

连续判断不正确则不输出yes

大于等于>= 小于等于<= 等于判断== 不等于!=

8 if else条件

if else 的位置相同,并且后面都有冒号。

x=5
y= 3
z= 9

if x <y :
    print('x < y')
else:
    print('x >= y')

运行结果:

x >= y

9 if elif else

满足if的第一个条件后就会跳出if elif else 语句

x=5
y =3
z= 9

if x > 8:
    print('x >8')
elif x <=8:
    print ('x <= 8')
elif x <6:
    print('x < 6')
print( 'finish ifelse' )

运行结果:

x <= 8
finish ifelse

10 def 函数

定义一个函数名字叫function或其他,再在命令行中使用函数名进行调用。
在这里插入图片描述

或者直接在脚本中定了了函数后调用,直接运行。

def function():
    print ('this is a function')
    a =1 +2
    print(a)

function()

11 函数、参数

def fun(a, b) :
    c = a*b
    print(' c=a*b=', c)

>>> fun(4,7)
 c=a*b= 28
>>> fun(b=6,a=3)
 c=a*b= 18

输出替换,转成字符串,此时的+号表示将两字符串连接

def multip1y(a,b):
    c = a*b
    print(str(c)+"="+str(a) +"*"+str(b))
>>> multip1y(6,8)
48=6*8

在Python中,f字符串(或称为格式化字符串)是一种方便的字符串格式化方式,可以将变量的值插入到字符串中。在f字符串中,可以使用花括号{}来包含变量名,这些变量名将在运行时被替换为它们的值。

def multiply(a,b):
    c=a*b
    print(f'{
      
      c}={
      
      a}*{
      
      b}')
>>> multiply(3,6)
18=3*6

12 函数默认参数

通过函数赋值

def sale_car (price,color,brand,is_second_hand) :
    print (' price:',price,
    'co1or:',color,
    'brand:',brand,
    'is_second_hand:',is_second_hand)

sale_car (10203,'red', 'carry', True)
 price: 10203 co1or: red brand: carry is_second_hand: True

1中是默认参数赋值,2中是需要将函数内的内容修改,可以观察到输出被修改为blue
在这里插入图片描述
需要定义的值不能在默认定义的值后面,否则会报错。如下需要定义品牌,放在了以及定义好的颜色后面,会报错。
在这里插入图片描述
改变位置后运行
在这里插入图片描述

13 全局&局部变量,global&local

APPLE为全局变量,a为局部变量,所有打印局部时报错

APPLE=100

def fun():
    a= 10
    return a+100

print (APPLE)
print(a)
100
Traceback (most recent call last):
  File "C:/Users/Desktop/python_exercise/pyyy.py", line 8, in <module>
    print(a)
NameError: name 'a' is not defined

打印函数返回值

APPLE=100

def fun():
    a= APPLE
    return a+100

print (APPLE)
print(fun())
100
200

按理全局变量放外边,如果一定想把全局放在函数内则使用global。

未运行之前的a为none,运行了fun函数之后a变为20。(此种情况一定记得在最前面对a赋值)

a =None
def fun():
    global a
    a= 20
    return a+100

print('a past is', a)
print(fun())
print('a now is', a)
a past is None
120
a now is 20

如果没有global a语句时,运行后a仍然为none

a =None
def fun():
    a= 20
    return a+100

print('a past is', a)
print(fun())
print('a now is', a)
a past is None
120
a now is None

15 读写文件

open()中的文件名没有,则会生成一个对应名字的文件,w表示write写操作。

写的内容在第一行表示了(text),其中的\n表示换行

写了之后必须记得要关上文档,所以close

text = "This is my first text.\nThis is next line.\nThis is last 1ine."
my_py_fi1e=open(' my_py_file.txt','w')
my_py_fi1e. write(text)
my_py_fi1e.close()

运行后会在此程序的存储位置中生成一个txt,其内容是我们写入的内容。

重写

如果直接写 add a new line 时会将原来的原件清空后写新内容

text = "This is my first text.\nThis is next line.\nThis is last 1ine."
my_py_fi1e=open(' my_py_file.txt','w')
my_py_fi1e. write('add a new line')
my_py_fi1e.close()

如下
在这里插入图片描述

附加

如果我们将open后的写改为附加(w改为a a表示append)

text = "This is my first text.\nThis is next line.\nThis is last 1ine."
append_txt='\nadd a new line'
my_py_fi1e=open(' my_py_file.txt','a')
my_py_fi1e. write(append_txt)
my_py_fi1e.close()

此时txt内容变为
在这里插入图片描述

my_fi1e = open(' my_py_file.txt','r')
counter = my_fi1e.read()
print(counter)
This is my first text.
This is next line.
This is last 1ine.
add a new line

readline 表示读行,一行一行的读

my_fi1e=open(' my_py_file.txt','r')
counter = my_fi1e.readline()
second_read =my_fi1e.readline()
print (counter, second_read)
This is my first text.
 This is next line.

readlines 表示全部读取

my_fi1e=open(' my_py_file.txt','r')
counter = my_fi1e.readlines()
print (counter)
['This is my first text.\n', 'This is next line.\n', 'This is last 1ine.\n', 'add a new line']

18 class类

class类,一般类是以首字母大写命名。

class Calculator:
    name = 'Good ca1cu1ator'
    price = 18
    def add(x, y):
        result =x+y
        print (result)
    def minus (x,y):
        result =x-y
        print (result)
    def times(x,y):
        result =x*y
        print (result)
    def divide(x, y) :
        result = x/y
        print (result)
>>> cal = Calculator
>>> cal.name
'Good ca1cu1ator'
>>> cal.price
18
>>> cal.minus(9,14)
-5
>>> cal.times(4,8)
32
>>> cal.divide(7,2)
3.5

19 类的init功能

注意此处的初始化左右是两个短线 ——init——,同时括号中要用self

class Calculator:
    def __init__(self,name,price,hight=20,width=16,weight=18):
       self.n = name
       self.p = price
       self.h = hight
       self.wi = width
       self.we = weight
    def add(self,x,y):
        result = x + y
        print(result)
    def minus(self,x,y):
        result = x-y
        print(result) 
    def times(self,x,y):
        result = x*y
        print(result)
    def divide(self,x,y):
        result = x/y
        print(result)
>>> c=Calculator('yuan',1)
>>> c.n
'yuan'
>>> c.p
1
>>> c.h
20
>>> c.we
18
>>> c.wi
16

使用类是一定记得加上self,否则会出现报错

如下初始化的时候用到了self.add 如果下面定义的函数中括号里没有self会出现报错,这样在初始就会计算一个加法。

同样不加self在命令行中使用c.we等也会报错。

20 input输入

input返回的是一个字符串

a_input = input (' P1ease give a number : ')
print ('This input number is',a_input)

input的字符串判断要通过用字符串表示的str(1)或‘2’来判断。

a_input = input (' P1ease give a number: ')
if a_input == str(1):
    print ('This is a good one')
elif a_input == '2':
    print (' see you')
else :
     print ('Good luck')

或者把input的数据转换为int类型再做判断

21 元组&列表

tuple元组 表示为(1,2,3,4,7)或 1,2,5,7,8 。即放在小括号内或无括号。

list列表[12,4,3,5,6]

a_tup1e =(2,5,6,7,4)
b_tup1e=5,6,3,2

a_list =[3,6,76,3,6]

for x in a_list:
    print(x)

运行结果:

3
6
76
3
6

在这里插入图片描述

len 表示长度,如此处的len(a_tuple)为5,range(5)就是0-4,此时就是输出a_tuple的0-4,就是全部数字。

虽然元组和列表的表示不一样,但是在print中都是用的中括号[]才不会报错。如果用小括号()会出现报错。

在这里插入图片描述

22 列表 list

增加(append)

在列表后面增加用到append

在这里插入图片描述

插入(insert)

在列表指定位置插入insert

此处表示在0,1,2的2位置上插入99

在这里插入图片描述

移除(remove)

remove表示移除值,而不是索引位,比如此处remove(5)表示的是移除掉列表中的第一个5,注意只会移除第一个5。

在这里插入图片描述

如下联系两次移除5

在这里插入图片描述

索引

索引位置

索引时可以用-1,-2等表示索引最后一位,倒数位等。

在这里插入图片描述

索引a[0:3]实际上索引的是0,1,2位(含头不含尾)。a[:3]表示从最前到2的位置,如下

在这里插入图片描述

a[-3:]也能够表示最后的第三位

在这里插入图片描述

索引值

索引值9的位置,用index可以知道9在第4位(01234)

在这里插入图片描述

计数(count)

列表a,计数5的数量,为3个

在这里插入图片描述

排序(sort)

sort会使得列表从小到大排序,并且排序后会覆盖掉原来的a,所以此时仍然是print(a),而不是print(a.sort())

在这里插入图片描述

如果要从大到小排序,则使用sort(reverse=Ture)

在这里插入图片描述

23 多维列表

排序(sort)

sort会使得列表从小到大排序,并且排序后会覆盖掉原来的a,所以此时仍然是print(a),而不是print(a.sort())

在这里插入图片描述

如果要从大到小排序,则使用sort(reverse=Ture)

在这里插入图片描述

a=[1,5,3,5,9,5,2]
multi_dim_a=[[1,2,3],[4,5,6],[7,8,9]]
print('a[3]=',a[3])
print('multi_dim_a[2][1]=',multi_dim_a[2][1])

运行结果(多维中[2][1]表示012,01的2和1):

a[3]= 5
multi_dim_a[2][1]= 8

24 字典

注意打印时的索引仍然用的[ ],而不是{ },增加字典内容也是[ ]。

d={
    
    'apple':3,'pear':7,'orange':9}   #字典
print('d=',d)
print('d[orange]=',d['orange'])

del d['pear']   #删除pear
print('deleted prar d=',d)

d['b'] = 20 #增加字典内容
d['pig'] = 100
d[1]= 12
print('add d=',d)

运行结果:

d= {
    
    'apple': 3, 'pear': 7, 'orange': 9}
d[orange]= 9
deleted prar d= {
    
    'apple': 3, 'orange': 9}
add d= {
    
    'apple': 3, 'orange': 9, 'b': 20, 'pig': 100, 1: 12}

同时,字典内还可以放字典,列表等,如打印出字典中apple中的3的内容。

d={
    
    'apple':{
    
    1:11,3:33,4:44},'pear':[3,7,9,2],'orange':9}   #字典
print(d['apple'][3])

运行结果为33。

25 import

import time模块,运行后显示当然时间。

import time

print(time.localtime())

或者为了简便书写,把time命名为t,运行后是同样的效果。

import time as t

print(t.localtime())

如果只需要用到个别的内容,可以写from xxx import xxx,xxx

from time import time,localtime
# 此时运用就不需要前缀time.XXX

print(localtime())
print(time())

导入time中所有的功能用*

from time import *
# 此时运用就不需要前缀time.XXX

print(localtime())
print(time())

26 自己的模块

建立自己的模块,在脚本中写如module1的模块,即文件名需要命名为module1

def add(a,b):
    c=a+b
    print('a+b=',c)

要进行调用时,需要在刚刚建立模块的同一目录下建立新的脚本

import module1 as m

m.add(5,8)

运行效果:

a+b= 13

对于python默认的自带模块则不需要保持在同一目录,所以对于自己之后建立的很有用的模块可以放在默认路径下,之后直接import即可。默认路径一般在python\Lib\site-packages中放入即可。

27 continue&break

不用continue或break时

a = True
while a:
    b = input('type something=')#input的内容被当作字符串
    if b== '1':
        a = False
    else:
        pass
    print('still in while')

print('finish run')

运行结果(当b==1时不是里面跳出循环,而是要将余下全部执行完再结束):

type something=2
still in while
type something=1
still in while
finish run

当使用break时,不是1时打印继续循环,是1时跳出循环,打印finish。

while True:
    b = input('type something=')#input的内容被当作字符串
    if b== '1':
        break
    else:
        pass
    print('still in while')

print('finish run')

运行结果:

type something=3
still in while
type something=5
still in while
type something=1
finish run

当使用continue时,不是1时打印继续循环,是1时继续执行while中的内容。

while True:
    b = input('type something=')#input的内容被当作字符串
    if b== '1':
        continue
    else:
        pass
    print('still in while')

print('finish run')

运行结果:

type something=2
still in while
type something=1
type something=

28 错误处理try…except…else

以下为简单的try…except…else的语法:

try:
<语句>        #运行别的代码
except <名字><语句>        #如果在try部份引发了'name'异常
except <名字><数据>:
<语句>        #如果引发了'name'异常,获得附加的数据
else:
<语句>        #如果没有异常发生

try的工作原理是,当开始一个try语句后,python就在当前程序的上下文中作标记,这样当异常出现时就可以回到这里,try子句先执行,接下来会发生什么依赖于执行时是否出现异常。

  • 如果当try后的语句执行时发生异常,python就跳回到try并执行第一个匹配该异常的except子句,异常处理完毕,控制流就通过整个try语句(除非在处理异常时又引发新的异常)。

  • 如果在try后的语句里发生了异常,却没有匹配的except子句,异常将被递交到上层的try,或者到程序的最上层(这样将结束程序,并打印默认的出错信息)。

  • 如果在try子句执行时没有发生异常,python将执行else语句后的语句(如果有else的话),然后控制流通过整个try语句。
    脚本代码如下(运行第一遍,输入y创建文件,运行第二遍向文件中写入内容ssss):

try:
    file=open('eeee','r+')
except:
    print('there is no file named eeee')
    response = input('do you want to creat a file?')
    if response =='y':
        file = open('eeee','w')
    else:
        pass
else:
    file.write('ssss')
file.close()

其中的open(‘filename’, ‘r+’)是打开文件的一种方式,其中’r+'表示以读写模式打开文件。这意味着可以读取文件的内容,也可以向文件写入内容。如果文件不存在,则会创建一个新文件。如果文件已经存在,则会从文件的开头开始读取和写入。

29 zip lambda map

>>> a =[1,2,3]
>>> b = [4,5,6]
>>> zip(a,b)
<zip object at 0x0000026ED9494148>	#运行结果,为一个object,不显示内容
>>> list(zip(a,b))					#放在list中显示
[(1, 4), (2, 5), (3, 6)] #运行结果
>>> for i,j in zip(a,b):
	print(i/2,j*2)

0.5 8					#运行结果
1.0 10
1.5 12

>>> list(zip(a,b,a))	#zip三组
[(1, 4, 1), (2, 5, 2), (3, 6, 3)]	#运行结果

>>> def fun1(x,y):
	return(x+y)

>>> fun1(4,6)
10					#运行结果
>>> fun2 = lambda x,y:x+y	#运行结果,lambda可以实现def同样的功能
>>> fun2(4,6)
10					#运行结果
>>> map(fun1,[1],[2])
<map object at 0x0000026ED9494048>	#运行结果,为一个object,不显示内容
>>> list(map(fun1,[1],[2]))
[3]						#运行结果
>>> list(map(fun1,[1,4],[5]))
[6]						#运行结果,如果不对应,只计算前一组
>>> list(map(fun1,[1,4],[5,8]))
[6, 12]					#运行结果

30 浅复制&深复制(copy&deepcopy)

直接用赋值b=a,两者的id一样,可以理解为a,b是同一个东西。改变其中一个另一个也会同时改变,且id保持一致。

a=[1,5,7]
>>> b=a
>>> id(a)
1815267812296
>>> id(b)
1815267812296
>>> a[0]=10		#改变a,b也同时改变
>>> b
[10, 5, 7]
>>> b[1]=20		#改变b,a也同时改变
>>> a
[10, 20, 7]
>>> id(a)==id(b)
True
>>> id(a[0])==id(b[0])
True
>>> id(a[1])==id(b[1])
True
>>> id(a[2])==id(b[2])
True

copy是浅复制,会把浅层的东西复制到别的id,深的不能够复制,所以id不变。

>>> a=[1,2,3]
>>> import copy
>>> c=copy.copy(a)
>>> id(a)==id(c)
False
>>> id(a[0])==id(c[0])  #各个位的值id为什么相同啦,推测是他们表示的是一个相同的数,而找的同一个数的id是相同的
True
>>> id(a[1])==id(c[1])
True
>>> id(a[2])==id(c[2])
True
>>> a[1]=1111	#被复制到别的id,改变a,c不变
>>> c
[1, 2, 3]
>>> a
[1, 1111, 3]
>>> c[1]=2222	#被复制到别的id,改变c,a不变
>>> a
[1, 1111, 3]
>>> c
[1, 2222, 3]

接下来试下深列表的copy

>>> a=[1,2,[3,4]]
>>> import copy
>>> d=copy.copy(a)
>>> d
[1, 2, [3, 4]]
>>> id(a)==id(d)
False
>>> a[0]=33		#改变a,d不变
>>> d
[1, 2, [3, 4]]
>>> a
[33, 2, [3, 4]]
>>> d[1]=55		#改变d,a不变
>>> a
[33, 2, [3, 4]]
>>> d
[1, 55, [3, 4]]

>>> d[2][0]=88		#改变d内列表中的第0个值后,a也同时改变
>>> a
[33, 2, [88, 4]]
>>> a[2][1]=99		#改变a内列表中的第1个值后,d也同时改变
>>> d
[1, 55, [88, 99]]

接下来使用deepcopy,这是完全的复制到别的id,改变一个不会影响另一个复制的内容。

>>> import copy
>>> a=[1,2,[3,4]]
>>> e =copy.deepcopy(a)
>>> e
[1, 2, [3, 4]]
>>> id(a) ==id(e)
False
>>> e[2][0]=55
>>> a
[1, 2, [3, 4]]
>>> e
[1, 2, [55, 4]]
>>> a[2][1]=77
>>> e
[1, 2, [55, 4]]
>>> a
[1, 2, [3, 77]]

31 Threading 多线程

Threading 多线程系列视频
Python3 多线程

1 什么是多线程

多线程类似于同时执行多个不同程序,多线程运行有如下优点:

  • 使用线程可以把占据长时间的程序中的任务放到后台去处理。
  • 用户界面可以更加吸引人,比如用户点击了一个按钮去触发某些事件的处理,可以弹出一个进度条来显示处理的进度。
  • 程序的运行速度可能加快。
  • 在一些等待的任务实现上如用户输入、文件读写和网络收发数据等,线程就比较有用了。在这种情况下我们可以释放一些珍贵的资源如内存占用等等。

每个独立的线程有一个程序运行的入口、顺序执行序列和程序的出口。但是线程不能够独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制。

每个线程都有他自己的一组CPU寄存器,称为线程的上下文,该上下文反映了线程上次运行该线程的CPU寄存器的状态。

指令指针和堆栈指针寄存器是线程上下文中两个最重要的寄存器,线程总是在进程得到上下文中运行的,这些地址都用于标志拥有线程的进程地址空间中的内存。

  • 线程可以被抢占(中断)。
  • 在其他线程正在运行时,线程可以暂时搁置(也称为睡眠) – 这就是线程的退让。

线程可以分为:

  • 内核线程:由操作系统内核创建和撤销。
  • 用户线程:不需要内核支持而在用户程序中实现的线程。

Python3 线程中常用的两个模块为:

  • _thread
  • threading(推荐使用)

thread 模块已被废弃。用户可以使用 threading 模块代替。所以,在 Python3 中不能再使用"thread" 模块。为了兼容性,Python3 将 thread 重命名为 “_thread”。

2 增加线程 add thread

import threading

def thread_job():
    print('This is an added,number is %s\n'% threading.current_thread())
def main():
    added_thread=threading.Thread(target=thread_job)
    added_thread.start()
    print(threading.active_count()) #激活的线程数
    print(threading.enumerate())    #返回当前活动的 Thread 对象列表
    print(threading.current_thread())#返回当前正在执行的线程对象

if __name__=='__main__':#判断是否为主模块,如果是,则运行main()函数
    main()

其中%s是一个占位符,表示后面要替换的变量或表达式的字符串表示。 具体的替换值由 % 符号后面的内容提供,这里是 threading.current_thread() 函数返回的线程对象。

如果占位符的类型是字符串,那么可以使用 %s;如果占位符的类型是整数,那么可以使用 %d;如果占位符的类型是浮点数,那么可以使用 %f。
例子如下:

name = 'John'
age = 30
height = 1.75

print('My name is %s, I am %d years old, and I am %f meters tall.' % (name, age, height))

3 join

在Python中,join()方法是线程类(Thread)的一个方法,它用于等待一个线程完成执行
当在一个线程中调用另一个线程的join()方法时,当前线程将会阻塞,直到被调用的线程执行完成或者超时

join()方法常常用于多线程编程中,以便在主线程中等待所有子线程执行完毕后再继续执行主线程的后续代码。如果没有使用join()方法,那么主线程可能会在子线程还在执行的时候就结束了,从而导致子线程无法完成任务。

join()方法可以传入一个参数,表示最长等待时间。如果被调用的线程在指定时间内没有执行完毕,join()方法会返回并继续执行当前线程的后续代码。如果不传入参数,则会一直等待直到被调用的线程执行完成。

import threading
import time
def T1_job():
    print('T1 start\n')
    for i in range(10):
        time.sleep(0.1)
    print('T1 finishi\n')

def T2_job():
    print('T2 start\n')
    print('T2 finish\n')

def main():
    thread1=threading.Thread(target=T1_job,name='T1')
    thread2 = threading.Thread(target=T2_job,name='T2')
    thread1.start()
    thread2.start()
    thread2.join()
    thread1.join()
    print('all done\n')
   
if __name__=='__main__':#判断是否为主模块,如果是,则运行main()函数
    main()

如果没有上面代码中的join时

 	thread2.join()
    thread1.join()

运行结果输出:

T1 start
T2 start
all done

T2 finish
>>> 
T1 finishi

只有thread1.join()时输出:

T1 start
T2 start


T2 finish

T1 finishi

all done

只有thread2.join()时输出:

T1 start
T2 start


T2 finish

all done

>>> T1 finishi

两个线程都有join时输出:

T1 start
T2 start


T2 finish

T1 finishi

all done

4 Queue

Python的Queue模块中提供了同步的、线程安全的队列类,包括FIFO(先入先出)队列Queue,LIFO(后入先出)队列LifoQueue,和优先级队列PriorityQueue。这些队列都实现了锁原语,能够在多线程中直接使用。可以使用队列来实现线程间的同步

通过创建一个Queue实例,我们可以在多个线程之间共享这个实例,并使用put()方法将数据添加到队列中,使用get()方法从队列中获取数据。

import threading
import time
from queue import Queue

def job(l,q):
    for i in range(len(l)):
        l[i]=l[i]**2
    q.put(l)        #线程是无法返回一个值的 

def multithreading():
    q = Queue()
    threads = []
    data= [[1,2,3],[3,4,5],[4,5,6],[5,6,7]]
    for i in range(4):
        t = threading.Thread(target=job,args=(data[i],q))#job后没有()
        t.start()
        threads.append(t)
    for thread in threads:
        thread.join()
    results = []
    for _ in range(4):
        results.append(q.get())
    print(results)
        
if __name__=='__main__':
    multithreading()

在Python中,我们可以使用threading模块创建线程。当我们创建一个线程时,我们可以使用target参数指定线程要执行的函数。在这个例子中,目标函数是job

除了target参数,threading.Thread()还提供了一个args参数。args是一个元组,它可以包含传递给目标函数的参数。在这个例子中,args参数包含两个值:data[i]和q。这意味着在启动线程时,目标函数job将被调用,并将data[i]和q作为参数传递给它

换句话说,args的作用是将参数传递给目标函数。这使得我们可以轻松地向函数传递多个参数,而不必在函数内部硬编码这些参数。

运行结果:

[[1, 4, 9], [9, 16, 25], [16, 25, 36], [25, 36, 49]]

5 不一定有效率 GIL

Python中单线程、多线程和多进程的效率对比实验
在这里插入图片描述
GIL(全局解释器锁)是Python中的一个重要概念,它是一种线程同步机制。在Python解释器中,每个线程都需要获取GIL才能执行,即一次只有一个线程可以在解释器中执行Python字节码。GIL是一个互斥锁,它可以确保同时只有一个线程可以访问Python对象和执行Python字节码。这种机制可以避免多个线程同时修改Python对象和字节码时出现竞争条件和数据不一致的问题。

GIL的存在对于Python的多线程应用程序有以下影响:

  1. 限制了多核CPU的利用:由于GIL的存在,多个线程不能同时执行Python字节码,这意味着Python中的多线程应用程序无法利用多个CPU核心。即使在多线程应用程序中使用多个线程,只有一个线程能够使用CPU,其他线程只能等待GIL的释放。

  2. 对I/O密集型应用程序的影响小:I/O密集型应用程序在执行期间需要等待外部资源(例如网络I/O或磁盘I/O),因此在这些应用程序中,GIL的影响相对较小。因为当一个线程在等待I/O时,其他线程可以获取GIL并执行Python代码。

  3. 对CPU密集型应用程序的影响大:CPU密集型应用程序需要大量的CPU资源,因此在这些应用程序中,GIL的影响相对较大。因为当一个线程执行CPU密集型任务时,其他线程必须等待GIL的释放,这可能会导致性能瓶颈。

需要注意的是,GIL只对解释器级别的Python代码起作用。对于Python中的一些扩展模块(例如numpy和pandas),它们使用的是C语言编写的代码,这些代码可以在不受GIL限制的情况下执行,因此它们可以充分利用多个CPU核心。

import threading
from queue import Queue
import copy
import time

def job(l, q):
    res = sum(l)
    q.put(res)

def multithreading(l):
    q = Queue()
    threads = []
    for i in range(4):
        t = threading.Thread(target=job, args=(copy.copy(l), q), name='T%i' % i)
        t.start()
        threads.append(t)
    [t.join() for t in threads]
    total = 0
    for _ in range(4):
        total += q.get()
    print(total)

def normal(l):
    total = sum(l)
    print(total)

if __name__ == '__main__':
    l = list(range(1000000))
    s_t = time.time()
    normal(l*4)
    print('normal: ',time.time()-s_t)
    s_t = time.time()
    multithreading(l)
    print('multithreading: ', time.time()-s_t)

在这里插入图片描述

6 锁 lock

无锁时:

import threading

def job1():
    global A, lock
    for i in range(10):
        A += 1
        print('job1', A)

def job2():
    global A, lock
    for i in range(10):
        A += 10
        print('job2', A)
   
if __name__ == '__main__':
    A = 0
    t1 = threading.Thread(target=job1)
    t2 = threading.Thread(target=job2)
    t1.start()
    t2.start()
    t1.join()
    t2.join()

运行结果很混乱:
实际上是由于都用的A所以被交替使用
0+1=1,1+10为11 输出111
11+1=12,12+10=22 输出1222
+1,+10交替运行

job1job2  111

job1job2  1222

job1job2  2333

job1job2  3444

job1job2  4555

job1job2  5666

job1job2  6777

job1job2  7888

job1job2  8999

job1job2  100110

修改为A,B表示后

import threading

def job1():
    global A, lock
    for i in range(10):
        A += 1
        print('job1 %s '% A)

def job2():
    global B, lock
    for i in range(10):
        B += 10
        print('job2 %s '% B)
   
if __name__ == '__main__':
    A = 0
    B = 0
    t1 = threading.Thread(target=job1)
    t2 = threading.Thread(target=job2)
    t1.start()
    t2.start()
    t1.join()
    t2.join()

运行结果:

job1 1 job2 10 

job1 2 job2 20 

job1 3 job2 30 

job1 4 job2 40 

job1 5 job2 50 

job1 6 job2 60 

job1 7 job2 70 

job1 8 job2 80 

job1 9 job2 90 

job1 10 job2 100

有锁时:
使用lock.acquire()和 lock.release()表示锁的开始与结束。

import threading

def job1():
    global A, lock
    lock.acquire()
    for i in range(10):
        A += 1
        print('job1', A)
    lock.release()

def job2():
    global A, lock
    lock.acquire()
    for i in range(10):
        A += 10
        print('job2', A)
    lock.release()

if __name__ == '__main__':
    lock = threading.Lock()
    A = 0
    t1 = threading.Thread(target=job1)
    t2 = threading.Thread(target=job2)
    t1.start()
    t2.start()
    t1.join()
    t2.join()

运行结果:

job1 1
job1 2
job1 3
job1 4
job1 5
job1 6
job1 7
job1 8
job1 9
job1 10
job2 20
job2 30
job2 40
job2 50
job2 60
job2 70
job2 80
job2 90
job2 100
job2 110

32 Multiprocessing 让你的多核计算机发挥真正潜力

Multiprocessing系列视频

1 什么是多进程

在Python中,多进程是指同时运行多个独立的进程,每个进程都有自己的执行空间和系统资源。每个进程都可以独立地运行并执行任务,可以同时执行多个任务,从而实现并行处理。

Python的多进程模块(multiprocessing)可以用来创建和管理多个进程。每个进程都有自己的进程 ID,可以通过它来标识和控制进程的行为。多进程的优点是可以充分利用多核CPU,提高程序的执行效率。

在Python中,可以使用多种方式实现多进程,包括使用multiprocessing模块、使用os模块的fork方法创建子进程、使用subprocess模块调用其他程序等。使用多进程的时候需要注意进程间的通信和同步,避免数据竞争和死锁等问题。

2 创建进程

import multiprocessing as mp

def job(a,b):
    print('aaaa')

if __name__=='__main__':
    p1 = mp.Process(target=job,args=(1,2))
    p1.start()
    p1.join()

3 queue

本例中算了两次job再相加

import multiprocessing as mp

def job(q):
    res = 0
    for i in range(1000):
        res += i+i**2+i**3
    q.put(res) # queue

if __name__ == '__main__':
    q = mp.Queue()
    p1 = mp.Process(target=job, args=(q,))
    p2 = mp.Process(target=job, args=(q,))
    p1.start()
    p2.start()
    p1.join()
    p2.join()
    res1 = q.get()
    res2 = q.get()
    print(res1+res2)

4 效率对比 multithreading和multiprocessing

在 Python 中,time.time() 函数返回当前时间戳,即从1970年1月1日午夜(UTC/GMT的历元时间)到当前时间的秒数。它返回一个浮点数,通常表示为以秒为单位的小数,例如:1617217878.8957865。该函数常用于计算程序的执行时间。
例子中相减是为了获取程序运行时间。

import multiprocessing as mp
import threading as td
import time

def job(q):
    res = 0
    for i in range(1000000):
        res += i+i**2+i**3
    q.put(res) # queue

def multicore():
    q = mp.Queue()
    p1 = mp.Process(target=job, args=(q,))
    p2 = mp.Process(target=job, args=(q,))
    p1.start()
    p2.start()
    p1.join()
    p2.join()
    res1 = q.get()
    res2 = q.get()
    print('multicore:' , res1+res2)

def normal():
    res = 0
    for _ in range(2):
        for i in range(1000000):
            res += i+i**2+i**3
    print('normal:', res)

def multithread():
    q = mp.Queue()
    t1 = td.Thread(target=job, args=(q,))
    t2 = td.Thread(target=job, args=(q,))
    t1.start()
    t2.start()
    t1.join()
    t2.join()
    res1 = q.get()
    res2 = q.get()
    print('multithread:', res1+res2)

if __name__ == '__main__':
    st = time.time()
    normal()
    st1= time.time()
    print('normal time:', st1 - st)
    multithread()
    st2 = time.time()
    print('multithread time:', st2 - st1)
    multicore()
    print('multicore time:', time.time()-st2)

我的电脑运行结果:

normal: 499999666667166666000000
normal time: 1.3881876468658447
multithread: 499999666667166666000000
multithread time: 1.3638417720794678
multicore: 499999666667166666000000
multicore time: 0.8919181823730469

5 进程池 pool

import multiprocessing as mp

def job(x):
    return x*x

def multicore():
    pool = mp.Pool(processes=2)
    res = pool.map(job, range(10))
    print(res)
    res = pool.apply_async(job, (2,))
    print(res.get())
    multi_res =[pool.apply_async(job, (i,)) for i in range(10)]
    print([res.get() for res in multi_res])

if __name__ == '__main__':
    multicore()

6 共享内存 shared memory

multiprocessing.Value() 是 Python 中 multiprocessing 模块提供的一个函数,它的作用是创建一个共享变量,可以被多个进程同时访问和修改。

函数的括号内需要传入两个参数,分别是共享变量的类型和初始值。共享变量的类型可以是 ‘c’,‘b’,‘h’,‘i’,‘l’,‘f’ 或 ‘d’ 等基本数据类型的字符表示,分别表示 char,bool,short,int,long,float 和 double 类型的共享变量。初始值则是共享变量的初始值,可以是对应类型的任意合法值。

例如,可以通过以下代码创建一个整型共享变量 x,初始值为 0:

from multiprocessing import Value

x = Value('i', 0)

这样,在多个进程中可以通过 x.value 访问和修改这个共享变量的值,而且多个进程对共享变量的修改操作是同步的,不会出现数据竞争的问题

7 lock锁

import multiprocessing as mp
import time

def job(v, num, l):
    l.acquire()
    for _ in range(10):
        time.sleep(0.1)
        v.value += num
        print(v.value)
    l.release()

def multicore():
    l = mp.Lock()
    v = mp.Value('i', 0)
    p1 = mp.Process(target=job, args=(v, 1, l))
    p2 = mp.Process(target=job, args=(v, 3, l))
    p1.start()
    p2.start()
    p1.join()
    p2.join()

if __name__ == '__main__':
    multicore()

<错误:无输出>

33 Tkinter 做简单的窗口视窗 Python GUI

1 Tkinter是什么

Tkinter 是使用 python 进行窗口视窗设计的模块。Tkinter模块(“Tk 接口”)是Python的标准Tk GUI工具包的接口。作为 python 特定的GUI界面,是一个图像的窗口,tkinter是python 自带的,可以编辑的GUI界面,我们可以用GUI 实现很多直观的功能,比如想开发一个计算器,如果只是一个程序输入,输出窗口的话,是没用用户体验的。所有开发一个图像化的小窗口,就是必要的。

对于稍有GUI编程经验的人来说,Python的Tkinter界面库是非常简单的。python的GUI库非常多,选择Tkinter,一是最为简单,二是自带库,不需下载安装,随时使用,三则是从需求出发,Python作为一种脚本语言,一种胶水语言,一般不会用它来开发复杂的桌面应用,它并不具备这方面的优势,使用Python,可以把它作为一个灵活的工具,而不是作为主要开发语言,那么在工作中,需要制作一个小工具,肯定是需要有界面的,不仅自己用,也能分享别人使用,在这种需求下,Tkinter是足够胜任的!

2 Label & Button标签和按钮

import tkinter as tk

window = tk.Tk()
window.title('my window')
window.geometry('200x100')

var = tk.StringVar()
l = tk.Label(window, textvariable=var, bg='green', font=('Arial', 12), width=15,
             height=2)
#l = tk.Label(window, text='OMG! this is TK!', bg='green', font=('Arial', 12), width=15, height=2)
l.pack()

on_hit = False
def hit_me():
    global on_hit
    if on_hit == False:
        on_hit = True
        var.set('you hit me')
    else:
        on_hit = False
        var.set('')

b = tk.Button(window, text='hit me', width=15,
              height=2, command=hit_me)
b.pack()


window.mainloop()

3 Entry & Text输入,文本框

import tkinter as tk

window = tk.Tk()
window.title('my window')
window.geometry('200x200')
# e = tk.Entry(window, show="*")
e = tk.Entry(window, show="1")
e.pack()

def insert_point():
    var = e.get()
    t.insert('insert', var)
def insert_end():
    var = e.get()
    # t.insert('end', var)
    t.insert(2.2, var)

b1 = tk.Button(window, text='insert point', width=15,
              height=2, command=insert_point)
b1.pack()
b2 = tk.Button(window, text='insert end',
               command=insert_end)
b2.pack()
t = tk.Text(window, height=2)
t.pack()

window.mainloop()

4 Listbox列表部件

import tkinter as tk

window = tk.Tk()
window.title('my window')
window.geometry('200x200')

var1 = tk.StringVar()
l = tk.Label(window, bg='yellow', width=4, textvariable=var1)
l.pack()

def print_selection():
    value = lb.get(lb.curselection())
    var1.set(value)

b1 = tk.Button(window, text='print selection', width=15,
              height=2, command=print_selection)
b1.pack()

var2 = tk.StringVar()
var2.set((11,22,33,44))
lb = tk.Listbox(window, listvariable=var2)
list_items = [1,2,3,4]
for item in list_items:
    lb.insert('end', item)
lb.insert(1, 'first')
lb.insert(2, 'second')
lb.delete(2)
lb.pack()

window.mainloop()

5 Radiobutton选择按钮

import tkinter as tk

window = tk.Tk()
window.title('my window')
window.geometry('200x200')

var = tk.StringVar()
l = tk.Label(window, bg='yellow', width=20, text='empty')
l.pack()

def print_selection():
    l.config(text='you have selected ' + var.get())

r1 = tk.Radiobutton(window, text='Option A',
                    variable=var, value='A',
                    command=print_selection)
r1.pack()
r2 = tk.Radiobutton(window, text='Option B',
                    variable=var, value='B',
                    command=print_selection)
r2.pack()
r3 = tk.Radiobutton(window, text='Option C',
                    variable=var, value='C',
                    command=print_selection)
r3.pack()


window.mainloop()

6 Scale尺度

import tkinter as tk

window = tk.Tk()
window.title('my window')
window.geometry('200x200')

l = tk.Label(window, bg='yellow', width=20, text='empty')
l.pack()

def print_selection(v):
    l.config(text='you have selected ' + v)

s = tk.Scale(window, label='try me', from_=5, to=11, orient=tk.HORIZONTAL,
             length=200, showvalue=0, tickinterval=2, resolution=0.01, command=print_selection)
s.pack()

window.mainloop()

7 Checkbutton勾选项

import tkinter as tk

window = tk.Tk()
window.title('my window')
window.geometry('200x200')

l = tk.Label(window, bg='yellow', width=20, text='empty')
l.pack()

def print_selection():
    if (var1.get() == 1) & (var2.get() == 0):
        l.config(text='I love only Python ')
    elif (var1.get() == 0) & (var2.get() == 1):
        l.config(text='I love only C++')
    elif (var1.get() == 0) & (var2.get() == 0):
        l.config(text='I do not love either')
    else:
        l.config(text='I love both')

var1 = tk.IntVar()
var2 = tk.IntVar()
c1 = tk.Checkbutton(window, text='Python', variable=var1, onvalue=1, offvalue=0,
                    command=print_selection)
c2 = tk.Checkbutton(window, text='C++', variable=var2, onvalue=1, offvalue=0,
                    command=print_selection)
c1.pack()
c2.pack()


window.mainloop()

8 Canvas 画布

图片命名ins.gif放在同一文件夹中。
在这里插入图片描述

import tkinter as tk

window = tk.Tk()
window.title('my window')
window.geometry('200x200')

canvas = tk.Canvas(window, bg='blue', height=100, width=200)
image_file = tk.PhotoImage(file='ins.gif')
image = canvas.create_image(10, 10, anchor='nw', image=image_file)
x0, y0, x1, y1= 50, 50, 80, 80
line = canvas.create_line(x0, y0, x1, y1)
oval = canvas.create_oval(x0, y0, x1, y1, fill='red')
arc = canvas.create_arc(x0+30, y0+30, x1+30, y1+30, start=0, extent=180)
rect = canvas.create_rectangle(100, 30, 100+20, 30+20)
canvas.pack()

def moveit():
    canvas.move(rect, 0, 2)

b = tk.Button(window, text='move', command=moveit).pack()

window.mainloop()

9 Menubar 菜单

import tkinter as tk

window = tk.Tk()
window.title('my window')
window.geometry('200x200')

l = tk.Label(window, text='', bg='yellow')
l.pack()
counter = 0
def do_job():
    global counter
    l.config(text='do '+ str(counter))
    counter+=1

menubar = tk.Menu(window)
filemenu = tk.Menu(menubar, tearoff=0)
menubar.add_cascade(label='File', menu=filemenu)
filemenu.add_command(label='New', command=do_job)
filemenu.add_command(label='Open', command=do_job)
filemenu.add_command(label='Save', command=do_job)
filemenu.add_separator()
filemenu.add_command(label='Exit', command=window.quit)

editmenu = tk.Menu(menubar, tearoff=0)
menubar.add_cascade(label='Edit', menu=editmenu)
editmenu.add_command(label='Cut', command=do_job)
editmenu.add_command(label='Copy', command=do_job)
editmenu.add_command(label='Paste', command=do_job)

submenu = tk.Menu(filemenu)
filemenu.add_cascade(label='Import', menu=submenu, underline=0)
submenu.add_command(label="Submenu1", command=do_job)

window.config(menu=menubar)

window.mainloop()

10 Frame框架

import tkinter as tk

window = tk.Tk()
window.title('my window')
window.geometry('200x200')
tk.Label(window, text='on the window').pack()

frm = tk.Frame(window)
frm.pack()
frm_l = tk.Frame(frm, )
frm_r = tk.Frame(frm)
frm_l.pack(side='left')
frm_r.pack(side='right')

tk.Label(frm_l, text='on the frm_l1').pack()
tk.Label(frm_l, text='on the frm_l2').pack()
tk.Label(frm_r, text='on the frm_r1').pack()
window.mainloop()

11 messagebox弹窗

import tkinter as tk
import tkinter.messagebox

window = tk.Tk()
window.title('my window')
window.geometry('200x200')

def hit_me():
    #tk.messagebox.showinfo(title='Hi', message='hahahaha')   # return 'ok'
    #tk.messagebox.showwarning(title='Hi', message='nononono')   # return 'ok'
    #tk.messagebox.showerror(title='Hi', message='No!! never')   # return 'ok'
    #print(tk.messagebox.askquestion(title='Hi', message='hahahaha'))   # return 'yes' , 'no'
    #print(tk.messagebox.askyesno(title='Hi', message='hahahaha'))   # return True, False
    print(tk.messagebox.asktrycancel(title='Hi', message='hahahaha'))   # return True, False
    print(tk.messagebox.askokcancel(title='Hi', message='hahahaha'))   # return True, False
    print(tk.messagebox.askyesnocancel(title="Hi", message="haha"))     # return, True, False, None

tk.Button(window, text='hit me', command=hit_me).pack()
window.mainloop()

12 pack grid place放置位置

import tkinter as tk

window = tk.Tk()
window.geometry('200x200')

#canvas = tk.Canvas(window, height=150, width=500)
#canvas.grid(row=1, column=1)
#image_file = tk.PhotoImage(file='welcome.gif')
#image = canvas.create_image(0, 0, anchor='nw', image=image_file)

#tk.Label(window, text='1').pack(side='top')
#tk.Label(window, text='1').pack(side='bottom')
#tk.Label(window, text='1').pack(side='left')
#tk.Label(window, text='1').pack(side='right')

#for i in range(4):
    #for j in range(3):
        #tk.Label(window, text=1).grid(row=i, column=j, padx=10, pady=10)

tk.Label(window, text=1).place(x=20, y=10, anchor='nw')

window.mainloop()

13例子1登录窗口

图片命名welcome.gif放在同一文件的中。
在这里插入图片描述

import tkinter as tk

window = tk.Tk()
window.title('Welcome to Mofan Python')
window.geometry('450x300')

# welcome image
canvas = tk.Canvas(window, height=200, width=500)
image_file = tk.PhotoImage(file='welcome.gif')
image = canvas.create_image(0,0, anchor='nw', image=image_file)
canvas.pack(side='top')

# user information
tk.Label(window, text='User name: ').place(x=50, y= 150)
tk.Label(window, text='Password: ').place(x=50, y= 190)

var_usr_name = tk.StringVar()
var_usr_name.set('[email protected]')
entry_usr_name = tk.Entry(window, textvariable=var_usr_name)
entry_usr_name.place(x=160, y=150)
var_usr_pwd = tk.StringVar()
entry_usr_pwd = tk.Entry(window, textvariable=var_usr_pwd, show='*')
entry_usr_pwd.place(x=160, y=190)

def usr_login():
    pass
def usr_sign_up():
    pass

# login and sign up button
btn_login = tk.Button(window, text='Login', command=usr_login)
btn_login.place(x=170, y=230)
btn_sign_up = tk.Button(window, text='Sign up', command=usr_sign_up)
btn_sign_up.place(x=270, y=230)

window.mainloop()

14例子1登录窗口

import tkinter as tk
import pickle

window = tk.Tk()
window.title('Welcome to Mofan Python')
window.geometry('450x300')

# welcome image
canvas = tk.Canvas(window, height=200, width=500)
image_file = tk.PhotoImage(file='welcome.gif')
image = canvas.create_image(0,0, anchor='nw', image=image_file)
canvas.pack(side='top')

# user information
tk.Label(window, text='User name: ').place(x=50, y= 150)
tk.Label(window, text='Password: ').place(x=50, y= 190)

var_usr_name = tk.StringVar()
var_usr_name.set('[email protected]')
entry_usr_name = tk.Entry(window, textvariable=var_usr_name)
entry_usr_name.place(x=160, y=150)
var_usr_pwd = tk.StringVar()
entry_usr_pwd = tk.Entry(window, textvariable=var_usr_pwd, show='*')
entry_usr_pwd.place(x=160, y=190)

def usr_login():
    usr_name = var_usr_name.get()
    usr_pwd = var_usr_pwd.get()
    try:
        with open('usrs_info.pickle', 'rb') as usr_file:
            usrs_info = pickle.load(usr_file)
    except FileNotFoundError:
        with open('usrs_info.pickle', 'wb') as usr_file:
            usrs_info = {
    
    'admin': 'admin'}
            pickle.dump(usrs_info, usr_file)
    if usr_name in usrs_info:
        if usr_pwd == usrs_info[usr_name]:
            tk.messagebox.showinfo(title='Welcome', message='How are you? ' + usr_name)
        else:
            tk.messagebox.showerror(message='Error, your password is wrong, try again.')
    else:
        is_sign_up = tk.messagebox.askyesno('Welcome',
                               'You have not sign up yet. Sign up today?')
        if is_sign_up:
            usr_sign_up()

def usr_sign_up():
    pass

# login and sign up button
btn_login = tk.Button(window, text='Login', command=usr_login)
btn_login.place(x=170, y=230)
btn_sign_up = tk.Button(window, text='Sign up', command=usr_sign_up)
btn_sign_up.place(x=270, y=230)

window.mainloop()

15例子1登录窗口

import tkinter as tk
from tkinter import messagebox  # import this to fix messagebox error
import pickle

window = tk.Tk()
window.title('Welcome to Mofan Python')
window.geometry('450x300')

# welcome image
canvas = tk.Canvas(window, height=200, width=500)
image_file = tk.PhotoImage(file='welcome.gif')
image = canvas.create_image(0,0, anchor='nw', image=image_file)
canvas.pack(side='top')

# user information
tk.Label(window, text='User name: ').place(x=50, y= 150)
tk.Label(window, text='Password: ').place(x=50, y= 190)

var_usr_name = tk.StringVar()
var_usr_name.set('[email protected]')
entry_usr_name = tk.Entry(window, textvariable=var_usr_name)
entry_usr_name.place(x=160, y=150)
var_usr_pwd = tk.StringVar()
entry_usr_pwd = tk.Entry(window, textvariable=var_usr_pwd, show='*')
entry_usr_pwd.place(x=160, y=190)

def usr_login():
    usr_name = var_usr_name.get()
    usr_pwd = var_usr_pwd.get()
    try:
        with open('usrs_info.pickle', 'rb') as usr_file:
            usrs_info = pickle.load(usr_file)
    except FileNotFoundError:
        with open('usrs_info.pickle', 'wb') as usr_file:
            usrs_info = {
    
    'admin': 'admin'}
            pickle.dump(usrs_info, usr_file)
    if usr_name in usrs_info:
        if usr_pwd == usrs_info[usr_name]:
            tk.messagebox.showinfo(title='Welcome', message='How are you? ' + usr_name)
        else:
            tk.messagebox.showerror(message='Error, your password is wrong, try again.')
    else:
        is_sign_up = tk.messagebox.askyesno('Welcome',
                               'You have not signed up yet. Sign up today?')
        if is_sign_up:
            usr_sign_up()

def usr_sign_up():
    def sign_to_Mofan_Python():
        np = new_pwd.get()
        npf = new_pwd_confirm.get()
        nn = new_name.get()
        with open('usrs_info.pickle', 'rb') as usr_file:
            exist_usr_info = pickle.load(usr_file)
        if np != npf:
            tk.messagebox.showerror('Error', 'Password and confirm password must be the same!')
        elif nn in exist_usr_info:
            tk.messagebox.showerror('Error', 'The user has already signed up!')
        else:
            exist_usr_info[nn] = np
            with open('usrs_info.pickle', 'wb') as usr_file:
                pickle.dump(exist_usr_info, usr_file)
            tk.messagebox.showinfo('Welcome', 'You have successfully signed up!')
            window_sign_up.destroy()
    window_sign_up = tk.Toplevel(window)
    window_sign_up.geometry('350x200')
    window_sign_up.title('Sign up window')

    new_name = tk.StringVar()
    new_name.set('[email protected]')
    tk.Label(window_sign_up, text='User name: ').place(x=10, y= 10)
    entry_new_name = tk.Entry(window_sign_up, textvariable=new_name)
    entry_new_name.place(x=150, y=10)

    new_pwd = tk.StringVar()
    tk.Label(window_sign_up, text='Password: ').place(x=10, y=50)
    entry_usr_pwd = tk.Entry(window_sign_up, textvariable=new_pwd, show='*')
    entry_usr_pwd.place(x=150, y=50)

    new_pwd_confirm = tk.StringVar()
    tk.Label(window_sign_up, text='Confirm password: ').place(x=10, y= 90)
    entry_usr_pwd_confirm = tk.Entry(window_sign_up, textvariable=new_pwd_confirm, show='*')
    entry_usr_pwd_confirm.place(x=150, y=90)

    btn_comfirm_sign_up = tk.Button(window_sign_up, text='Sign up', command=sign_to_Mofan_Python)
    btn_comfirm_sign_up.place(x=150, y=130)

# login and sign up button
btn_login = tk.Button(window, text='Login', command=usr_login)
btn_login.place(x=170, y=230)
btn_sign_up = tk.Button(window, text='Sign up', command=usr_sign_up)
btn_sign_up.place(x=270, y=230)

window.mainloop()

猜你喜欢

转载自blog.csdn.net/weixin_48412658/article/details/129753519