项目介绍
Python官方LOGO
项目是一个python入门的案例代码,可以帮助你通过实践来更好的学习python
项目地址:https://gitlab.com/lxqxsyu/PythonDemos
Tkinter是什么
Tkinter是python自带的一个图形开发介面库
python提供了多个图形开发界面的库,几个常用Python GUI库如下:
Tkinter: Tkinter模块(“Tk 接口”)是Python的标准Tk GUI工具包的接口.Tk和Tkinter可以在大多数的Unix平台下使用,同样可以应用在Windows和Macintosh系统里.,Tk8.0的后续版本可以实现本地窗口风格,并良好地运行在绝大多数平台中。
wxPython:wxPython 是一款开源软件,是 Python 语言的一套优秀的 GUI 图形库,允许 Python 程序员很方便的创建完整的、功能键全的 GUI 用户界面。
Jython:Jython程序可以和Java无缝集成。除了一些标准模块,Jython使用Java的模块。Jython几乎拥有标准的Python中不依赖于C语言的全部模块。比如,Jython的用户界面将使用Swing,AWT或者SWT。Jython可以被动态或静态地编译成Java字节码。
最简单 的Tkinter实例
tkinter显示一个窗体
我们从导入Tkinter模块开始。它包含了与Tk工具包一起工作所需的所有类,函数和其他东西。在大多数情况下,你可以简单地将所有东西从Tkinter导入你的模块名字空间:
要初始化Tkinter,我们必须创建一个Tk根部件。这是一个普通的窗口,窗口管理器提供标题栏和其他装饰。您应该只为每个程序创建一个根窗口小部件,并且必须在任何其他窗口部件之前创建它。
程序将保持在事件循环中,直到关闭窗口。事件循环不仅处理来自用户的事件(如鼠标点击和按键)还处理窗口系统(如重绘事件和窗口配置消息)事件。
相关文档地址:http://effbot.org/tkinterbook/tkinter-whats-tkinter.htm
python的模块
模块可以让你有逻辑的组织代码,可以把相关的代码分配到一个模块里。简单的说模块就是一个python文件,模块可以定义函数,类和变量.
import 语句
想使用Python源文件,只需在另一个源文件里执行import语句,语法如下:
1
| import module1[, module2[,... moduleN]
|
当解释器遇到import语句,如果模块在当前的搜索路径就会被导入。
搜索路径是一个解释器会先进行搜索的所有目录的列表。如想要导入模块hello.py,需要把命令放在脚本的顶端:
1
2
3
4
5
6
7
8
| #coding=utf-8
#!/usr/bin/python
# 导入模块
import support
# 现在可以调用模块里包含的函数了
support.print_func("Zara")
|
From…import 语句
Python的from语句让你从模块中导入一个指定的部分到当前命名空间中。语法如下:
1
| from modname import name1[, name2[, ... nameN]]
|
例如,要导入模块fib的fibonacci函数,使用如下语句:
1
| from fib import fibonacci
|
From…import 语句*
把一个模块的所有内容全都导入到当前的命名空间也是可行的,只需使用如下声明:
这提供了一个简单的方法来导入一个模块中的所有项目。然而这种声明不该被过多地使用。
定位模块
当你导入一个模块,Python解析器对模块位置的搜索顺序是:
- 当前目录
- 如果不在当前目录,Python则搜索在shell变量PYTHONPATH下的每个目录。
- 如果都找不到,Python会察看默认路径。UNIX下,默认路径一般为/usr/local/lib/python/
模块搜索路径存储在system模块的sys.path变量中。变量里包含当前目录,PYTHONPATH和由安装过程决定的默认目录。
python内置了很多常用的模块
dir()函数
dir()函数一个排好序的字符串列表,内容是一个模块里定义过的名字。
返回的列表容纳了在一个模块里定义的所有模块,变量和函数。如下一个简单的实例:
1
2
3
4
5
6
7
8
9
| #coding=utf-8
#!/usr/bin/python
# 导入内置math模块
import math
content = dir(math)
print(content)
|
dir()函数执行结果
python面向对象
创建类
1
2
3
4
5
6
7
8
9
10
| class Person:
#特殊方法,构造函数,创建这个类的时候会首先调用
def __init__(self, name, age):
self.name = name
self.age = age
#定义一个方法,显示人的信息
def displyPersonInfor(self):
print("name:", self.name, ", age:", self.age)
|
创建对象(对象就是类的具体实例)
1
| person = Person("xiaoming", 22)
|
访问属性及方法
1
2
3
4
| person.displyPersonInfor() #访问类的成员方法
print(person.name) #访问类的属性
print(person.age)
|
python对象销毁(垃圾回收)
析构函数 __del__
,__del__
在对象销毁的时候被调用,当对象不再被使用时,__del__
方法运行:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
| class Person:
#特殊方法,构造函数,创建这个类的时候会首先调用
def __init__(self, name, age):
self.name = name
self.age = age
#定义一个方法,显示人的信息
def displyPersonInfor(self):
print("name:", self.name, ", age:", self.age)
#析构函数,对象销毁的时候调用
def __del__(self):
print(self.__class__.__name__ + "销毁")
xiaoming = Person("xiaoming", 22)
xiaoming.displyPersonInfor() #访问类的成员方法
xiaoqiang = Person("xiaoqiang", 25)
xiaoqiang.displyPersonInfor()
del xiaoming
del xiaoqiang
|
类的继承
面向对象的编程带来的主要好处之一是代码的重用,实现这种重用的方法之一是通过继承机制。继承完全可以理解成类之间的类型和子类型关系。
继承语法 class 派生类名(基类名):基类名写作括号里,基本类是在类定义的时候,在元组之中指明的。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
| class Person:
#特殊方法,构造函数,创建这个类的时候会首先调用
def __init__(self, name, age):
self.name = name
self.age = age
#定义一个方法,显示人的信息
def displyPersonInfor(self):
print("name:", self.name, ", age:", self.age)
#析构函数,对象销毁的时候调用
def __del__(self):
print(self.__class__.__name__ + "销毁")
class Student(Person):
def __init__(self, name, age, grade):
Person.__init__(self, name, age)
self.grade = grade
def displyPersonInfor(self):
print("i am a student, my name is " + self.name)
def __del__(self):
print("student析构函数调用")
xiaoming = Person("xiaoming", 22)
xiaoming.displyPersonInfor() #访问类的成员方法
xiaoqiang = Student("xiaoqiang", 25, 3)
xiaoqiang.displyPersonInfor()
del xiaoming
del xiaoqiang
|
Tkinter面向对象写法
创建一个Frame窗体,然后给里面添加了一个关闭按钮
Tkinter面向对象写法
相关代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| #!/usr/bin/python3.6.3
#-*-coding:utf-8-*-
import tkinter
class App:
def __init__(self, master):
frame = tkinter.Frame(master)
frame.pack()
self.button = tkinter.Button(
frame, text="关闭", fg="red", command=frame.quit)
self.button.pack()
root = tkinter.Tk(None, None)
app = App(root)
root.mainloop()
|
细心的朋友会发现上面每次创建一个窗体对象就会调用一次pack()方法,这个pack()方法是用来确定窗体大小然后重绘窗体的。
案例一:计算器界面
我们先写出计算器界面的最上面一行和输入框
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
| #!/usr/bin/python3
#-*-coding:utf-8-*-
import tkinter
import tkinter.font
class Calculate():
def __init__(self, master):
master.title("Calculate")
master.resizable(0, 0)
self.showfont = tkinter.font.Font(master, size=26)
self.sysfont = tkinter.font.Font(master, size=16)
self.entry = tkinter.Entry(master, width=20, font=self.showfont, background="#ffffff")
self.entry.grid(row=0, column=0, columnspan=4, pady=10)
self.btn1 = tkinter.Button(master, text="1", font=self.sysfont)
self.btn1.grid(row=1, column=0, sticky = tkinter.N + tkinter.S + tkinter.W+tkinter.E)
self.btn2 = tkinter.Button(master, text="2", font=self.sysfont)
self.btn2.grid(row=1, column=1, sticky = tkinter.N + tkinter.S + tkinter.W+tkinter.E)
self.btn3 = tkinter.Button(master, text="3", font = self.sysfont)
self.btn3.grid(row=1, column=2, sticky = tkinter.N + tkinter.S + tkinter.W + tkinter.E)
self.btn_divide = tkinter.Button(master, text = "÷", font=self.sysfont)
self.btn_divide.grid(row=1, column = 3, sticky = tkinter.N + tkinter.S + tkinter.W + tkinter.E)
root = tkinter.Tk(None, None)
cal=Calculate(root)
root.mainloop()
|
tkinter实现计算器按钮过程示例
修改框体的名字,也可在创建时使用className参数来命名;
root.title(‘标题名’)
框体大小可调性,分别表示x,y方向的可变性;
root.resizable(0,0)
tkinter有那些UI控件呢?
Tkinter supports 15 core widgets
Button、Cavans、Checkbutton、Entry、Frame、Label、Listbox、Menu、Menubutton、Message、Radiobutton、Scale、Scrollbar、Text、Toplevel
计算器全部代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
| #!/usr/bin/python3
#-*-coding:utf-8-*-
import tkinter
import tkinter.font
class Calculate():
def __init__(self, master):
master.title("Calculate")
master.resizable(0, 0)
self.showfont = tkinter.font.Font(master, size=26)
self.sysfont = tkinter.font.Font(master, size=16)
self.entry = tkinter.Entry(
master, width=20, font=self.showfont, background="#ffffff")
self.entry.grid(row=0, column=0, columnspan=4, pady=10)
self.btn1 = tkinter.Button(master, text="1", font=self.sysfont)
self.btn1.grid(row=1, column=0, sticky=tkinter.N +
tkinter.S + tkinter.W + tkinter.E)
self.btn2 = tkinter.Button(master, text="2", font=self.sysfont)
self.btn2.grid(row=1, column=1, sticky=tkinter.N +
tkinter.S + tkinter.W + tkinter.E)
self.btn3 = tkinter.Button(master, text="3", font=self.sysfont)
self.btn3.grid(row=1, column=2, sticky=tkinter.N +
tkinter.S + tkinter.W + tkinter.E)
self.btn_divide = tkinter.Button(master, text="÷", font=self.sysfont)
self.btn_divide.grid(
row=1, column=3, sticky=tkinter.N + tkinter.S + tkinter.W + tkinter.E)
self.btn4 = tkinter.Button(master, text="4", font=self.sysfont)
self.btn4.grid(row=2, column=0, sticky=tkinter.N +
tkinter.S + tkinter.W + tkinter.E)
self.btn5 = tkinter.Button(master, text="5", font=self.sysfont)
self.btn5.grid(row=2, column=1, sticky=tkinter.N +
tkinter.S + tkinter.W + tkinter.E)
self.btn6 = tkinter.Button(master, text="6", font=self.sysfont)
self.btn6.grid(row=2, column=2, sticky=tkinter.N +
tkinter.S + tkinter.W + tkinter.E)
self.btn_mult = tkinter.Button(master, text="×", font=self.sysfont)
self.btn_mult.grid(row=2, column=3, sticky=tkinter.N +
tkinter.S + tkinter.W + tkinter.E)
self.btn7 = tkinter.Button(master, text="7", font=self.sysfont)
self.btn7.grid(row=3, column=0, sticky=tkinter.N +
tkinter.S + tkinter.W + tkinter.E)
self.btn8 = tkinter.Button(master, text="8", font=self.sysfont)
self.btn8.grid(row=3, column=1, sticky=tkinter.N +
tkinter.S + tkinter.W + tkinter.E)
self.btn9 = tkinter.Button(master, text="9", font=self.sysfont)
self.btn9.grid(row=3, column=2, sticky=tkinter.N +
tkinter.S + tkinter.W + tkinter.E)
self.btn_minus = tkinter.Button(master, text="-", font=self.sysfont)
self.btn_minus.grid(row=3, column=3, sticky=tkinter.N +
tkinter.S + tkinter.W + tkinter.E)
self.btn0 = tkinter.Button(master, text="0", font=self.sysfont)
self.btn0.grid(row=4, column=0, sticky=tkinter.N +
tkinter.S + tkinter.W + tkinter.E)
self.btn_point = tkinter.Button(master, text=".", font=self.sysfont)
self.btn_point.grid(row=4, column=1, sticky=tkinter.N +
tkinter.S + tkinter.W + tkinter.E)
self.btn_es = tkinter.Button(master, text="=", font=self.sysfont)
self.btn_es.grid(row=4, column=2, sticky=tkinter.N +
tkinter.S + tkinter.W + tkinter.E)
self.btn_add = tkinter.Button(master, text="+", font=self.sysfont)
self.btn_add.grid(row=4, column=3, sticky=tkinter.N +
tkinter.S + tkinter.W + tkinter.E)
root = tkinter.Tk(None, None)
cal = Calculate(root)
root.mainloop()
|
tkinter实现的计算器界面
Python中的包
包是一个分层次的文件目录结构,它定义了一个由模块及子包,和子包下的子包等组成的Python的应用环境。
考虑一个在Phone目录下的pots.py文件。这个文件有如下源代码:
1
2
3
4
5
| #coding=utf-8
#!/usr/bin/python
def Pots():
print "I'm Pots Phone"
|
同样地,我们有另外两个保存了不同函数的文件:
- Phone/Isdn.py 含有函数Isdn()
- Phone/G3.py 含有函数G3()
现在,在Phone目录下创建file __init__.py
:
当你导入Phone时,为了能够使用所有函数,你需要在__init__.py
里使用显式的导入语句,如下:
1
2
3
| from Pots import Pots
from Isdn import Isdn
from G3 import G3
|
当你把这些代码添加到__init__.py
之后,导入Phone包的时候这些类就全都是可用的了。
packagetest.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| #coding=utf-8
#!/usr/bin/python
# 导入内置math模块
#import math
#导入我们创建的Phone包
import Phone
#content = dir(math)
#print(content)
Phone.Pots()
Phone.Isdn()
Phone.G3()
|
python工程目录结构
案例二(android多渠道打包)
1
2
3
4
5
6
7
8
| #!/usr/bin/python
# coding=utf-8
# 空文件 便于写入此空文件到apk包中作为channel文件
src_empty_file = 'info/czt.txt'
# 创建一个空文件(不存在则创建)
f = open(src_empty_file, 'w')
f.close()
|
open函数
python中必须先用Python内置的open()函数打开一个文件,创建一个file对象,相关的辅助方法才可以调用它进行读写。
1
| file object = open(file_name [, access_mode][, buffering])
|
各个参数的细节如下:
- file_name:file_name变量是一个包含了你要访问的文件名称的字符串值。
- access_mode:access_mode决定了打开文件的模式:只读,写入,追加等。所有可取值见如下的完全列表。这个参数是非强制的,默认文件访问模式为只读(r)。
- buffering:如果buffering的值被设为0,就不会有寄存。如果buffering的值取1,访问文件时会寄存行。如果将buffering的值设为大于1的整数,表明了这就是的寄存区的缓冲大小。如果取负值,寄存区的缓冲大小则为系统默认。
不同模式打开文件的完全列表:
不同模式打开文件的完全列表
File对象的属性
一个文件被打开后,你有一个file对象,你可以得到有关该文件的各种信息。
以下是和file对象相关的所有属性的列表:
File对象的属性
1
2
3
4
5
6
7
8
9
| #!/usr/bin/python
# -*- coding: UTF-8 -*-
# 打开一个文件
fo = open("foo.txt", "wb")
print "文件名: ", fo.name
print "是否已关闭 : ", fo.closed
print "访问模式 : ", fo.mode
print "末尾是否强制加空格 : ", fo.softspace
|
close()方法
File对象的close()方法刷新缓冲区里任何还没写入的信息,并关闭该文件,这之后便不能再进行写入。
当一个文件对象的引用被重新指定给另一个文件时,Python会关闭之前的文件。用close()方法关闭文件是一个很好的习惯。
更多关于读写的方法请参考:https://www.w3cschool.cn/python/python-files-io.html
筛选apk文件
1
2
3
4
5
6
7
8
9
10
11
12
13
| # 获取当前目录中所有的apk源包
src_apks = []
# python3 : os.listdir()即可,这里使用兼容Python2的os.listdir('.')
apk_path = 'E:/AndroidStudio/work/xxx/app/build/outputs/apk/'
for file in os.listdir(apk_path):
fulldirfile = os.path.join(apk_path, file)
if os.path.isfile(fulldirfile):
extension = os.path.splitext(file)[1][1:]
if extension in 'apk':
if file.find('unaligned') == -1:
src_apks.append(fulldirfile)
print(src_apks)
|
Python中有很多标准库,我们来看看这个操作系统接口库os
注意:确保使用import os而不是from os import *。这样可以防止函数os.open()覆盖内建函数open(),两者之间的操作是很不同的。
我们可以通过dir()和help()函数来帮助我们了解这些库是怎么使用的
1
2
3
4
5
6
7
| import os
dir = dir(os)
print(dir)
help(os)
|
dir()和help()函数的输出结果
os.listdir(path='.')
返回一个list,包含给定path 目录下所有条目的名字。该list是任意顺序,不包括特殊条目'.‘以及’..',即使它们存在于目录中。
path可以是str类型或bytes类型。如果path的类型为bytes,则返回的文件名也将为bytes类型;否则,它们的类型为str。
*os.path.join(path, paths)
将一个或多个路径正确地连接起来。返回值是路径和*路径的任何成员与每个非空的后面紧跟一个目录分隔符(os.sep)的连接部分
os.path.isfile(path)
如果路径是现有的常规文件,则返回True。
os.path.splitext(path)
将从文件路径的后缀名分割字符串
关于更多module-os的函数请参考:http://python.usyiyi.cn/translate/python_352/library/os.html#module-os
os.path相关文档:http://python.usyiyi.cn/translate/python_352/library/os.path.html#module-os.path
完整代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
| #!/usr/bin/python
# coding=utf-8
import os
import zipfile
import shutil
# 空文件 便于写入此空文件到apk包中作为channel文件
src_empty_file = 'info/czt.txt'
# 创建一个空文件(不存在则创建)
f = open(src_empty_file, 'w')
f.close()
# 获取当前目录中所有的apk源包
src_apks = []
# python3 : os.listdir()即可,这里使用兼容Python2的os.listdir('.')
apk_path = 'E:/AndroidStudio/work/xxx/app/build/outputs/apk/'
for file in os.listdir(apk_path):
fulldirfile = os.path.join(apk_path, file)
if os.path.isfile(fulldirfile):
extension = os.path.splitext(file)[1][1:]
if extension in 'apk':
if file.find('unaligned') == -1:
src_apks.append(fulldirfile)
print(src_apks)
# 获取渠道列表
channel_file = 'info/channel.txt'
f = open(channel_file)
lines = f.readlines()
f.close()
for src_apk in src_apks:
# file name (with extension)
src_apk_file_name = os.path.basename(src_apk)
# 分割文件名与后缀
temp_list = os.path.splitext(src_apk_file_name)
# name without extension
src_apk_name = temp_list[0]
# 后缀名,包含. 例如: ".apk "
src_apk_extension = temp_list[1]
# 创建生成目录,与文件名相关
package_name = src_apk_name[0:src_apk_name.index('-')]
output_dir = 'G:/XXX打包/' + package_name +'/output_' + src_apk_name + '/'
# 目录不存在则创建
if not os.path.exists(output_dir):
os.mkdir(output_dir)
# 遍历渠道号并创建对应渠道号的apk文件
for line in lines:
# 获取当前渠道号,因为从渠道文件中获得带有\n,所有strip一下
target_channel = line.strip()
# 拼接对应渠道号的apk
target_apk = output_dir + src_apk_name + "-" + target_channel + src_apk_extension
# 拷贝建立新apk
shutil.copy(src_apk, target_apk)
# zip获取新建立的apk文件
zipped = zipfile.ZipFile(target_apk, 'a', zipfile.ZIP_DEFLATED)
# 初始化渠道信息
empty_channel_file = "META-INF/cztchannel_{channel}".format(channel = target_channel)
# 写入渠道信息
zipped.write(src_empty_file, empty_channel_file)
# 关闭zip流
zipped.close()
|
打包思路参考请参考:https://segmentfault.com/a/1190000003763833