Python两个案例练习

项目介绍

项目是一个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模块开始。它包含了与Tk工具包一起工作所需的所有类,函数和其他东西。在大多数情况下,你可以简单地将所有东西从Tkinter导入你的模块名字空间:

from Tkinter import *

要初始化Tkinter,我们必须创建一个Tk根部件。这是一个普通的窗口,窗口管理器提供标题栏和其他装饰。您应该只为每个程序创建一个根窗口小部件,并且必须在任何其他窗口部件之前创建它。

root = Tk()

程序将保持在事件循环中,直到关闭窗口。事件循环不仅处理来自用户的事件(如鼠标点击和按键)还处理窗口系统(如重绘事件和窗口配置消息)事件。

root.mainloop()

相关文档地址:http://effbot.org/tkinterbook/tkinter-whats-tkinter.htm

python的模块

模块可以让你有逻辑的组织代码,可以把相关的代码分配到一个模块里。简单的说模块就是一个python文件,模块可以定义函数,类和变量.

import 语句

想使用Python源文件,只需在另一个源文件里执行import语句,语法如下:

import module1[, module2[,… moduleN]

当解释器遇到import语句,如果模块在当前的搜索路径就会被导入。
搜索路径是一个解释器会先进行搜索的所有目录的列表。如想要导入模块hello.py,需要把命令放在脚本的顶端:

#coding=utf-8
#!/usr/bin/python

# 导入模块
import support

# 现在可以调用模块里包含的函数了
support.print_func("Zara")

From…import 语句

Python的from语句让你从模块中导入一个指定的部分到当前命名空间中。语法如下:

from modname import name1[, name2[, … nameN]]

例如,要导入模块fib的fibonacci函数,使用如下语句:

from fib import fibonacci

From…import* 语句

把一个模块的所有内容全都导入到当前的命名空间也是可行的,只需使用如下声明:

from modname import *

这提供了一个简单的方法来导入一个模块中的所有项目。然而这种声明不该被过多地使用。

定位模块

当你导入一个模块,Python解析器对模块位置的搜索顺序是:

  • 当前目录
  • 如果不在当前目录,Python则搜索在shell变量PYTHONPATH下的每个目录
  • 如果都找不到,Python会察看默认路径。UNIX下,默认路径一般为/usr/local/lib/python/

模块搜索路径存储在system模块的sys.path变量中。变量里包含当前目录,PYTHONPATH和由安装过程决定的默认目录。

python内置了很多常用的模块

dir()函数

dir()函数一个排好序的字符串列表,内容是一个模块里定义过的名字。

返回的列表容纳了在一个模块里定义的所有模块,变量和函数。如下一个简单的实例:

#coding=utf-8
#!/usr/bin/python

# 导入内置math模块
import math

content = dir(math)

print(content)

python面向对象

创建类

class Person:

    #特殊方法,构造函数,创建这个类的时候会首先调用
    def __init__(self, name, age):
        self.name = name
        self.age = age

    #定义一个方法,显示人的信息
    def displyPersonInfor(self):
        print("name:", self.name, ",  age:", self.age)

创建对象(对象就是类的具体实例)

person = Person("xiaoming", 22)

访问属性及方法

person.displyPersonInfor()  #访问类的成员方法

print(person.name)          #访问类的属性
print(person.age)

python对象销毁(垃圾回收)

析构函数 deldel在对象销毁的时候被调用,当对象不再被使用时,del方法运行:

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 派生类名(基类名)://… 基类名写作括号里,基本类是在类定义的时候,在元组之中指明的。

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窗体,然后给里面添加了一个关闭按钮

相关代码:

#!/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()方法是用来确定窗体大小然后重绘窗体的。

案例一:计算器界面

我们先写出计算器界面的最上面一行和输入框

#!/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();

修改框体的名字,也可在创建时使用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

计算器全部代码

#!/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()

Python中的包

包是一个分层次的文件目录结构,它定义了一个由模块及子包,和子包下的子包等组成的Python的应用环境。
考虑一个在Phone目录下的pots.py文件。这个文件有如下源代码:

#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

当你导入Phone时,为了能够使用所有函数,你需要在init.py里使用显式的导入语句,如下:

from Pots import Pots
from Isdn import Isdn
from G3 import G3

当你把这些代码添加到init.py之后,导入Phone包的时候这些类就全都是可用的了。

packagetest.py

#coding=utf-8
#!/usr/bin/python

# 导入内置math模块
#import math

#导入我们创建的Phone包
import Phone

#content = dir(math)
#print(content)

Phone.Pots()
Phone.Isdn()
Phone.G3()

案例二(android多渠道打包)

#!/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对象,相关的辅助方法才可以调用它进行读写。

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对象相关的所有属性的列表:

#!/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()方法关闭文件是一个很好的习惯。

fileObject.close();

更多关于读写的方法请参考:https://www.w3cschool.cn/python/python-files-io.html

筛选apk文件

# 获取当前目录中所有的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()函数来帮助我们了解这些库是怎么使用的

import os

dir = dir(os)

print(dir)

help(os)

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

完整代码

#!/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

关注水寒

更多精彩优质技术内容请扫描订阅