精华内容
下载资源
问答
  • Matplotlib

    万次阅读 多人点赞 2018-08-23 23:28:21
    在matplotlib.pyplot中,各种各样的状态通过调用不同的函数被保存下来,因此,matplotlib 能够持续地对例如:当前的图形和绘图区域、并将绘图函数作用到当前轴上(请注意,这里和文档中大多数地方的“轴”的是图形...

    官网帮助文档地址:https://matplotlib.org/tutorials/introductory/pyplot.html 

    Pyplot简介

    matplotlib.pyplot 是一个命令风格的函数集合,这使得 matplotlib 工作起来和MATLAB很相似。每一个 pyplot 函数都会使图形发生一些变化,例如:创建一幅图形、在一幅图中创建一个绘图区域、在绘图区域中绘制一些线、使用标签对图形进行修饰,等等。在matplotlib.pyplot中,各种各样的状态通过调用不同的函数被保存下来,因此,matplotlib 能够持续地对例如:当前的图形和绘图区域、并将绘图函数作用到当前轴上(请注意,这里和文档中大多数地方的“轴”指的是图形的坐标系部分,而不是严格数学术语中的多个轴)。
               使用 pyplot 生成一个可视化效果非常快:

    import matplotlib.pyplot as plt
    plt.plot([1,2,3,4])
    plt.ylabel('some numbers')
    plt.show()

    你可能会觉得很奇怪:为什么X轴取值的范围是 0~3,而Y轴取值的范围是1~4 ?

    这是因为:如果你只提供 了一个列表或者数组作为 plot() 命令的参数,Matplotlib 就会把这个序列当作是Y轴上的取值,并自动地为你生成 X轴上的值。由于在python中范围是从0开始的,因此在默认情况下,X轴向量会与Y轴向量的长度相同但其取值会从0开始,正如我们所看到的X轴的数据是[0,1,2,3]。
               plot() 是一个多功能的命令,能够接收任意数量的参数,例如:你可以使用如下命令来绘制与X相对的Y的图形。

    plt.plot([1, 2, 3, 4], [1, 4, 9, 16])

    格式化图形样式

    plot() 还为每一对参数X和Y提供了一个可选的第三个格式化字符串参数用来指定图形的颜色和线型。该格式化字符串的字母和符号均来自于MATLAB,由一个代表颜色的字符串和一个代表线型的字符串组合而成。默认使用的格式化字符串是’b-‘(表示蓝色实线)。 
               如果想要使用红色的圆点来绘制上例中的图形,你可以这么写:

    plt.plot([1, 2, 3, 4], [1, 4, 9, 16], 'ro')
    plt.axis([0, 6, 0, 20])
    plt.show()

     你可以查看 plot() 的文档来获取关于线的样式和格式化字符串的完整列表。
                上例中的 axis() 命令接收了 [xmin, xmax, ymin, ymax] 列表作为参数来指定了各个轴的视口大小。但如果 Matplotlib 被限制成只能和 list 一起使用 ,那么它在数值处理上将显得几乎毫无用处 。通常,我们都会使用 numpy 数组,事实上,所有的序列都会在 Matplotlib 内部被转化成 numpy 数组。下面的例子展示了如何在一条命令里使用  numpy 数组绘制出几条样式不同的线:

    import numpy as np
    
    # evenly sampled time at 200ms intervals
    t = np.arange(0., 5., 0.2)
    
    # red dashes, blue squares and green triangles
    plt.plot(t, t, 'r--', t, t**2, 'bs', t, t**3, 'g^')
    plt.show()

     

     补充:plot()  中,格式化字符串由颜色、标识符和线型三部分组成,定义格式如下:

    fmt = '[color][marker][line]'

    其中,支持的颜色缩写有如下几个:

    charactercolor
    'b'blue
    'g'green
    'r'red
    'c'cyan
    'm'magenta
    'y'yellow
    'k'black
    'w'white

    标识符定义如下表所示:

    characterdescription
    '.'point marker
    ','pixel marker
    'o'circle marker
    'v'triangle_down marker
    '^'triangle_up marker
    '<'triangle_left marker
    '>'triangle_right marker
    '1'tri_down marker
    '2'tri_up marker
    '3'tri_left marker
    '4'tri_right marker
    's'square marker
    'p'pentagon marker
    '*'star marker
    'h'hexagon1 marker
    'H'hexagon2 marker
    '+'plus marker
    'x'x marker
    'D'diamond marker
    'd'thin_diamond marker
    '|'vline marker
    '_'hline marker

    可以选用的线型有以下四个:

    characterdescription
    '-'solid line style
    '--'dashed line style
    '-.'dash-dot line style
    ':'dotted line style

     以下是几个格式化字符串的示例:

    'b'    # blue markers with default shape
    'ro'   # red circles
    'g-'   # green solid line
    '--'   # dashed line with default color
    'k^:'  # black triangle_up markers connected by a dotted line

    使用关键字绘图

    Matplotlib 允许用户提供带有关键字的数据对象作为参数,一旦提供了带有关键字的数据,就能够直接使用关键字来代替这些变量去生成图形。
               我们可以使用某些命令来获取到这种格式的数据,例如:numpy.recarraypandas.DataFrame  。

    data = {'a': np.arange(50),
            'c': np.random.randint(0, 50, 50),
            'd': np.random.randn(50)}
    data['b'] = data['a'] + 10 * np.random.randn(50)
    data['d'] = np.abs(data['d']) * 100
    
    plt.scatter('a', 'b', c='c', s='d', data=data)
    plt.xlabel('entry a')
    plt.ylabel('entry b')
    plt.show()

    使用分类变量绘图

    使用分类变量来创建图形也是可以的,Matplotlib 允许用户直接把分类变量传递给多个绘图函数,例如:

    names = ['group_a', 'group_b', 'group_c']
    values = [1, 10, 100]
    
    plt.figure(1, figsize=(9, 3))
    
    plt.subplot(131)
    plt.bar(names, values)
    plt.subplot(132)
    plt.scatter(names, values)
    plt.subplot(133)
    plt.plot(names, values)
    plt.suptitle('Categorical Plotting')
    plt.show()

     控制线的属性 

    线的属性有很多,详情参见  matplotlib.lines.Line2D ,例如你可以设置:线宽、虚线和抗锯齿效果,等等。
               我们可以通过以下几种途径对线的属性进行设置:
               使用关键字参数

    plt.plot(x, y, linewidth=2.0)

    使用2D 线实例的set方法
               plot() 命令会返回一个线对象的列表,例如:line1, line2 = plot(x1, y1, x2, y2)。在下面的代码中,我们将假设我们只有一条线即plot() 命令返回的线列表的长度为 1 。我们使用 line, 来获取列表中的第一个元素。

    line, = plt.plot(x, y, '-')
    line.set_antialiased(False) # turn off antialising

               使用setp()命令
               下面示例一下如何使用MATLAB风格的命令对一个线列表的多个属性进行设置。很明显地,setp() 能够作用于一个对象列表或者是一个单独的对象。你既可以使用Python 的关键字作为参数也可以使用MATLAB风格的string/value 对作为参数:

    lines = plt.plot(x1, y1, x2, y2)
    # use keyword args
    plt.setp(lines, color='r', linewidth=2.0)
    # or MATLAB style string value pairs
    plt.setp(lines, 'color', 'r', 'linewidth', 2.0)

    2D 线实例的可用属性见下表:

    PropertyValue Type
    alphafloat
    animated[True | False]
    antialiased or aa[True | False]
    clip_boxa matplotlib.transform.Bbox instance
    clip_on[True | False]
    clip_patha Path instance and a Transform instance, a Patch
    color or cany matplotlib color
    containsthe hit testing function
    dash_capstyle['butt' | 'round' | 'projecting']
    dash_joinstyle['miter' | 'round' | 'bevel']
    dashessequence of on/off ink in points
    data(np.array xdata, np.array ydata)
    figurea matplotlib.figure.Figure instance
    labelany string
    linestyle or ls[ '-' | '--' | '-.' | ':' | 'steps' | ...]
    linewidth or lwfloat value in points
    lod[True | False]
    marker[ '+' | ',' | '.' | '1' | '2' | '3' | '4' ]
    markeredgecolor or mecany matplotlib color
    markeredgewidth or mewfloat value in points
    markerfacecolor or mfcany matplotlib color
    markersize or msfloat
    markevery[ None | integer | (startind, stride) ]
    pickerused in interactive line selection
    pickradiusthe line pick selection radius
    solid_capstyle['butt' | 'round' | 'projecting']
    solid_joinstyle['miter' | 'round' | 'bevel']
    transforma matplotlib.transforms.Transform instance
    visible[True | False]
    xdatanp.array
    ydatanp.array
    zorderany number

     如果你想要获取可供设置的线属性的列表,你可以直接调用 setp() 命令并传入一条线或者传入一个线列表作为唯一参数。

    lines = plt.plot([1, 2, 3])
    
    plt.setp(lines)
      alpha: float
      animated: [True | False]
      antialiased or aa: [True | False]
      ...snip

     使用多图形和多轴

    MATLAB和 pyplot 都有当前图形和当前轴的概念,所有的绘图命令都会被应用到当前轴上。在 Matplotlib 中,gca() 命令用来获取当前轴(一个 matplotlib.axes.Axes 实例),gcf() 命令用来获取当前图形(一个 matplotlib.figure.Figure 实例)。通常情况下,你并不需要考虑这些,因为 Matplotlib 会在后台对它们进行自动处理。
               下面是一个创建了两个子图形的示例脚本:

    def f(t):
        return np.exp(-t) * np.cos(2*np.pi*t)
    
    t1 = np.arange(0.0, 5.0, 0.1)
    t2 = np.arange(0.0, 5.0, 0.02)
    
    plt.figure(1)
    plt.subplot(211)
    plt.plot(t1, f(t1), 'bo', t2, f(t2), 'k')
    
    plt.subplot(212)
    plt.plot(t2, np.cos(2*np.pi*t2), 'r--')
    plt.show()

    figure()命令在这儿是一个可选项,因为默认创建的就是 figure(1) ,同样地,在没有手动地指定任何轴的情况下,将默认创建 subplot(111) 。subplot() 命令需要指定行数、列数、图形编号,其中图形编号的取值范围为(1 ~ 行数*列数)。如果行数*列数<10,参数之间的逗号可以省略。因此,subplot(211) 和 subplot(2, 1, 1) 的作用是一样的。

    你可以创建任意数量的子图形或者坐标系。如果你想要手动去放置一个坐标系可以使用 axes() 命令,并通过  axes([left, bottom, width, height]) 的四个参数( 0 ~ 1 的小数)来指定坐标系的位置和大小。

               手动设置坐标系示例:https://matplotlib.org/gallery/subplots_axes_and_figures/axes_demo.html
               绘制多个子图形示例:
               https://matplotlib.org/gallery/subplots_axes_and_figures/subplot_demo.html
               https://matplotlib.org/gallery/subplots_axes_and_figures/subplots_demo.html
               你可以通过多次调用figure() 方法并传入一个递增的图形编号来创建多个图形。当然,只要你喜欢每一个图形也可以包含多个子图形或者坐标系:

    import matplotlib.pyplot as plt
    plt.figure(1)                # the first figure
    plt.subplot(211)             # the first subplot in the first figure
    plt.plot([1, 2, 3])
    plt.subplot(212)             # the second subplot in the first figure
    plt.plot([4, 5, 6])
    
    
    plt.figure(2)                # a second figure
    plt.plot([4, 5, 6])          # creates a subplot(111) by default
    
    plt.figure(1)                # figure 1 current; subplot(212) still current
    plt.subplot(211)             # make subplot(211) in figure1 current
    plt.title('Easy as 1, 2, 3') # subplot 211 title
    plt.show()

     

     你可以使用 clf() 命令来清除当前图形或者使用 cla() 命令来清除当前坐标系。 如果你觉得由后台帮你维护图形状态(指当前的图像,图形和坐标系)这种方式比较烦人,无须绝望:这只是对面向对象API的一个瘦状态封装,你可以把它替换掉(参见 Artist tutorial )。
                如果你是在创建多个图形,你还需要注意另外一件事:图形所占用的内存直到你调用 close() 显式地将其关闭才会全部释放,如果只删除掉图形的引用或者通过窗口管理器销毁掉屏幕上的图像展示窗口,图形所占用的内存是不能完全被释放的,因为pyplot 在 close() 命令被调用之前仍会对其内部引用进行维护。

     使用文本

    使用 text() 命令可以在图形的任意位置添加文本,xlabel()、ylabel()、title() 用来在指定位置添加文本(更多详细案例参见 Text in Matplotlib Plots )。

    mu, sigma = 100, 15
    x = mu + sigma * np.random.randn(10000)
    
    # the histogram of the data
    n, bins, patches = plt.hist(x, 50, density=1, facecolor='g', alpha=0.75)
    
    
    plt.xlabel('Smarts')
    plt.ylabel('Probability')
    plt.title('Histogram of IQ')
    plt.text(60, .025, r'$\mu=100,\ \sigma=15$')
    plt.axis([40, 160, 0, 0.03])
    plt.grid(True)
    plt.show()

     

    所有的文本命令都会返回一个  matplotlib.text.Text  实例,跟前面线的属性设置一样,你可以往文本命令中传入关键字参数或者使用 setp() 命令来自定义文本的属性。

    t = plt.xlabel('my data', fontsize=14, color='red')

                关于文本的属性的更多细节请参见:https://matplotlib.org/tutorials/text/text_props.html

     在文本中使用数学表达式 

    Matplotlib 接收的文本表达式中可以包含 TeX 方程表达式,比如,书写时,需要使用 "$" 符号把TeX表达式包起来:

    plt.title(r'$\sigma_i=15$')

    标题字符串前面的”r”字符非常重要:它表示这个字符串是一个原生字符串,不用把里面的反斜杠当作 Python 的转义字符来看待。
               Matplotlib 有一个內建的 TeX 方程式的语法分析器和布局引擎,并带有自己的数学字体(详情参见  Writing mathematical expressions )。因此你可以不用安装TeX就能够跨平台使用数学表达式,对于那些已经安装了LaTeX和dvipng的用户,你也可以使用LaTex 来格式化你的文字并将输出的文本并入到你要展示的图形或者要保存的脚本中(详情参见 Text rendering With LaTeX)。

     注释文本 

    上面讲到过 text()命令的基本作用是在坐标系的任意位置添加一个文本,而文本通常是用来对图形的某些特征进行注释,annotate() 方法提供了一些非常有用的功能使得注释变得更加容易。对于注释有两个需要考虑的点:使用 xy 参数来代表需要被注释的位置;使用 xytext 参数来指定注释文本的放置位置;这两个参数的取值均为(x,y) 的组合。

    ax = plt.subplot(111)
    
    t = np.arange(0.0, 5.0, 0.01)
    s = np.cos(2*np.pi*t)
    line, = plt.plot(t, s, lw=2)
    
    plt.annotate('local max', xy=(2, 1), xytext=(3, 1.5),
                 arrowprops=dict(facecolor='black', shrink=0.05),
                 )
    
    plt.ylim(-2, 2)
    plt.show()

     

    在这个基础示例中,xy (箭头提示) 和 xytext(文本位置)都是在数据的坐标系中,这里还有许多其他种类的坐标系可以选择(详情参见  Basic annotationAdvanced Annotation),更多示例参见: Annotating Plots

     对数及其他非线性坐标系

    matplotlib.pylot 除了支持线性坐标系外,也支持对数和分对数等非线性坐标系,当数据的量级跨度比较大时会经常用到这些坐标系,改变一个坐标轴的刻度非常容易:

    plt.xscale('log')

    下例中展示了对于同样的数据,当Y轴使用不同刻度时的四个图形:

    from matplotlib.ticker import NullFormatter  # useful for `logit` scale
    
    # Fixing random state for reproducibility
    np.random.seed(19680801)
    
    # make up some data in the interval ]0, 1[
    y = np.random.normal(loc=0.5, scale=0.4, size=1000)
    y = y[(y > 0) & (y < 1)]
    y.sort()
    x = np.arange(len(y))
    
    # plot with various axes scales
    plt.figure(1)
    
    # linear
    plt.subplot(221)
    plt.plot(x, y)
    plt.yscale('linear')
    plt.title('linear')
    plt.grid(True)
    
    
    # log
    plt.subplot(222)
    plt.plot(x, y)
    plt.yscale('log')
    plt.title('log')
    plt.grid(True)
    
    
    # symmetric log
    plt.subplot(223)
    plt.plot(x, y - y.mean())
    plt.yscale('symlog', linthreshy=0.01)
    plt.title('symlog')
    plt.grid(True)
    
    # logit
    plt.subplot(224)
    plt.plot(x, y)
    plt.yscale('logit')
    plt.title('logit')
    plt.grid(True)
    # Format the minor tick labels of the y-axis into empty strings with
    # `NullFormatter`, to avoid cumbering the axis with too many labels.
    plt.gca().yaxis.set_minor_formatter(NullFormatter())
    # Adjust the subplot layout, because the logit one may take more space
    # than usual, due to y-tick labels like "1 - 10^{-3}"
    plt.subplots_adjust(top=0.92, bottom=0.08, left=0.10, right=0.95, hspace=0.25,
                        wspace=0.35)
    
    plt.show()

    你也可以添加你自定义的刻度,详情参见:Developer's guide for creating scales and transformations

    展开全文
  • 小甲鱼零基础入门学习python笔记

    万次阅读 多人点赞 2019-08-14 11:06:30
    小甲鱼老师零基础入门学习Python全套资料百度云(包括小甲鱼零基础入门学习Python全套视频+全套源码+全套PPT课件+全套课后题及Python常用工具包链接、电子书籍等)请往我的资源...

    小甲鱼老师零基础入门学习Python全套资料百度云(包括小甲鱼零基础入门学习Python全套视频+全套源码+全套PPT课件+全套课后题及Python常用工具包链接、电子书籍等)请往我的资源(https://download.csdn.net/download/qq_32809093/13099592查看

    目录:

    000 愉快的开始
    001 我和Python的第一次亲密接触
    002 用Python设计第一个游戏
    003 小插曲之变量和字符串
    004 改进我们的小游戏
    005 闲聊之Python的数据类型
    006 Pyhon之常用操作符
    007 了不起的分支和循环
    008 了不起的分支和循环2
    009 了不起的分支和循环3
    010 列表:一个打了激素的数组
    011列表:一个打了激素的数组2
    012列表:一个打了激素的数组3
    013元组:戴上了枷锁的列表
    014字符串:各种奇葩的内置方法
    015字符串:格式化
    016 序列!序列!
    017函数:Python的乐高积木
    018 函数:灵活即强大
    019函数:我的地盘听我的(局部变量与全局变量)
    020函数:内嵌函数和闭包
    021函数:lambda表达式
    022 函数:递归是神马
    023 递归:这帮小兔崽子
    024 递归:汉诺塔
    025 字典:当索引不好用时
    026 字典:当索引不好用时2
    027 集合:在我的世界里,你就是唯一
    028 文件:因为懂你,所以永恒
    029 文件:一个任务
    030 文件系统:介绍一个高大上的东西
    031 永久存储:腌制一缸美味的泡菜(pickle)
    032 异常处理:你不可能总是对的
    033 异常处理:你不可能总是对的2
    034 丰富的else语句及简洁的with语句
    035 图形用户界面入门:EasyGui
    036 类和对象:给大家介绍对象
    037 类和对象:面向对象编程
    038 类和对象:继承
    039 类和对象:拾遗
    040 类和对象:一些相关的BIF
    041 魔法方法:构造和析构
    042 魔法方法:算术运算
    043 魔法方法:算术运算2
    044 魔法方法:简单定制
    045 魔法方法:属性访问
    046 魔法方法:描述符(Property的原理)
    047 魔法方法:定制序列
    048 魔法方法:迭代器
    049 乱入:生成器
    050 模块:模块就是程序
    051 模块:__name__='__main__'、搜索路径和包
    052 模块:像个极客一样去思考
    053 论一只爬虫的自我修养
    054 论一只爬虫的自我修养2:实战
    055 论一只爬虫的自我修养3:隐藏

    064 GUI的终极选择:Tkinter
    065 GUI的终极选择:Tkinter2
    066 GUI的终极选择:Tkinter3
    067 GUI的终极选择:Tkinter4
    068 GUI的终极选择:Tkinter5
    069 GUI的终极选择:Tkinter6
    070 GUI的终极选择:Tkinter7
    071 GUI的终极选择:Tkinter8
    073 GUI的终极选择:Tkinter10
    074  GUI的终极选择:Tkinter11
    075 GUI的终极选择:Tkinter12
    076 GUI的终极选择:Tkinter13
    077 GUI的终极选择:Tkinter14

    078 Pygame:初次见面,请大家多多关照

     

    000 愉快的开始

    python跨平台。
    应用范围:操作系统、WEB、3D动画、企业应用、云计算
    大家可以学到什么Python3的所有常用语法、面向对象编程思维、运用模块进行编程、游戏编程、计算机仿真

    Python 是脚本语言
    脚本语言(Scripting language)是电脑编程语言,因此也能让开发者藉以编写出让电脑听命行事的程序。以简单的方式快速完成某些复杂的事情通常是创造脚本语言的重要原则,基于这项原则,使得脚本语言通常比 C 语言、C++语言 或 Java 之类的系统编程语言要简单容易。也让脚本语言另有一些属于脚本语言的特性:
    •  语法和结构通常比较简单
    •  学习和使用通常比较简单
    •  通常以容易修改程序的“解释”作为运行方式,而不需要“编译”
    •  程序的开发产能优于运行性能
    一个脚本可以使得本来要用键盘进行的相互式操作自动化。一个 Shell 脚本主要由原本需要在命令行输入的命令组成,或在一个文本编辑器中,用户可以使用脚本来把一些常用的操作组合成一组串行。主要用来书写这种脚本的语言叫做脚本语言。很多脚本
    语言实际上已经超过简单的用户命令串行的指令,还可以编写更复杂的程序。

    IDLE 是一个 Python Shell,shell 的意思就是“外壳”,基本上来说,就是一个通过键入文本与程序交互的途径!像我们 Windows 那个 cmd 窗口,像 Linux 那个黑乎乎的命令窗口,他们都是 shell,利用他们,我们就可以给操作系统下达命令。同样的,我们可以利用 IDLE 这个 shell 与 Python 进行互动。

    注:在 Python 中不能把两个完全不同的东西加在一起,比如说数字和文本

    如果我需要在一个字符串中嵌入一个双引号,正确的做法是:你可以利用反斜杠(\)对双引号转义:\",或者用单引号引起这个字符串

    001 我和Python的第一次亲密接触

    IDLE启动Python

    IDLE是一个Python Shellshell的意思就是“外壳”,基本上来说,就是一个通过键入文本与程序交互的途径

    我们看到>>>这个提示符,Ta的含义是告诉你,Python已经准备好了,在等着你键入Python指令呢

    好了,大家试试在IDLE里输入:

    >>>print (“I love fishc.com”)

    我们尝试点儿新的东西,我们输入

    >>>print(5+3)

    或者直接输入

    >>>5+3

    不妨在试试计算

    >>>1234567890987654321*987654321012345678

    还有我们可以将两个字符串“相加”在一起,这种做法叫做拼接字符串

    >>>print("well water"+"river")

    先试试

    >>> print("I love fishc.com"*2)

    >>> print("I love fishc.com\n"* 2)

    002 用Python设计第一个游戏

    实例1:

    print("---------我爱鱼C工作室----------")
    temp = input("不妨猜一下小甲鱼现在心里想的是哪个数字:")
    guess = int(temp)
    if guess == 8:
        print("我草,你是小甲鱼心里的蛔虫嘛?!")
        print("哼,猜中了也没有奖励!")
    else:
        print("猜错了,小甲鱼现在心里想的是8!")
        print("游戏结束,不玩啦")

    BIF 就是 Built-in Functions,内置函数。为了方便程序员快速编写脚本程序(脚本就是要编程速度快快快!!!),Python 提供了非常丰富的内置函数,我们只需要直接调用即可,例如 print() 的功能是“打印到屏幕”,input() 的作用是接收用户输入。

    在 Python 或 IDLE 中,输入 dir(__builtins__) 可以看到 Python 提供的内置方法列表(注意,builtins 前后是两个下划线哦)其中小写的就是 BIF。如果想具体查看某个BIF 的功能,比如 input(),可以在 shell 中输入 help(input),就会得到这个 BIF 的功能描述。哦,答案应该是 68 个

    >>> dir(__builtins__)  查看 Python 提供的内置方法列表

    >>> help(input)  查看input的具体使用说明 

    注:

    只有当标识符已经赋值后( Python 的变量是不用先声明的)才能在代码中使用,未赋值的标识符直接使用会导致运行时错误

    缩进是 Python 的灵魂

    Python 不允许 if 条件中赋值,所以 if c = 1: 会报错!

     

    003 小插曲之变量和字符串

    插曲之变量

    变量名就像我们现实社会的名字,把一个值赋值给一个名字时,Ta会存储在内存中,称之为变量(variable),在大多数语言中,都把这种行为称为“给变量赋值”或“把值存储在变量中”。

    不过Python与大多数其他计算机语言的做法稍有不同,Ta并不是把值存储在变量中,而更像是把名字贴在值的上边。

    所以有些Python程序员会说“Python”没有“变量”,只有“名字”。

    需要注意的地方

    在使用变量之前,需要对其先赋值。

    变量名可以包括字母、数字、下划线,但变量名不能以数字开头

    字母可以是大写或小写,但大小写是不同的。也就是说fishcFishC对于Python来说是完全不同的两个名字

    等号(=)是赋值的意思,左边是名字,右边是值,不可写反咯。

    插曲之字符串

    到目前为止,我们所认知的字符串就是引号内的一切东西,我们也把字符串叫做文本,文本和数字是截然不同的,咱看例子:>>>5+8

    >>> '5'+'8'

    要告诉Python你在创建一个字符串,就要在字符两边加上引号,可以是单引号或者双引号Python女士表示不挑剔。但必须成对,你不能一边单引号,另一边却花心的用上双引号结尾。

    如果字符串中需要出现单引号或双引号怎么办

    例如我想打印字符串:Let’s go!

    有两种方法,第一种比较常用,就是使用我们的转义符号(\)对字符串中的引号进行转义:

    >>> 'Let\'s go!'

    原始字符串

    好像反斜杠是一个好东西,但不妨试试打印:

    >>> str = 'C:\now'

    我们可以用反斜杠对自身进行转义:

    >>> str = 'C:\\now'

    原始字符串的使用非常简单,只需要在字符串前边加一个英文字母r即可(则都会以原始字符串输出):

    >>>str = r'C:\now'

    长字符串

    如果希望得到一个跨越多行的字符串,例如:

    我爱鱼C

    正如我爱小甲鱼,

    久久不肯散去……

    这我们就需要使用到三重引号字符串!

     

    004 改进我们的小游戏

    第一个改进要求:猜错的时候程序提示用户当前的输入比答案大了还是小了

    与操作and

    第二个改进要求:程序应该提供多次机会给用户猜测,专业点来讲就是程序需要重复运行某些代码。

    条件分支

    while循环

    实例1:找8

    temp = input("请输入一个数据:")
    guess = int(temp)
    i=0
    while guess != 8 and i < 3:
        i = i + 1
        temp = input("哎呀,猜错了,请重新输入吧:")
        guess = int(temp)
        if guess == 8:
            print("我草,你是小甲鱼心里的蛔虫嘛?")
            print("哼,猜对了也没有奖励")
        else:
            if guess > 8:
                print("哥,大了大了~~")
            else:
                print("嘿,小了!小了!!")
    print("游戏结束,不玩啦~~")

    random模块里边有一个函数叫做:randint()Ta会返回一个随机的整数。

    实例2:找随机数

    import random#导入随机数函数
    secret = random.randint(1,5)#随机生成1到5的一个随机数
    temp = input("请输入一个1-5的数据:")
    guess = int(temp)
    i=0
    while guess != secret and i < 6:
        i = i + 1
        guess = int(temp)
        if guess == secret:
            print("我草,你是小甲鱼心里的蛔虫嘛?")
            print("哼,猜对了也没有奖励")
        else:
            if guess > secret:
                print("哥,大了大了~~")
            else:
                print("嘿,小了!小了!!")      
            temp = input("请重新输入吧:")
    print("游戏结束,不玩啦~~")

     

    005 闲聊之Python的数据类型

    Python的一些数值类型:整型、布尔类型(True与False)、浮点型、e记法、复数类型等

    e记法(e4相当于10的四次方,e-10相当于10的-10次方)

    类型转换

    字符型转换为整型

    其它同上

    type()函数(可查看变量类型)

    isinstance()函数(用来判断两个输入参数类型是否一致)

     

    006 Pyhon之常用操作符

    算术操作符

    注:python中 \ 为除法, \\ 为整除 ,% 为取余

    幂运算(3的二次方)

    3的二次方后取负

    注:先幂运算、然后乘除、后加减、后逻辑

    3的负二次方

    比较操作符

    逻辑操作符

    优先级问题

    007 了不起的分支和循环

    打飞机游戏框架:

    加载背景音乐

    播放背景音乐(设置单曲循环)

    我方飞机诞生

    while True:
        if 用户是否点击了关闭按钮:
           推出程序
           
        interval += 1;
        if interval == 50:
           interval = 0;
           小飞机诞生
        小飞机移动一个位置
        屏幕刷新
        
        if 用户鼠标产生移动:
           我方飞机中心位置 = 用户鼠标位置
           屏幕刷新
           
        if 我方飞机与小飞机发生肢体冲突:
           我方挂,播放撞机音乐
           修改我方飞机图案
           打印“Game over"
           停止背景音乐,最好淡出

     

    008 了不起的分支和循环2

    现在小甲鱼来考考大家:

    按照100分制,90分以上成绩为A8090B6080C60以下为D,写一个程序,当用户输入分数,自动转换为ABCD的形式打印。

    score = int(input('请输入一个分数:'))
    if 100 >= score >= 90:
        print('A')
    elif 90 > score >= 80:
        print('B')
    elif 80 > score >= 60:
        print('C')
    elif 60 > score >= 0:
        print('D')
    else:
        print('输入错误!')

    条件表达式(三元操作符)

    有了这个三元操作符的条件表达式,你可以使用一条语句来完成以下的条件判断和赋值操作:

    x, y = 4, 5

    if x < y:

      small = x

    else:

      small = y

    例子可以改进为

    small = x if x < y else y    #如果x小于y,则small等于x,否则等于y

    断言(assert)

    assert这个关键字我们称之为“断言”,当这个关键字后边的条件为假的时候,程序自动崩溃并抛出AssertionError的异常。

    举个例子:

    >>> assert 3 > 4

    一般来说我们可以用Ta再程序中置入检查点,当需要确保程序中的某个条件一定为真才能让程序正常工作的话,assert关键字就非常有用了

     

    009 了不起的分支和循环3

    while循环

    while 条件:

                      循环体

    for循环

    虽然说Python是由C语言编写而来的,但是Tafor循环跟C语言的for循环不太一样,Pythonfor循环显得更为智能和强大!

    语法:

    for 目标 in 表达式:

         循环体

    每次取FishC中一个字符及空格输出

    range()函数

    语法:range( [strat],[stop],[step] )

    这个BIF有三个参数,其中用中括号括起来的两个表示这两个参数是可选的。

    step=1表示第三个参数的值默认值是1setp为每步距离

    range这个BIF的作用是生成一个从start参数的值开始到stop参数的值结束的数字序列

     

    break语句(结束本层循环)

    实例:

    bingo = '小甲鱼是帅哥'
    answer = input('请输入小甲鱼最想听的一句话:')

    while True:
        if answer == bingo:
            break
        answer = input('抱歉,错了,请重新输入(答案正确才能退出游戏):')

    print('哎哟,帅哦~')
    print('您真是小甲鱼肚子里的蛔虫啊^_^')

    continue语句(当前位置结束本次循环,重新开始下次循环)

    实例:

    for i in range(10):
        if i%2 != 0:
            print(i)
            continue
        i += 2
        print(i)

    010 列表:一个打了激素的数组

    列表一个打了激素的数组

    创建列表

    创建一个普通列表

    创建一个混合列表

    创建一个空列表

    向列表添加元素

    append()函数向列表末尾添加一个元素

    extend()函数向列表末尾添加多个元素

    insert(n,xxx)函数向列表中第n个元素前插入一个元素

    注:0表示第一个元素

    011列表:一个打了激素的数组2

    从列表中获取元素

    跟数组一样,我们可以通过元素的索引值(index)从列表获取单个元素,注意,列表索引值是从 0 开始的。

    从列表删除元素

    remove()函数表示从列表中删除某个元素

    del()函数也表示从列表中删除某个元素

    pop()函数从列表中取出最后一个元素

    列表分片(Slice

    利用索引值,每次我们可以从列表获取一个元素,但是我们总是贪心的,如果一次性需要获取多个元素,有没有办法实现呢?利用列表分片,我们可以简单的实现这个要求。

    member[0:2]表示从第1个元素开始拷贝,一共拷贝两个元素,即member[0]和member[1]

    列表的拷贝

    012列表:一个打了激素的数组3

    列表的一些常用操作符

    比较操作符

    逻辑操作符

    连接操作符

    重复操作符

    成员关系操作符

    关于分片“拷贝”概念的补充

    >>> dir(list)可查看所有列表的操作函数

    count()函数可计算列表中相同元素个数

    index()函数可索引列表元素

    reverse()将列表中元素倒序

    sort()将列表中元素从小到大排序

    关于分片“拷贝”概念的补充

    注:list13=list11相当于多了个指向列表的标签,list12 = list[:]是实实在在的拷贝

    013元组:戴上了枷锁的列表

    由于和列表是近亲关系,所以元组和列表在实际使用上是非常相似的。

    我们这节课主要通过讨论元组和列表到底有什么不同来学习元组,酱紫大家就不会觉得老是重复一样的内容

    我们主要从以下几个点来讨论学习:

    创键和访问一个元组

    创建元组(括号可以没有,但逗号一定要有)

    访问元组前两个元素

    更新和删除一个元组

    更新一个元组

    注:其并未对原元组进行修改,而是生成了一个新的元组,并贴上temp名字标签而已。原元组由于标签没有了,则会被自动回收。

    删除一个元组

    元组相关的操作符

    注:元组不允许修改和删除。

    014字符串:各种奇葩的内置方法

     

    015字符串:格式化

    由于花括号被解释掉,所以不打印后面中文

    字符串格式化符号含义

    将ASCII码97对应的字符输出

    格式化整数

    格式化操作符辅助命令

    5表示输出为五位数

    Python 的转义字符及其含义

     

    016 序列!序列!

    列表、元组和字符串的共同点

    都可以通过索引得到每一个元素

    默认索引值总是从0开始

    可以通过分片的方法得到一个范围内的元素的集合

    有很多共同的操作符(重复操作符、拼接操作符、成员关系操作符)

    使用list方法

    元组转换为列表

    注:元组为小括号,列表为中括号。

    max() 返回序列或者参数集合中的最大值

    min() 返回序列或者参数集合中的最小值

    sum(iterable[,start=0]) 返回序列iterable和可选参数start的总和

    sorted()将元素从小到大重新排列

    reversed()将元素倒序排列

    注:元组是不可以修改和删除的,所以不可以直接对元组使用sorted与reversed命令

    enumerate()将每个元素插入枚举

    zip()返回由各个参数的序列组成的元组

     

    017函数:Python的乐高积木

    定义一个函数和调用

     

    018 函数:灵活即强大

    形参和实参

    >>> def MyFirstFunction(name):

      '函数定义过程中的name是叫形参'

      #因为Ta只是一个形式,表示占据一个参数位置

      print('传递进来的' + name + '叫做实参,因为Ta是具体的参数值!')

    >>> MyFirstFunction('小甲鱼')

    传递进来的小甲鱼叫做实参,因为Ta是具体的参数值!

    关键字参数

    默认参数(即形参中给定默认值,则在未给实参时会以默认值输出)

    收集参数

     

    019函数:我的地盘听我的

    函数与过程

    再谈谈返回值

    如果有返回值,函数则返回对应值;如果没有,则返回None

    可以返回多个值

    019函数:我的地盘听我的(局部变量与全局变量)

    def discounts(price, rate):
        final_price = price * rate
        old_price = 88 #这里试图修改全局变量
        print('修改后old_price的值是:', old_price)
        return final_price

    old_price = float(input('请输入原价:'))
    rate = float(input('请输入折扣率:'))
    new_price = discounts(old_price, rate)
    print('修改后old_price的值是:', old_price)
    print('打折后价格是:', new_price)

    global可将局部变量声明为全局变量

    020函数:内嵌函数和闭包

    内嵌函数

    闭包(closure

    注:使用nonlocal语句将x强制为不是局部变量

    021函数:lambda表达式

    lambda表达式的作用

    Python写一些执行脚本时,使用lambda就可以省下定义函数过程,比如说我们只是需要写个简单的脚本来管理服务器时间,我们就不需要专门定义一个函数然后再写调用,使用lambda就可以使得代码更加精简

    对于一些比较抽象并且整个程序执行下来只需要调用一两次的函数,有时候给函数起个名字也是比较头疼的问题,使用lambda就不需要考虑命名的问题了

    简化代码的可读性,由于普通的屌丝函数阅读经常要跳到开头def定义部分,使用lambda函数可以省去这样的步骤。

    过滤函数filter可筛选出非零元素

    筛选出奇数

    注:lambda x:x%2用来判断是否为奇,x为奇则输出1,否则输出0;range(10)可生成0-9的10个整数,filter用来筛选非零元素;如果为偶数,则被筛选掉;如果为奇数,则保留,但输出的是rang(10)产生的原始数,因为lambda只是用来判断是否为奇偶

    range生成的0-9给了x,x经过2倍运算后再赋值给x

    022 函数:递归是神马

    汉诺塔游戏

    树结构的定义

    谢尔宾斯基三角形

    递归求阶乘

    写一个求阶乘的函数

    正整数阶乘指从1乘以2乘以3乘以4一直乘到所要求的数。

    例如所给的数是5,则阶乘式是1×2×3×4×5,得到的积是120,所以120就是4的阶乘。

    假设我们n的值传入是5,那么:

    实例:求阶乘

    def factorial(n):
        result = n
        for i in range(1, n):
            result *= i

        return result

    number = int(input('请输入一个正整数:'))
    result = factorial(number)
    print("%d 的阶乘是:%d"  % (number, result))#格式化为整数类型

    实例2:递归求阶乘

    def factorial(n):
        if n == 1:
            return 1
        else:
            return n * factorial(n-1)

    number = int(input('请输入一个正整数:'))
    result = factorial(number)
    print("%d 的阶乘是:%d" % (number, result))

    023 递归:这帮小兔崽子

    坑爹的兔子

    斐波那契数列的迭代实现

    我们都知道兔子繁殖能力是惊人的,如下图:

    我们可以用数学函数来定义:

    课间练习:假设我们需要求出经历了20个月后,总共有多少对小兔崽子?(迭代 vs 递归

    def fab(n):
        n1 = 1
        n2 = 1
        n3 = 1

        if n < 1:
            print('输入有误!')
            return -1

        while (n-2) > 0:
            n3 = n2 + n1
            n1 = n2
            n2 = n3
            n -= 1
        
        return n3

    result = fab(20)
    if result != -1:
        print('总共有%d对小兔崽子诞生!' % result)

    斐波那契数列的递归实现

    递归实现(递归计算时间将拉长)

    def fab(n):
        if n < 1:
            print('输入有误!')
            return -1

        if n == 1 or n == 2:
            return 1
        else:
            return fab(n-1) + fab(n-2)

    result = fab(35)
    if result != -1:
        print('总共有%d对小兔崽子诞生!' % result)

    注:迭代计算时间远比递归少,因为递归要循环出入栈

    024 递归:汉诺塔

    递归求解汉诺塔

     

    对于游戏的玩法,我们可以简单分解为三个步骤

    将前63个盘子从X移动到Y上。

    将最底下的第64个盘子从X移动到Z上。

    Y上的63个盘子移动到Z上。

    问题一:将X上的63个盘子借助Z移到Y上;

    问题二:将Y上的63个盘子借助X移到Z上。

     

    对于游戏的玩法,我们可以简单分解为三个步骤

    将前63个盘子从X移动到Y上。

    将最底下的第64个盘子从X移动到Z上。

    Y上的63个盘子移动到Z上。

    问题一:将X上的63个盘子借助Z移到Y上;

    问题二:将Y上的63个盘子借助X移到Z上。

    实例:

    def hanoi(n, x, y, z):
        if n == 1:
            print(x, ' --> ', z)
        else:
            hanoi(n-1, x, z, y) # 将前n-1个盘子从x移动到y上
            print(x, ' --> ', z) # 将最底下的最后一个盘子从x移动到z上
            hanoi(n-1, y, x, z) # 将y上的n-1个盘子移动到z上

    n = int(input('请输入汉诺塔的层数:'))
    hanoi(n, 'X', 'Y', 'Z')

    025 字典:当索引不好用时

    映射

    创建和访问字典

    >>> dict4 = dict(小甲鱼='让编程改变世界',李宁='一切皆有可能')
    >>> dict4
    {'小甲鱼': '让编程改变世界', '李宁': '一切皆有可能'}

    >>> dict4['爱迪生'] = '天才是99%的汗水加1%的灵感'
    >>> dict4
    {'小甲鱼': '让编程改变世界', '李宁': '一切皆有可能', '爱迪生': '天才是99%的汗水加1%的灵感'}

    026 字典:当索引不好用时2

    fromkey()方法用于创建并返回一个新的字典它有两个参数,第一个参数是字典的键;第二个参数是可选的,是传入键的值。如果不提供,默认是None

    >>> dict1 = {}
    >>> dict1.fromkeys((1,2,3))
    {1: None, 2: None, 3: None}
    >>> dict2 = {}
    >>> dict2.fromkeys((1,2,3),"Number")
    {1: 'Number', 2: 'Number', 3: 'Number'}
    >>> dict3 = {}
    >>> dict3.fromkeys((1,2,3),('one','two','three'))
    {1: ('one', 'two', 'three'), 2: ('one', 'two', 'three'), 3: ('one', 'two', 'three')}

    访问字典的方法有key()、values()和items()

    key()用于返回字典中的键,value()用于返回字典中所有的值,item()当然就是返回字典中所有的键值对(也就是项)

    >>> dict1 = dict1.fromkeys(range(5),'赞')
    >>> dict1.keys()
    dict_keys([0, 1, 2, 3, 4])
    >>> dict1.values()
    dict_values(['赞', '赞', '赞', '赞', '赞'])
    >>> dict1.items()
    dict_items([(0, '赞'), (1, '赞'), (2, '赞'), (3, '赞'), (4, '赞')])

    get()方法提供了更宽松的方式去访问字典项,当键不存在的时候,get()方法并不会报错,只是默默第返回一个None,表示啥都没找到:

    >>> dict1.get(10)
    >>> dict1.get(4)
    '赞'

    如果希望找不到数据时返回指定的值,可以在第二个参数设置对应的默认返回值:

    >>> dict1.get(32,'木有')
    '木有'

    如果不知道一个键是否在字典中,可以使用成员资格操作符(in 或 not in)来判断
    >>> 31 in dict1
    False
    >>> 4 in dict1

    clear()可清空一个字典

    >>> dict1
    {0: '赞', 1: '赞', 2: '赞', 3: '赞', 4: '赞'}
    >>> dict1.clear()
    >>> dict1
    {}

    copy()方法是复制字典(全拷贝)

    >>> a = {1:'one',2:'two',3:'three'}
    >>> b = a.copy()
    >>> id(a)
    52448840
    >>> id(b)
    52503624
    >>> a[1] = 'four'
    >>> a
    {1: 'four', 2: 'two', 3: 'three'}
    >>> b
    {1: 'one', 2: 'two', 3: 'three'}

    pop()是给定键弹出对应的值,popitem()是随机弹出一个项

    >>> a.pop(2)
    'two'
    >>> a
    {1: 'four', 3: 'three'}
    >>> a.popitem()
    (1, 'four')
    >>> a
    {3: 'three'}

    setdefault()方法与get()方法相似,但setdefault()在字典中找不到相应的键值时会自动添加

    >>> a = {1:'one',2:'two',3:'three'}
    >>> a.setdefault(2)
    'two'
    >>> a.setdefault(4)
    >>> a
    {1: 'one', 2: 'two', 3: 'three', 4: None}

    update()方法可以更新字典

    >>> a = {1:'one','小白':None}

    >>> b = {'小白':'狗'}
    >>> a.update(b)
    >>> a
    {1: 'one', '小白': '狗'}

    027 集合:在我的世界里,你就是唯一

    字典的表亲--集合(在python3中,如果用大括号括起一堆数字但没有体现映射关系,那么就会认为这堆玩意儿就是个集合)

    >>> num1 = {}
    >>> type(num1)
    <class 'dict'>
    >>> num2 = {1,3,4}
    >>> type(num2)
    <class 'set'>

    集合中的元素都是唯一的(集合会自动帮我们把重复的数据清理掉,集合是无序的,所以不能试图去索引集合中的某一个元素

    >>> num = {1,2,3,4,5,5,4,3,2,1}
    >>> num
    {1, 2, 3, 4, 5}

    如何创建一个集合有两种方法:1、直接把一堆元素用大括号括起来;2、用set()

    一种是直接把一堆元素用花括号括起来

    >>> set1 = {'小甲鱼','小鱿鱼','小甲鱼'}

    一种是使用set()工厂函数

    >>> set2 = set(['小甲鱼','小鱿鱼','小甲鱼'])
    >>> set1 == set2
    True

    课堂搞搞看

    要求:去掉列表中重复的元素

    [0, 1, 2, 3, 4, 5, 5, 3, 1]

    方法一、

    >>> list1 = [1,2,3,4,5,5,3,1,0]

    >>> temp = list1[:]
    >>> list1.clear()
    >>> list1
    []
    >>> for each in temp:
        if each not in list1:
            list1.append(each) #append()表示向列表中添加元素

    方法二、

    >>> list1 = list(set(list1))
    >>> list1
    [0, 1, 2, 3, 4, 5]

    #set(list1)先将list1列表转变为集合, list(set(list1))再讲集合转变为列表

    如何访问集合中的值

    由于集合中的元素是无序的,所以并不能像序列那样用下标来进行访问,但是可以使用迭代把集合中的数据一个个读取出来

    可以使用for把集合中的数据一个个读取出来

    >>> set1 = {1,2,3,4,5,4,3,2,1,0}
    >>> for each in set1:
        print(each,end = ' ')

        
    0 1 2 3 4 5 

    •也可以通过innot in判断一个元素是否在集合中已经存在

    >>> 0 in set1
    True
    >>> 8 in set1
    False

    使用add()方法可以为集合添加元素,使用remove()方法可以删除集合中已知的元素:

    >>> set1.add(6)
    >>> set1
    {0, 1, 2, 3, 4, 5, 6}
    >>> set1.remove(5)
    >>> set1
    {0, 1, 2, 3, 4, 6}

    不可变集合(把元素给froze冰冻起来)(像元组一样不能随意地增加或删除集合中的元素)

    028 文件:因为懂你,所以永恒

    大多数u程序都是:首先接收输入数据,然后按照要求进行处理,最后输出数据

    虽然当前数据放在内存中存取的速度要比硬盘中快,但一旦断电则会丢失,所以尽量ctrl+s保持到硬盘中


    什么是文件

    打开文件

    open(file, mode='r', buffering=-1, encoding=None,errors=None, newline=None, closefd=True, opener=None)

    open()的第一个参数是传入的文件名,第二个参数是指定文件的打开模式

    文件对象方法

    >>> f = open("D:\\python3.3.2\Hello.txt")
    >>> f
    <_io.TextIOWrapper name='D:\\python3.3.2\\Hello.txt' mode='r' encoding='cp936'>
    >>> f.read()
    "A. HISTORY OF THE SOFTWARE\n==========================\n\nPython was created in the early 1990s by Guido van Rossum at Stichting\nMathematisch Centrum (CWI, see http://www.cwi.nl) in the Netherlands\nas a successor of a language called ABC.  Guido remains Python's\nprincipal author, although it includes many contributions from others.\n\nIn 1995, Guido continued his work on Python at the Corporation for\nNational Research Initiatives (CNRI, see http://www.cnri.reston.va.us)\nin Reston, Virginia where he released several versions of the\nsoftware."
    >>> f.close()
    >>> f = open("D:\\python3.3.2\Hello.txt")
    >>> f.read(5)
    'A. HI'
    >>> f.tell()   #返回当前光标所在文件的位置
    5
    >>> f.readline()
    'STORY OF THE SOFTWARE\n'
    将f放入到列表

    >>> f = open("D:\\python3.3.2\Hello.txt",'w')#w模式写入会覆盖已存在的文件(即原文件内容全部被删除),a模式则在末尾追加写入
    >>> f.write('who are you')          #返回的是写入的字符数
    11
    >>> f.close()

    029 文件:一个任务

    任务:将文件(record.txt)中的数据进行分割并按照以下规律保存起来:

    小甲鱼的对话单独保存为boy_*.txt的文件(去掉“小甲鱼:”)

    小客服的对话单独保存为girl_*.txt的文件(去掉“小客服:”)

    文件中总共有三段对话,分别保存为boy_1.txt, girl_1.txtboy_2.txt, girl_2.txt, boy_3.txt, gril_3.txt6个文件(提示:文件中不同的对话间已经使用“==========分割

    test1:

    f = open("record.txt")

    boy = []
    girl = []
    count = 1

    for each_line in f:
        if each_line[:6] != '======':#判断是否连续读到六个=
            (role,line_spoken) = each_line.split(':',1)#split以:进行字符切割,
            #将切得到的两部分内容依次存放在role与line_spoken中
            if role == '小甲鱼':
                boy.append(line_spoken)#将小甲鱼说的内容添加到列表boy中
            if role == '小客服':
                girl.append(line_spoken)#将小客服说的内容添加到列表girl中
        else:
            file_name_boy = 'boy_' + str(count) + '.txt'
            file_name_girl = 'girl_' + str(count) + '.txt'

            boy_file = open(file_name_boy,'w')#以w模式新建一个以file_name_boy命名的txt文件
            girl_file = open(file_name_girl,'w')#并贴上boy_file的标签

            boy_file.writelines(boy)#将列表boy中的内容写入到boy_file文件中
            girl_file.writelines(girl)

            boy_file.close()#关闭boy_file文件
            girl_file.close()

            boy = []#清空列表boy
            girl = []
            count += 1

    file_name_boy = 'boy_' + str(count) + '.txt'
    file_name_girl = 'girl_' + str(count) + '.txt'

    boy_file = open(file_name_boy,'w')
    girl_file = open(file_name_girl,'w')

    boy_file.writelines(boy)
    girl_file.writelines(girl)

    boy_file.close()
    girl_file.close()#记得关闭文件

    test2:

     

    def save_file(boy,girl,count):
        file_name_boy = 'boy_' + str(count) + '.txt'
        file_name_girl = 'girl_' + str(count) + '.txt'

        boy_file = open(file_name_boy,'w')
        girl_file = open(file_name_girl,'w')

        boy_file.writelines(boy)
        girl_file.writelines(girl)

        boy_file.close()
        girl_file.close()

    def split_file(file_name):
        f = open(file_name)

        boy = []
        girl = []
        count = 1

        for each_line in f:
            if each_line[:6] != '======':
                (role,line_spoken) = each_line.split(':',1)#split以:进行字符切割,
                #将切得到的两部分内容依次存放在role与line_spoken中
                if role == '小甲鱼':
                    boy.append(line_spoken)
                if role == '小客服':
                    girl.append(line_spoken)
            else:
                save_file(boy,girl,count)

                boy = []
                girl = []
                count += 1


        save_file(boy,girl,count)
        f.close()

    split_file('record.txt')

    030 文件系统:介绍一个高大上的东西

    os模块中关于文件/目录常用的函数使用方法

    >>> import os
    >>> os.getcwd()
    'D:\\python3.3.2\\小甲鱼python\\python程序\\第二十九课'

    >>> os.listdir('D:\\python3.3.2\\小甲鱼python\\python程序\\第二十九课')
    ['boy_1.txt', 'boy_2.txt', 'boy_3.txt', 'girl_1.txt', 'girl_2.txt', 'girl_3.txt', 'record.txt', 'test.py', 'test2.py']

    os.path模块中关于路径常用的函数使用方法

     >>> os.path.getsize('python.exe')  #获取文件的尺寸,返回值以字节为单位


    031 永久存储:腌制一缸美味的泡菜(pickle)

    python提供了一个标准的模块pickle可以非常容易地将列表、字典这类复杂的数据类型存储为文件。它几乎可以把所有python的对象都转化为二进制的形式存放,这个过程称为pickling,从二进制转换回对象的过程称为unpickling

    pickling过程

    >>> import pickle
    >>> my_list = [123,3,14,'小甲鱼',['another list']]

    >>> pickle_file = open('D:\\python3.3.2\小甲鱼python\python程序\第三十节课\my_list.pkl','wb')  #二进制写形式打开文件
    >>> pickle.dump(my_list,pickle_file)
    >>> pickle_file.close()

    unpickling过程       

    >>> import pickle
    >>> pickle_file = open('D:\\python3.3.2\小甲鱼python\python程序\第三十节课\my_list.pkl','rb')#以二进制读形式打开文件
    >>> my_list = pickle.load(pickle_file)
    >>> print(my_list)
    [123, 3, 14, '小甲鱼', ['another list']]

    实例:城市天气打包

    >>> pickle_file = open('D:\\python3.3.2\小甲鱼python\python程序\第三十一节课\city_data.pkl','wb')
    >>> pickle.dump(city,pickle_file)
    >>> pickle_file.close()

    032 异常处理:你不可能总是对的

    实例1:

    file_name = input('请输入需要打开的文件名:')
    file = open(file_name)
    print('文件的内容是:')
    for each_line in file:
        print(each_line)
    file.close()

    注:py文件与要打开的文件在同一个文件下则不需要加路径

    Python标准异常总结

    以下是 Python 内置异常类的层次结构:

            

    033 异常处理:你不可能总是对的2

    try-except语句

    try:

      检测范围

    except Exception[as reason]:

      出现异常(Exception)后的处理代码

    实例1:

    try:
        f = open('TE.txt')
        print(f.read())
        f.close()
    except OSError:
        print('文件打开过程中出错了!!!')

    实例2:

    try:
        f = open('TE.txt')
        print(f.read())
        f.close()
    except OSError as reason:
        print('文件打开出错原因是:\n' + str(reason))

    实例3:

    try:
        sum = 1 + '1'
        f = open('TE.txt')
        print(f.read())
        f.close()
    except OSError as reason:
        print('文件打开出错原因是:\n' + str(reason))
    except TypeError as reason:
        print('类型出错原因是:\n' + str(reason))

    实例4(多个异常统一处理):

    try:
        sum = 1 + '1'
        f = open('TE.txt')
        print(f.read())
        f.close()
    except(OSError, TypeError):
        print('出错了')

    注:try语句一旦检测到异常,剩下的语句将不会被执行

    try-finally语句

    try:

      检测范围

    except Exception[as reason]:

      出现异常(Exception)后的处理代码

    finally:

      无论如何都会被执行的代码

    实例5:

    try:
        f = open('test.txt')
        print(f.read())
        sum = 1 + '1'
    except (OSError,TypeError)as reason:
        print('出错了\n原因是:' + str(reason))
    finally:
        f.close()

    raise语句可以自己抛出一个异常

    034 丰富的else语句及简洁的with语句

    丰富的else语句

    要么怎样,要么不怎样

    if 条件:
        条件为真执行
    else:
        条件为假执行
          

    干完了能怎样,干不完就别想怎样

    实例1:

    def showMaxFactor(num):
        count = num // 2#//为整除,判断是素数,只需依次判断当前数num除以1到(num // 2)都不能整除即可
        while count > 1:
            if num % count == 0:#判断是否整除
                print('%d最大的约数是%d' % (num, count))
                break#跳出循环后else并不执行
            count -= 1
        else:#当while循环不成立时,或者理解为while循环完全被执行完了,没有给中途跳出(即break)
            print('%d是素数!' % num)

    num = int(input('请输入一个数:'))
    showMaxFactor(num)

    注:else与for语句搭配与while语句相同

    没有问题?那就干

    只要try语句块里没有出现任何异常,那么就会执行else语句块里的内容啦

    实例2:

    try:#尝试运行以下程序
        print(int('abc'))
    except ValueError as reason:#如果程序有异常时
        print('出错了:' + str(reason))
    else:#程序无异常时
        print('没有任何异常!')

    实例3:

    try:
        print(int('123'))
    except ValueError as reason:
        print('出错了:' + str(reason))
    else:
        print('没有任何异常!')

    简洁的with语句(with会自动帮你关闭文件)

    实例4:

    try:
        with open('test.txt','w') as f:
            for each_line in f:
                print(each_line)
    except (OSError,TypeError) as reason:
        print('出错了\n原因是:' + str(reason))

    035 图形用户界面入门:EasyGui

    图形用户界面编程,也就是平时常说的GUI(Graphical User  Interface),python有一个非常简单的GUI工具包:EasyGui

    GUI的安装

    导入方法一:

    >>> import easygui         #导入EasyGui
    >>> easygui.msgbox('嗨,亦我飞也')

    导入方法二:

    >>> from easygui import *
    >>> msgbox('嗨,亦我飞也')

    导入方法三(推荐使用):

    >>> import easygui as g
    >>> g.msgbox('嗨,亦我飞也')

    显示图片(注:图片需要为GIF格式,且存放在python.exe通目录

    >>> easygui.buttonbox(msg='你喜欢以下哪种水果',title='亦我飞也',choices=('草莓','西瓜','芒果'),image='aa.gif')

    实例1:

    import easygui as g
    import sys
     
    while 1:
        g.msgbox("嗨,欢迎进入第一个界面小游戏")
        msg = "请问你希望在鱼C工作室学习到什么知识呢"
        title="小游戏互动"
        choices=["谈恋爱","编程","OOXX","琴棋书画"]
        choice=g.choicebox(msg,title,choices)
     
        #note that we convert choice to string,in case
        #the user cancelled the choice,and we got None
        g.msgbox("你的选择是:"+str(choice),"结果")
        msg="你希望重新开始小游戏吗?"
        title=" 请选择"
        if g.ccbox(msg,title):  #show a Contiue/Cancel dialog
            pass #user chose Contonue
        else:
            sys.exit(0)  #user chose Cancel

    修改窗口大小(choicebox)

    修改文字大小(PROPORTIONAL_FONT)

    036 类和对象:给大家介绍对象

    给大家介绍对象

    把乱七八糟的数据扔进列表里,称数据层面的封装

    把常用的代码段打包成一个函数,称语句层面的封装

    把数据和代码都封装在一起,称对象层面的封装

    对象 = 属性 + 方法

    对象可以从静态(属性)动态(方法)两个特征来描述

    OO(面向对象)的特征

    继承

    class Turtle: # Python 中的类名约定以大写字母开头
        """关于类的一个简单例子"""
        # 属性
        color = 'green'
        weight = 10
        legs = 4
        shell = True
        mouth = '大嘴'

        # 方法
        def climb(self):
            print("我正在很努力的向前爬......")

        def run(self):
            print("我正在飞快的向前跑......")

        def bite(self):
            print("咬死你咬死你!!")

        def eat(self):
            print("有得吃,真满足^_^")

        def sleep(self):
            print("困了,睡了,晚安,Zzzz")

    调用类中的方法:

    >>> tt = Turtle()     #声明tt对象继承Turtle()
    >>> tt.climb()
    我正在很努力的向前爬......
    >>> tt.bite()
    咬死你咬死你!!

    定义一个带列表类MyList,将list2对象继承于它,则列表的功能继承它的对象都可以使用

    >>> class MyList(list):
        pass

    >>> list2 = MyList()

    >>> list2.append(5)
    >>> list2.append(6)

    >>> list2.append(1)
    >>> list2
    [5, 6, 1]
    >>> list2.sort()
    >>> list2
    [1, 5, 6]

    多态(下例中都调用的名字相同的方法,但实现不一样)

    >>> class A:
        def fun(self):
            print('我是小A。。。')

            
    >>> class B:
        def fun(self):
            print('我是小B。。。')

            
    >>> a = A()
    >>> b = B()
    >>> a.fun()
    我是小A。。。
    >>> b.fun()
    我是小B。。。

    037 类和对象:面向对象编程

    self是什么?

    Python的self其实就相当于C++的this指针。由同一个类可以生产无数对象,当一个对象的方法被调用的时候,对象会将自身的引用作为第一个参数传给该方法,那么python就知道需要操作哪个对象的方法了。

    >>> class Ball:
        def setName(self,name):
            self.name = name
        def kick(self):
            print('我叫%s,该死的,谁踢我。。。' % self.name)

            
    >>> a = Ball()

    >>> a.setName('球A')
    >>> b = Ball()

    >>> b.setName('球B')

    >>> a.kick()
    我叫球A,该死的,谁踢我。。。
    >>> b.kick()
    我叫球B,该死的,谁踢我。。。

    你听说过Python的魔法方法吗?

    python的这些具有魔法的方法,总是被双下划线所包围,例如__init__(),即构造方法,也称构造函数,这个方法会在对象被创建时自动调用。其实,实例化对象时是可以传入参数的,这些参数会自动传入__init__()方法中,可以通过重写这个方法来自定义对象的初始化操作

    实例:

    >>> class Ball():
        def __init__(self,name):
            self.name = name
        def kick(self):
            print('我叫%s,该死的,谁踢我。。。' % self.name)

            
    >>> b = Ball('小土豆')
    >>> b.kick()
    我叫小土豆,该死的,谁踢我。。。

    公有和私有?python内部采用了一种叫 name mangling(名字改编)的技术

    默认上对象的属性和方法都是公开的,可以直接通过点操作符(.)进行访问:

    >>> class Person:
        name = '亦我飞也'

        
    >>> p = Person()
    >>> p.name
    '亦我飞也'

    为了实现定义私有变量,只需要在变量名或函数名前加上"__"两个下划线,那么这个函数或变量就会变成私有的了:

    私有变量不可以直接由外部访问

    >>> class Person:
        __name = '亦我飞也'

        
    >>> p = Person()
    >>> p.__name
    Traceback (most recent call last):
      File "<pyshell#65>", line 1, in <module>
        p.__name
    AttributeError: 'Person' object has no attribute '__name'

    室友变量可以由内部(内部函数)进行访问

    >>> class Person:
        __name = '亦我飞也'
        def getName(self):
            return self.__name

        
    >>> p = Person()
    >>> p.__name
    Traceback (most recent call last):
      File "<pyshell#72>", line 1, in <module>
        p.__name
    AttributeError: 'Person' object has no attribute '__name'

    >>> p.getName()
    '亦我飞也'

    其实,name mangling(名字改编)技术,只是把双下划线开头的变量进行了改名而已。实际上在外部使用“_类名__变量名“即可访问双下划线开头的私有变量了

    >>> p._Person__name
    '亦我飞也'

    038 类和对象:继承

    继承

                      子类                              父类

    class DerivedClassName(BaseClassName):

    ……

    实例:一个子类可以继承它的父类的所有属性和方法

    >>> class Parent:
        def hello(self):
            print('正在调用父类的方法。。。')

            

    >>> class Child(Parent):    #子类继承父类
        pass     #直接往下执行

    >>> p = Parent()
    >>> p.hello()
    正在调用父类的方法。。。
    >>> c = Child()
    >>> c.hello()
    正在调用父类的方法。。。

    如果子类中定义与父类同名的方法或属性,则会自动覆盖父类对应的方法和属性(即子类方法属性改变,父类是不变的)

    >>> class Child(Parent):
        def hello(self):
            print('正在调用子类的方法')

            
    >>> c = Child()
    >>> c.hello()
    正在调用子类的方法
    >>> p.hello()
    正在调用父类的方法。。。

    实例2:

    import random as r
    class Fish:
        def __init__(self):
            self.x = r.randint(0,10)
            self.y = r.randint(0,10)

        def move(self):
            self.x -= 1
            print('我的位置是:',self.x,self.y)


    class Goldfish(Fish):
        pass

    class Garp(Fish):
        pass

    class Shark(Fish):
        def __init__(self):
            self.hungry = True

        def eat(self):
            if self.hungry:
                print('吃货的梦想就是天天有的吃')
                self.hungry = False
            else:
                print('太撑了,吃不下了!')

    >>> fish = Fish()
    >>> fish.move()
    我的位置是: -1 10
    >>> fish.move()
    我的位置是: -2 10
    >>> goldfish = Goldfish()
    >>> goldfish.move()
    我的位置是: 2 3
    >>> goldfish.move()
    我的位置是: 1 3
    >>> shark = Shark()
    >>> shark.eat()
    吃货的梦想就是天天有的吃
    >>> shark.eat()
    太撑了,吃不下了!
    >>> shark.move()    #报错原因时因为子类重写构造函数,覆盖了父类D的构造函数
    Traceback (most recent call last):
      File "<pyshell#9>", line 1, in <module>
        shark.move()
      File "D:\python3.3.2\小甲鱼python\python程序\第三十八节课\fish.py", line 8, in move
        self.x -= 1
    AttributeError: 'Shark' object has no attribute 'x'

    注:继承父类属性的子类,其变量值只属于当前子类,是子类的局部变量

    报错修改部分解决方法一:调用未绑定的父类方法

    >>> shark = Shark()
    >>> shark.move()
    我的位置是: 2 1
    >>> shark.move()
    我的位置是: 1 1

    报错修改部分解决方法二:使用super函数super函数会帮我们自动找到基类的方法,而且还自动为我们传入self参数

    >>> shark = Shark()
    >>> shark.move()
    我的位置是: 1 1
    >>> shark.move()
    我的位置是: 0 1

    多重继承

    class DerivedClassName(Base1, Base2, Base3):

    ……

    实例:子类c同时继承基类Base1和基类Base2

    >>> class Base1:
        def fool1(self):
            print('我是fool1,我为Base1代言。。。')

            
    >>> class Base2:
        def fool2(self):
            print('我是fool2,我为Base2代言。。。')

            
    >>> class C(Base1,Base2):
        pass

    >>> c = C()
    >>> c.fool1()
    我是fool1,我为Base1代言。。。
    >>> c.fool2()
    我是fool2,我为Base2代言。。。

    039 类和对象:拾遗

    组合(将需要的类一起进行实例化并放入新的类中)

    实例:

    class Turtle:
        def __init__(self,x):
            self.num = x

    class Fish:
        def __init__(self,x):
            self.num = x

    class Pool:
        def __init__(self,x,y):
            self.turtle = Turtle(x)
            self.fish = Fish(y)

        def print_num(self):
            print('水池里一共有乌龟 %d 条,鱼 %d 条' % (self.turtle.num,self.fish.num))

    >>> pool = Pool(5,2)
    >>> pool.print_num()
    水池里一共有乌龟 5 条,鱼 2 条

    现在要求定义一个类,叫水池,水池里要有乌龟和鱼。

    类、类对象和实例对象

    以下例子可见,对实例对象c的count属性赋值后,就相当于覆盖了类对象C的count属性。如果没有赋值覆盖,那么引用的是类对象的count属性

    >>> a = C()
    >>> b = C()
    >>> c = C()
    >>> print(a.count,b.count,c.count)
    0 0 0
    >>> c.count += 10
    >>> print(a.count,b.count,c.count)
    0 0 10
    >>> C.count += 100
    >>> print(a.count,b.count,c.count)
    100 100 10

    另外,如果属性的名字跟方法名相同,属性会覆盖方法:

    >>> class C:
        def x(self):
            print('X-man')

            
    >>> c = C()
    >>> c.x()
    X-man
    >>> c.x = 1              #新定义对象c的一个x属性,并赋值为1
    >>> c.x
    1
    >>> c.x()     #可见,方法x()已经被属性x给覆盖了
    Traceback (most recent call last):
      File "<pyshell#8>", line 1, in <module>
        c.x()
    TypeError: 'int' object is not callable

    结论:不要试图在一个类里边定义出所有能想到的特性和方法,应该利用继承和组合机制来进行扩展;用不同的词性命名,如属性名用名词、方法名用动词,并使用骆驼命名法等。

    到底什么是绑定?

    实例1:(python严格要求需要有实例才能被调用,即绑定概念)

    >>> class BB:
        def printBB():        #缺少self,导致无法绑定具体对象
            print('no zuo no die')

            
    >>> BB.printBB()
    no zuo no die
    >>> bb = BB()
    >>> bb.printBB()        #出现错误原因是由于绑定机制,自动把bb对象作为第一个参数传入
    Traceback (most recent call last):
      File "<pyshell#15>", line 1, in <module>
        bb.printBB()
    TypeError: printBB() takes 0 positional arguments but 1 was given

     

    Python严格要求方法需要有实例才能被调用,这种限制其实就是Python所谓的绑定概念。

    040 类和对象:一些相关的BIF

    一些相关的BIF

    issubclass(class, classinfo)  如果第一个参数(class)是第二个参数(classinfo)的一个子类,则返回True,否则返回False

    >>> class A:
        pass

    >>> class B(A):
        pass

    >>> issubclass(B,A)
    True
    >>> issubclass(B,B)   #一个类被认为是其自身的子类
    True
    >>> issubclass(B,object)      # object是所有类的基类
    True
    >>> class C:
        pass

    >>> issubclass(B,C)
    False

    isinstance(object, classinfo)  如果第一个参数(object)是第二个参数(classinfo)的实例对象,则返回True,否则返回False

    >>> issubclass(B,C)       注:第一个参数如果不是对象,则永远返回False
    False
    >>> b1 = B()
    >>> isinstance(b1,B)
    True
    >>> isinstance(b1,C)
    False
    >>> isinstance(b1,A)
    True
    >>> isinstance(b1,(A,B,C))
    True

    hasattr(object, name)  用来测试一个对象里是否有指定的属性,第一个参数(object)是对象,第二个参数(name)是属性名(属性的字符串名字)

    >>> class C:
        def __init__(self,x=0):
            self.x = x

            
    >>> c1 = C()
    >>> hasattr(c1,'x')    
    #注意,属性名要用引号括起来
    True

     

    getattr(object, name[, default])  返回对象指定的属性值,如果指定的属性不存在,则返回default(可选参数);若没有设置default参数,则抛出异常

    >>> getattr(c1,'x')
    0
    >>> getattr(c1,'y')

    Traceback (most recent call last):
      File "<pyshell#25>", line 1, in <module>
        getattr(c1,'y')
    AttributeError: 'C' object has no attribute 'y'

    setattr(object, name, value)  可以设置对象中指定属性的值,如果指定的属性不存在,则会新建属性并赋值
    >>> setattr(c1,'y','FishC')
    >>> getattr(c1,'y')
    'FishC'

    delattr(object, name)  用于删除对象中指定的属性,如果属性不存在,抛出异常。

    >>> delattr(c1,'y')
    >>> delattr(c1,'Z')

    Traceback (most recent call last):
      File "<pyshell#30>", line 1, in <module>
        delattr(c1,'Z')
    AttributeError: Z

    property(fget=None, fset=None, fdel=None, doc=None)  用来通过属性设置属性,第一个参数是获取属性的方法名,第二个参数是设置属性的方法名,第三个参数是删除属性的方法名

    >>> class C:
        def __init__(self,size =10):
            self.size = size
        def getSize(self):
            return self.size
        def setSize(self,value):
            self.size = value
        def delSize(self):
            del self.size
        x=property(getSize,setSize,delSize)

        

    >>> c = C()
    >>> c.x         #调用getSize()
    10
    >>> c.x = 12      #调用SetSize()
    >>> c.x
    12
    >>> c.size
    12
    >>> del c.x      #调用DelSize()
    >>> c.size
    Traceback (most recent call last):
      File "<pyshell#53>", line 1, in <module>
        c.size
    AttributeError: 'C' object has no attribute 'size'

    041 魔法方法:构造和析构

    __init__(self[, ...]) 方法是类在实例化成对象的时候首先会调用的一个方法

    >>> class Rectangle:
        def __init__(self,x,y):
            self.x = x
            self.y = y
        def getPeri(self):
            return (self.x + self.y) * 2
        def getArea(self):
            return self.x * self.y

    >>> rect = Rectangle(5,2)
    >>> rect.getPeri()
    14
    >>> rect.getArea()
    10

       注:__init__()方法的返回值一定是None 

    其实,__new__()才是在一个对象实例化时候所调用的第一个方法,它的第一个参数是这个类(cla),而其他的参数会直接传递给__init__()方法

    __new__(cls[, ...])

    >>> class CapStr(str):
        def __new__(cls,string):
            string = string.upper()
            return str.__new__(cls,string)

        
    >>> a = CapStr('hello world')
    >>> a
    'HELLO WORLD

    __del__(self)  当对象将要被销毁的时候,这个方法就会被调用。但要注意,并非del x就相当于调用x.__del__(),__del__()方法是当垃圾回收机制回收这个对象的时候才调用的。

    >>> class C:
        def __init__(self):
            print('我是__init__方法,我被调用了...')
        def __del__(self):
            print('我是__del__方法,我被调用l...')

            
    >>> c1 = C()     #创建对象c1
    我是__init__方法,我被调用了...
    >>> c2 = c1
    >>> c3 = c2
    >>> del c1
    >>> del c2
    >>> del c3   #删除c3时,对象c1才会彻底被删除(即没有标签指向对象c1时,其才会被回收)
    我是__del__方法,我被调用l...

    042 魔法方法:算术运算

    python2.2以后,对类和类型进行了统一,做法就是讲int()、float()、str()、list()、tuple()这些BIF转换为工厂函数(类对象):

    >>> type(len)
    <class 'builtin_function_or_method'>            #普通的BIF
    >>> type(int)
    <class 'type'>             #工厂函数(类对象),当调用它们的时候,其实就是创建了一个相应的实例对象
    >>> type(dir)
    <class 'builtin_function_or_method'>
    >>> type(list)
    <class 'type'>

    >>> a = int('123')        #创建一个相应的实例对象a
    >>> b = int('345')
    >>> a + b              #python在两个对象进行相加操作
    468

    举个例子,下面定义一个比较特立独行的类:

    >>> class New_int(int):
        def __add__(self,other):
            return int.__sub__(self,other)
        def __sub__(self,other):
            return int.__add__(self,other)

        
    >>> a = New_int(3)
    >>> b = New_int(5)
    >>> a + b    #两个对象相加,触发 __add__(self,other)方法
    -2
    >>> a - b
    8
    >>>

    实例2:

    >>> class New_int(int):
        def __add__(self,other):
            return (int(self) + int(other))       #将self与other强制转换为整型,所以不会出现两个对象相加触发__add__()方法
        def __sub__(self,other):
            return (int(self) - int(other))

        
    >>> a = New_int(3)
    >>> b = New_int(5)
    >>> a + b
    8

    043 魔法方法:算术运算2

    实例1:

    >>> class int(int):
        def __add__(self,other):
            return int.__sub__(self,other)

        
    >>> a = int(3)
    >>> b = int(2)
    >>> a + b
    1

    反运算:

    反运算与算术运算符的不同之处是,反运算多了一个'r',例如 __add__()的反运算对应为 __radd__()

    >>> a + b

    这里a是加数,b是被加数,如果a对象的__add__()方法没有实现或者不支持相应的操作,那么python就会自动调用b的__radd__()方法

    实例:

    >>> class Nint(int):
        def __radd__(self,other):
            return int.__sub__(self,other)

        
    >>> a = Nint(5)
    >>> b = Nint(3)
    >>> a + b      #由于a对象默认有__add__()方法,所以b的__radd__()没有执行
    8

    实例2:

    >>> class Nint(int):
        def __radd__(self,other):
            return int.__sub__(self,other)

        
    >>> b = Nint(5)
    >>> 3 + b         #由于3无__add__()方法,所以执行b的反运算__radd__(self,other)方法,其中self是b对象
    2

    注:在重写反运算魔法方法时,一定要注意顺序问题。

    增量赋值运算:

    比较操作符:

    其它操作符:

    044 魔法方法:简单定制

    简单定制

    基本要求:

    定制一个计时器的类

    startstop方法代表启动计时和停止计时

    假设计时器对象t1print(t1)和直接调用t1均显示结果

    当计时器未启动或已经停止计时,调用stop方法会给予温馨的提示

    两个计时器对象可以进行相加:t1 + t2

    只能使用提供的有限资源完成

    你需要这些资源

    使用time模块的localtime方法获取时间

    扩展阅读:time 模块详解(时间获取和转换)

    有关time模块的localtime方法获取时间(参考:

    https://fishc.com.cn/forum.php?mod=viewthread&tid=51326&extra=page%3D1%26filter%3Dtypeid%26typeid%3D403

    time.localtime返回struct_time的时间格式

    表现你的类:__str__ __repr__

    实例:

    import time as t   #导入时间模块,调用对象t

    class Mytimer():
        def __init__(self):
            self.unit = ['年','月','天','小时','分钟','秒']
            self.prompt = "未开始计时"
            self.lasted = []
            self.begin = 0  #属性
            self.end = 0
        def __str__(self):
            return self.prompt

        __repr__ = __str__

        def __add__(self,other):   #重写加法操作符,运行时间相加
            prompt = "总共运行了"
            result = []
            for index in range(6):
                result.append(self.lasted[index] + other.lasted[index])
                if result[index]:
                    prompt += (str(result[index]) + self.unit[index])
            return prompt
                               
        #开始计时
        def start(self):    #方法,属性名和方法名不能相同
            if not self.stop:
                self.prompt = ("提示:请先调用stop()停止计时!")
            else:
                self.begin = t.localtime()
                print('计时开始...')

        #停止计时
        def stop(self):
            if not self.begin:
                print('提示:请先调用start()进行计时!')
            else:
                self.end = t.localtime()
                self._calc()
                print('计时结束!')

        #内部方法,计算运行时间
        def _calc(self):
            self.prompt = "总共运行了"
            for index in range(6):
                self.lasted.append(self.end[index] - self.begin[index])
                if self.lasted[index]:
                    self.prompt += (str(self.lasted[index]) + self.unit[index])
            #为下一轮计时初始化变量
            self.begin = 0
            self.end = 0

    >>> t1 = Mytimer()
    >>> t1.stop()
    提示:请先调用start()进行计时!
    >>> t1.start()
    计时开始...
    >>> t1.stop()
    计时结束!
    >>> t1
    总共运行了4秒
    >>> t2 = Mytimer()
    >>> t2.start()
    计时开始...
    >>> t2.stop()
    计时结束!
    >>> t2
    总共运行了4秒
    >>> t1 + t2
    '总共运行了8秒'        

    进阶定制

    如果开始计时的时间是202222216:30:30,停止时间是202512315:30:30,那按照我们用停止时间减开始时间的计算方式就会出现负数3-11-1小时)你应该对此做一些转换

    现在的计算机速度都非常快,而我们这个程序最小的计算单位却只是秒,精度是远远不够的

    045 魔法方法:属性访问

    属性访问

    __getattr__(self, name)

    定义当用户试图获取一个不存在的属性时的行为

    __getattribute__(self, name)

    定义当该类的属性被访问时的行为

    __setattr__(self, name, value)

    定义当一个属性被设置时的行为

    __delattr__(self, name)

    定义当一个属性被删除时的行为

    实例1:

    class C:
        def __getattribute__(self, name):
            print('getattribute')
            # 使用 super() 调用 object 基类的 __getattribute__ 方法
            return super().__getattribute__(name)

        def __setattr__(self, name, value):
            print('setattr')
            super().__setattr__(name, value)

        def __delattr__(self, name):
            print('delattr')
            super().__delattr__(name)

        def __getattr__(self, name):
            print('getattr')

    >>> c = C()
    >>> c.x
    getattribute
    getattr
    >>> c.x = 1
    setattr
    >>> c.x
    getattribute
    1
    >>> del c.x
    delattr
    >>> setattr(c,'y','Yellow')
    setattr

    练习要求

    写一个矩形类,默认宽和高两个属性

    如果为一个叫square的属性赋值,那么说明这是一个正方形,值就是正方形的边长,此时宽和高都应该等于边长。

    实例2:

    class Rectangle:
        def __init__(self, width=0, height=0):
            self.width = width
            self.height = height

        def __setattr__(self, name, value):#一发生赋值操作,则会触发__setattr__()魔法方法
            if name == 'square':#判断name属性是否为正方形
                self.width = value
                self.height = value
            else:
                self.__dict__[name] = value

        def getArea(self):
            return self.width * self.height

    >>> r1 = Rectangle(4,5)
    >>> r1.getArea()
    20
    >>> r1.square = 10
    >>> r1.getArea()
    100

    046 魔法方法:描述符(Property的原理)

    描述符

    描述符就是将某种特殊类型的类的实例指派给另一个类的属性。

    __get__(self, instance, owner)

    用于访问属性,它返回属性的值

    __set__(self, instance, value)

    将在属性分配操作中调用,不返回任何内容

    __delete__(self, instance)

    控制删除操作,不返回任何内容

    实例:

    >>> class MyDecriptor:
        def __get__(self,instance,owner):
            print("getting...",self,instance,owner)
        def __set__(self,instance,value):
            print("setting...",self,instance,value)
        def __delete__(self,instance):
            print("deleting...",self,instance)

     

    >>> class Test:
        x = MyDecriptor()   #取Mydecriptor类的实例指派给Test类的属性x

    >>> test = Test()
    >>> test.x
    getting... <__main__.MyDecriptor object at 0x00000000033467F0> <__main__.Test object at 0x000000000335EF98> <class '__main__.Test'>
    >>> test
    <__main__.Test object at 0x000000000335EF98>
    >>> test.x = "X-man"
    setting... <__main__.MyDecriptor object at 0x00000000033467F0> <__main__.Test object at 0x000000000335EF98> X-man
    >>> del test.x
    deleting... <__main__.MyDecriptor object at 0x00000000033467F0> <__main__.Test object at 0x000000000335EF98>

     

    实例2:

    >>> class MyProperty:
        def __init__(self,fget = None,fset = None,fdel = None):
            self.fget = fget
            self.fset = fset
            self.fdel = fdel
        def __get__(self,instance,owner):
            return self.fget(instance)
        def __set__(self,instance,value):
            self.fset(instance,value)
        def __delete__(self,instance):
            self.fdel(instance)

            
    >>> class C:
        def __init__(self):
            self._x = None
        def getX(self):
            return self._x
        def setX(self,value):
            self._x = value
        def delX(self):
            del self._x
        x = MyProperty(getX,setX,delX)

        
    >>> c = C()
    >>> c.x = "HELLOW"
    >>> c.x
    'HELLOW'
    >>> c._x
    'HELLOW'
    >>> del c.x
    >>> c._x
    Traceback (most recent call last):
      File "<pyshell#70>", line 1, in <module>
        c._x
    AttributeError: 'C' object has no attribute '_x'

    练习要求

    先定义一个温度类,然后定义两个描述符类用于描述摄氏度和华氏度两个属性

    要求个属性会自动进行转换,也就是说你可以给摄氏度这个属性赋值,然后打印的华氏度属性是自动转换后的结果。

    实例3:

    ss Celsius:  #摄氏度描述符类
        def __init__(self,value = 26.0):#self为描述符类自身(此为摄氏度描述符类)的实例(此为cel)
            self.value = float(value)
        def __get__(self,instance,owner):#instance是这个描述符的拥有者所在的类的实例(此为temp)
            return self.value
        def __set__(self,instance,value):#owner是这个描述符的拥有者所在的类本身(此为温度类)
            self.value = float(value)

    class Fahrenheit:   #华氏度描述符类
        def __get__(self,instance,owner):
            return instance.cel * 1.8 +32  #摄氏度转华氏度
        def __set__(self,instance,value):
            instance.cel = ((float)(value)- 32)/ 1.8   #华氏度转摄氏度
            
    class Temperature:   #温度类
        cel = Celsius()   #设置摄氏度属性(描述符类的实例指派给了温度类的属性)
        fah = Fahrenheit()#设置华氏度属性

    >>> temp = Temperature()
    >>> temp.cel
    26.0
    >>> temp.fah
    78.80000000000001
    >>> temp.fah = 78.8
    >>> temp.cel
    25.999999999999996

    047 魔法方法:定制序列

    协议是什么?

    协议(Protocols)与其他编程语言中的接口很相似,它规定你哪些方法必须要定义。然而,在Python中的协议就显得不那么正式。事实上,在Python中,协议更像是一种指南

    容器类型的协议

    如果说你希望定制的容器是不可变的话,你只需要定义__len__()__getitem__()方法。

    如果你希望定制的容器是可变的话,除了__len__()__getitem__()方法,你还需要定义__setitem__()__delitem__()两个方法。

    练习要求

    编写一个不可改变的自定义列表,要求记录列表中每个元素被访问的次数。

    class CountList:  #定义记录列表中每个元素访问次数类
        def __init__(self,*args): #参数是可变类型的
            self.values = [x for x in args]#将args的数据存入列表self.values中
            self.count = {}.fromkeys(range(len(self.values)),0)#创建字典,初试化为0

        def __len__(self):  #返回容器中元素的个数
            return len(self.values)#len方法用于返回参数的长度 
        def __getitem__(self,key):  #获取容器中指定元素的行为,key为访问对应的键
            self.count[key] += 1#每访问一次,字典键对应的键值加1
            return self.values[key]

    >>> c1 = CountList(1,3,5,7,9)
    >>> c2 = CountList(2,4,6,8,10)
    >>> c1[1]  #c1[1]第一次访问
    3
    >>> c2[2]
    6
    >>> c1[1] + c2[2] #c1[1]第二次访问
    9
    >>> c1.count
    {0: 0, 1: 2, 2: 0, 3: 0, 4: 0}
    >>> c2.count
    {0: 0, 1: 0, 2: 2, 3: 0, 4: 0}

    048 魔法方法:迭代器

    迭代的意思类似于循环,每一次重复的过程被称为一次迭代的过程,而每一次迭代得到的结果会被用来作为下一次迭代的初始值。提供迭代方法的容器称为迭代器(如序列(列表、元组、字符串)、字典等)。

    对一个容器对象调用iter()就得到它的迭代器,调用next()迭代器就会返回下一个值。入托迭代器没有值可以返回了,就会抛出异常。

    •iter()

    –__iter__()

    •next()

    –__next__()

    实例1:

    >>> string = "FishC"
    >>> it = iter(string)
    >>> next(it)
    'F'
    >>> next(it)
    'i'
    >>> next(it)
    's'
    >>> next(it)
    'h'
    >>> next(it)
    'C'
    >>> next(it)
    Traceback (most recent call last):
      File "<pyshell#8>", line 1, in <module>
        next(it)
    StopIteration

    一个容器如果是迭代器,那就必须实现__iter__()魔法方法,这个方法实际上就是返回迭代器本身。重点要实现的是__next__()魔法方法,因为它决定了迭代的规则。

    实例2:

    >>> class Fibs:
        def __init__(self):
            self.a = 0
            self.b = 1
        def __iter__(self):
            return self
        def __next__(self):
            self.a,self.b = self.b,self.a + self.b
            return self.a

        
    >>> fibs = Fibs()
    >>> for each in fibs:
        if each < 20:
            print(each)
        else:
            break

        
    1
    1
    2
    3
    5
    8
    13

    实例3:

     

    >>> class Fibs:
        def __init__(self,n =20):
            self.a = 0
            self.b = 1
            self.n = n
        def __iter__(self):
            return self
        
        def __next__(self):
            self.a,self.b = self.b,self.a + self.b
            if self.a > self.n:
                raise StopIteration
            return self.a

        
    >>> fibs = Fibs()
    >>> for each in fibs:
        print(each)

        
    1
    1
    2
    3
    5
    8
    13

     

    >>> fibs = Fibs(10)
    >>> for each in fibs:
        print(each)

        
    1
    1
    2
    3
    5
    8

     

    049 乱入:生成器

    所谓协同程序,就是可以运行的独立函数调用,函数可以暂停或者挂起,并在需要的时候从程序离开的地方继续或者重新开始。

    生成器可以暂时挂起函数,并保留函数的局部变量等数据,然后在再次调用它的时候,从上次暂停的位置继续执行下去。

    一个函数中如果有yield语句,则被定义为生成器。

    实例1:

    >>> def myGen():
        print("生成器被执行了!")
        yield 1   #暂停一次,相当于return,返回1
        yield 2     #暂停一次,相当于return,返回2

        
    >>> myG = myGen()
    >>> next(myG)
    生成器被执行了!
    1
    >>> next(myG)
    2

    像前面介绍的斐波那契的例子,也可以用生成器来实现:

    >>> def fibs():
        a = 0
        b = 1
        while True:
            a,b = b,a + b
            yield a

            
    >>> for each in fibs():
        if each > 100:
            break
        print(each)

        
    1
    1
    2
    3
    5
    8
    13
    21
    34
    55
    89

    列表推导式表达:

    100以内,能被2整除,但不能被3整除的所有整数

    >>> a = [i for i in range(100) if not (i % 2) and (i % 3 )]
    >>> a
    [2, 4, 8, 10, 14, 16, 20, 22, 26, 28, 32, 34, 38, 40, 44, 46, 50, 52, 56, 58, 62, 64, 68, 70, 74, 76, 80, 82, 86, 88, 92, 94, 98]

    字典推导式:

    10以内是否为偶数

    >>> a = {i:i % 2 == 0 for i in range(10)}
    >>> a
    {0: True, 1: False, 2: True, 3: False, 4: True, 5: False, 6: True, 7: False, 8: True, 9: False}

    集合推导式:

    >>> a = {i for i in [1,2,3,3,4,5,5,5,6,7,7,8]}
    >>> a
    {1, 2, 3, 4, 5, 6, 7, 8}

    元组生成器推导式:

    >>> e = (i for i in range(5))
    >>> next(e)
    0
    >>> next(e)
    1
    >>> next(e)
    2

    050 模块:模块就是程序

    什么是模块

    容器 -> 数据封装

    函数 -> 语句封装

    -> 方法和属性的封装

    模块 -> 模块就是程序

    命名空间

    爱的宣言:世界上只有一个名字,使我这样牵肠挂肚,像有一根看不见的线,一头牢牢系在我心尖上,一头攥在你手中,这个名字就叫做鱼C工作室计算机一班的小花……

    导入模块

    第一种:import 模块名

    实例1:import导入模块

    实例2:import导入模块

    第二种:from 模块名 import 函数名(不推荐使用)

    第三种:import 模块名 as 名字(推荐使用)

    TemperatureConversion文件:

    def c2f(cal):
        return cal * 1.8 + 32
    def f2c(fah):
        return (fah - 32)/1.8

    calc文件:

    import TemperatureConversion as tc  #tc为取得新名字

    print("32摄氏度 = %.2f 华氏度\n" % tc.c2f(32))
    print("99华氏度 = %.2f 摄氏度" % tc.f2c(99))

    051 模块:__name__='__main__'、搜索路径和包

    模块!模块!

    实例1:为TemperatureConversion添加测试程序(TemperatureConversion被作为程序运行)

    def c2f(cal):
        return cal * 1.8 + 32

    def f2c(fah):
        return (fah - 32)/1.8

    def test():
        print("0摄氏度 = %.2f 华氏度\n" % c2f(0))
        print("0华氏度 = %.2f 摄氏度" % f2c(0))

    test()

    运行calc文

    当希望TemperatureConversion被调用时作为模块导入时

    def c2f(cal):
        return cal * 1.8 + 32

    def f2c(fah):
        return (fah - 32)/1.8

    def test():
        print("0摄氏度 = %.2f 华氏度" % c2f(0))
        print("0华氏度 = %.2f 摄氏度" % f2c(0))

    if __name__ == "__main__":#当此文件当做程序运行时,执行test(),否则不执行
        test()

    运行calc文件

    if __name__ == ‘__main__’

    搜索路径(系统会首先搜索的路径)

    >>> import sys
    >>> sys.path
    ['D:\\python3.3.2\\小甲鱼python\\python程序\\第五十节课\\Temperature', 'D:\\python3.3.2\\Lib\\idlelib', 'C:\\windows\\system32\\python33.zip', 'D:\\python3.3.2\\DLLs', 'D:\\python3.3.2\\lib', 'D:\\python3.3.2', 'D:\\python3.3.2\\lib\\site-packages']

    添加搜索路径:

    >>> import TemperatureConversion
    Traceback (most recent call last):
      File "<pyshell#0>", line 1, in <module>
        import TemperatureConversion
    ImportError: No module named 'TemperatureConversion'

    >>> import sys
    >>> sys.path.append("D:\\python3.3.2\WODE\Temperature")
    >>> sys.path
    ['', 'D:\\python3.3.2\\Lib\\idlelib', 'C:\\windows\\system32\\python33.zip', 'D:\\python3.3.2\\DLLs', 'D:\\python3.3.2\\lib', 'D:\\python3.3.2', 'D:\\python3.3.2\\lib\\site-packages', 'D:\\python3.3.2\\WODE\\Temperature']
    >>> import TemperatureConversion
    >>> TemperatureConversion.f2c(59)
    15.0

    package

    1.创建一个文件夹,用于存放相关的模块,文件夹的名字即包的名字;

    2.文件夹中创建一个__init__.py的模块文件,内容可以为空;

    3.相关的模块放入文件夹中

    052 模块:像个极客一样去思考

    使用print调用__doc__属性,可以带格式查看这个模块的简介

    使用dir()可以查询到该模块定义了哪些变量、函数和类

    053 论一只爬虫的自我修养

    Python如何访问互联网?

     

    URL的一般格式为(带方括号[]的为可选项)

    protocol :// hostname[:port] / path / [;parameters][?query]#fragment

    URL由三部分组成:

    第一部分是协议httphttpsftpfileed2k…

    第二部分是存放资源的服务器的域名系统或IP地址(有时候要包含端口号,各种传输协议都有默认的端口号,如http的默认端口为80)。

    第三部分是资源的具体地址,如目录文件名

    054 论一只爬虫的自我修养2:实战

    import urllib.request

    response = urllib.request.urlopen('http://placekitten.com/g/500/600')#  返回文件对象response
    cat_imag = response.read()

    with open('cat_500_600.jpg','wb') as f:
        f.write(cat_imag)

    >>> response.geturl()
    'http://placekitten.com/g/500/600'
    >>> response.info()
    <http.client.HTTPMessage object at 0x00000000034EAA20>
    >>> print(response.info())
    Date: Sat, 27 Jul 2019 02:44:18 GMT
    Content-Type: image/jpeg
    Transfer-Encoding: chunked
    Connection: close
    Set-Cookie: __cfduid=d3cd08233581619b9ef8464ae93f7d5ff1564195458; expires=Sun, 26-Jul-20 02:44:18 GMT; path=/; domain=.placekitten.com; HttpOnly
    Access-Control-Allow-Origin: *
    Cache-Control: public, max-age=86400
    Expires: Sun, 28 Jul 2019 02:44:18 GMT
    CF-Cache-Status: HIT
    Age: 66459
    Vary: Accept-Encoding
    Server: cloudflare
    CF-RAY: 4fcb454ecc35ce6b-LHR


    >>> response.getcode()
    200

    055 论一只爬虫的自我修养3:隐藏

    修改 headers

    通过Requestheaders参数修改

    通过Request.add_header()方法修改

    代理

    步骤:

    1. 参数是一个字典 {‘类型’:‘代理ip:端口号’}

    proxy_support = urllib.request.ProxyHandler({})

     

    2. 定制、创建一个 opener

    opener = urllib.request.build_opener(proxy_support)

     

    3a. 安装 opener

    urllib.request.install_opener(opener)

    3b. 调用 opener

    opener.open(url)

     

    064 GUI的终极选择:Tkinter

     

    >>> import tkinter   #Tkinter是python默认的GUI库,导入Tkinter模块
    >>> 

    实例1:

    import tkinter as tk

    root = tk.Tk()#创建一个主窗口,用于容纳整个GUI程序
    root.title("FishC Demo")#设置主窗口对象的标题栏

    #添加一个Label组件,可以显示文本、图标或者图片(此处显示文本)
    theLabel = tk.Label(root,text = "我的第二个窗口程序")
    theLabel.pack()#调用Label组件的pack方法,用于自动调节组件自身尺寸

    root.mainloop()#执行此语句后,窗口才会显示,程序进入主事件循环

    实例2:

    import tkinter as tk

    class App:#创建类App
        def __init__(self,root):#self为指向App类的指针
            #创建一个框架,然后在里面添加一个Button按钮组件,框架用来将复杂布局中按钮分组
            frame = tk.Frame(root)
            frame.pack(side = tk.RIGHT,padx = 10,pady = 10)#调节框架自身尺寸,此处设置为右对齐(右上角为原点),偏移(10,10)
            
            #创建一个按钮组件,fg(foreground),设置前景色
            #创建一个Button按钮,属性为self.hi_there,属于frame框架,按钮按下时调用self.say_hi方法
            #设置前景色为黑色,背景色为白色
            self.hi_there = tk.Button(frame,text = "打招呼",bg = "black",fg = "white",command = self.say_hi)
            self.hi_there.pack()#自动调节自身尺寸
            
            #say_hi()方法定义实现   
        def say_hi(self):
            print("互联网广大朋友们好,我是亦我飞也!")
            
            
    root = tk.Tk()#创建一个主窗口(toplever的根窗口),并把它作为参数实例化app对象,用于容纳整个GUI程序,
    app = App(root)#创建类App的一个实例对象app,传入参数为root

    app.mainloop()#执行此语句后,窗口才会显示,程序进入主事件循环
     

    065 GUI的终极选择:Tkinter2

    实例1:Label组件显示文字与gif图片

    #导入tkinter模块的所有内容
    from tkinter import *

    #创建主窗口
    root = Tk()
    #创建一个文本Label对象,文字为左对齐,离左边边框距离为10
    textLabel = Label(root,
                      text = "您下载的影片含有未成年人限制内容,\n请满18周岁后再点击观看!",
                      justify = LEFT,padx = 10)
    #Label组件为左对齐
    textLabel.pack(side = LEFT)

    #创建一个图像Label对象
    #用PhotoImage实例化一个图片对象(支持gif格式的图片)
    photo = PhotoImage(file = "18.gif")
    imgLabel = Label(root,image = photo)
    imgLabel.pack(side = RIGHT)

    mainloop()
     

    实例2:

    例2:文字显示在图片上

    #导入tkinter模块的所有内容
    from tkinter import *

    #创建主窗口
    root = Tk()

    #创建一个图像Label对象
    photo = PhotoImage(file = "bg.gif")
    #创建一个文本Label对象
    textLabel = Label(root,
                      text = "学Python\n到FishC!",
                      font = ("宋体",20),
                      fg = "white",
                      justify = LEFT,  #文字左对齐
                      image = photo,
                      compound = CENTER, #设置文本和图像的混合模式
                      )
    #文本Label对象偏移,离左窗口与上窗口都为10
    textLabel.pack(side = LEFT,padx =10,pady =10)

    mainloop()
     

    实例2:Button组件

    #导入tkinter模块的所有内容
    from tkinter import *

    def callback():
        var.set("吹吧你,我才不信呢~")

    #创建主窗口
    root = Tk()
    #设置主窗口对象的标题栏
    root.title("TK")

    frame1 = Frame(root)#框架1
    frame2 = Frame(root)#框架2

    #创建一个文本Label对象,文字为左对齐
    var = StringVar()
    var.set("您下载的影片含有未成年人限制内容,\n请满18周岁后再点击观看!")
    textLabel = Label(frame1,
                      textvariable = var, #Button显示一个StringVar的变量
                      justify = LEFT)
    #Label组件为左对齐
    textLabel.pack(side = LEFT)

    #创建一个图像Label对象
    #用PhotoImage实例化一个图片对象(支持gif格式的图片)
    photo = PhotoImage(file = "18.gif")
    imgLabel = Label(root,image = photo)
    imgLabel.pack(side = RIGHT)

    #加一个按钮
    theButton = Button(frame2,text = "已满18周岁",command = callback)
    theButton.pack()
    frame1.pack(padx = 10,pady = 10)
    frame2.pack(padx = 10,pady = 10)

    mainloop()

    066 GUI的终极选择:Tkinter3

    实例1:Checkbutton 组件

    from tkinter import *

    root = Tk()
    #需要一个Tkinter变量,用于表示该按钮是否被选中
    v = IntVar()
    c = Checkbutton(root,text="测试一下",variable = v)

    c.pack()
    #如果被选中,那么变量v被赋值为1,否则为0
    #可以用个Label标签动态地给大家展示:
    lable = Label(root,textvariable = v)
    lable.pack()

    mainloop()

    实例2:

    from tkinter import *

    root = Tk()

    GIRLS = ["貂蝉","王昭君","西施","杨玉环"]
    v = []
    for girl in GIRLS:
        v.append(girl)
        c = Checkbutton(root,text = girl,variable = v[-1])#-1表示每次取v列表中最后一个元素,即刚加入的那个元素
        c.pack(anchor = W)#W(western)向左对齐

    mainloop()

    实例3:Radiobutton 组件

    from tkinter import *

    root = Tk()

    v = IntVar()#如果被选中,v被赋值为1,否则为0
    Radiobutton(root,text = "One",variable = v,value = 1).pack(anchor = W)
    #value表示第一个按钮被选中时,v的值赋值给variable

    Radiobutton(root,text = "Two",variable = v,value = 2).pack(anchor = W)

    Radiobutton(root,text = "Three",variable = v,value = 3).pack(anchor = W)

    Radiobutton(root,text = "Four",variable = v,value = 4).pack(anchor = W)

    mainloop()

    实例4:循环处理

    from tkinter import *

    root = Tk()

    LANGS = [
        ("Python",1),
        ("Perl",2),
        ("Ruby",3),
        ("Lua",4)]
         

    v = IntVar()#如果被选中,v被赋值为1,否则为0
    v.set(1)#将1设置为默认值
    for lang,num in LANGS:
        b= Radiobutton(root,text = lang,variable = v,value = num)
        b.pack(anchor = W)
    #value表示第一个按钮被选中时,v的值赋值给variable

    mainloop()

    实例5:改成按钮形式

    from tkinter import *

    root = Tk()

    LANGS = [
        ("Python",1),
        ("Perl",2),
        ("Ruby",3),
        ("Lua",4)]
         

    v = IntVar()#如果被选中,v被赋值为1,否则为0
    v.set(1)#将1设置为默认值
    for lang,num in LANGS:
        b= Radiobutton(root,text = lang,variable = v,value = num,indicatoron = False)
        b.pack(fill = X)#表示横向填充
    #value表示第一个按钮被选中时,v的值赋值给variable

    mainloop()

    实例6:LabelFrame 组件

    from tkinter import *

    root = Tk()

    group = LabelFrame(root,text = "最好的脚本语言是?",padx = 10,pady = 10)#按钮相对边框的偏移
    group.pack(padx = 10,pady = 10)#框架相对边框的偏移

    LANGS = [
        ("Python",1),
        ("Perl",2),
        ("Ruby",3),
        ("Lua",4)]
         

    v = IntVar()#如果被选中,v被赋值为1,否则为0
    v.set(1)#将1设置为默认值
    for lang,num in LANGS:
        b= Radiobutton(group,text = lang,variable = v,value = num,indicatoron = False)
        b.pack(fill = X)
    #value表示第一个按钮被选中时,v的值赋值给variable

    mainloop()

    067 GUI的终极选择:Tkinter4

    实例1:

    from tkinter import *

    root = Tk()#创建主窗口
    e = Entry(root)#在主窗口中插入输入框
    e.pack(padx = 20,pady = 20)

    e.delete(0,END)#清空输入框
    e.insert(0,"默认文本...")#设置输入框内容

    mainloop()

    实例2:

    from tkinter import *

    def button1_show():
        print("作品:《%s》" % e1.get())#将e1.get()中得到的输入框1的内容格式化为字符串
        print("作者:%s" % e2.get())

    root = Tk()#创建主窗口

    Label(root,text = "作品:",padx = 20,pady = 10).grid(row=0,column=0)#第1行第1列,偏移是相对于当前操作组件的相邻x轴或y轴的偏移距离
    Label(root,text = "小甲鱼:").grid(row=1,column=0)#第1行第0列


    e1 = Entry(root)#在主窗口中插入输入框,文本框的内容通过e1调用
    e2 = Entry(root)#在主窗口中插入输入框
    e1.grid(row=0,column=1,padx=10)#x方向偏移是相对于"作品"的x方向偏移的;y方向偏移表示此输入框与y方向相邻物体或边框之间偏移的距离(y方向偏移)
    e2.grid(row=1,column=1,padx=10,pady=20)#x方向偏移是相对于"小甲鱼"的x方向偏移的;y方向偏移表示此输入框与y方向相邻上下物体或边框偏移的距离(y方向偏移)


    #加两个按钮
    Button1 = Button(root,text = "获取信息",command = button1_show)\
              .grid(row = 2,column = 0,sticky = W,padx = 10,pady=10)#加入反斜杠可实现分行编辑,方位设置为最西边(即靠左)
    Button2 = Button(root,text = "退出",command = root.quit).grid(row = 2,column = 1,sticky = E,padx=10)#方位设置为最东边(即靠右)

    #注:双击打开文件时退出才有效
    e1.delete(0,END)#清空输入框
    e1.insert(0,"零基础入门学习Python")#设置输入框内容

    e2.delete(1,END)#清空输入框
    e2.insert(1,"小甲鱼")#设置输入框内容

    mainloop()

    按下获取信息

    更改输入框数据,然后按下获取信息

    实例2:账号密码设置

    from tkinter import *

    def show():
        print("作品:《%s》" % e1.get())#将e1.get()中得到的输入框1的内容格式化为字符串
        print("作者:%s" % e2.get())
        e1.delete(0,END)#清空输入框1
        e2.delete(0,END)#清空输入框2

    root = Tk()#创建主窗口
    #Tkinter总共提供了三种布局组件的方法:pack()、grid()和place()
    #grid()方法允许你用表格的形式来管理组件的位置
    #row选项代表行,coulumn选项代表列
    #row = 1,column = 2表示第二行第三列(0表示第一行)

    Label(root,text = "账号:").grid(row=0)#第1行
    Label(root,text = "密码:").grid(row=1)#第2行
    v1 = StringVar()
    v2 = StringVar()

    e1 = Entry(root,textvariable = v1)#在主窗口中插入输入框,文本框的内容通过e1调用
    e2 = Entry(root,textvariable = v2,show="*")#在主窗口中插入输入框
    e1.grid(row=0,column=1,padx=10,pady=5)#x方向偏移是相对于"作品"的x方向偏移的;y方向偏移表示此输入框与y方向相邻物体或边框之间偏移的距离(y方向偏移)
    e2.grid(row=1,column=1,padx=10,pady=5)#x方向偏移是相对于"小甲鱼"的x方向偏移的;y方向偏移表示此输入框与y方向相邻上下物体或边框偏移的距离(y方向偏移)


    #可以使用sticky选项来设置组件的位置
    #使用N、E、S、W以及他们的组合NE、SE、SW、NW来表示方位

    #加两个按钮
    Button(root,text = "芝麻开门",command = show)\
              .grid(row = 2,column = 0,sticky = W,padx = 10,pady=5)#加入反斜杠可实现分行编辑,方位设置为最西边(即靠左)
    Button(root,text = "退出",command = root.quit).grid(row = 2,column = 1,sticky = E,padx=10)#方位设置为最东边(即靠右)

    mainloop()

    实例3:验证函数validatecommand

    from tkinter import *

    master = Tk()

    def test():
        if e1.get() == "小甲鱼":
            print("正确!")
            return True
        else:
            print("错误!")
            e1.delete(0, END)
            return False

    v = StringVar()

    #focusout表示Entry组件失去焦点的时候验证,调用validatecommand的test函数

    e1 = Entry(master, textvariable=v, validate="focusout", validatecommand=test)
    e2 = Entry(master)
    e1.pack(padx=10, pady=10)
    e2.pack(padx=10, pady=10)

    mainloop()
     

    实例4:invalidcommand函数

    from tkinter import *

    master = Tk()

    def test():
        if e1.get() == "小甲鱼":
            print("正确!")
            return True
        else:
            print("错误!")
            e1.delete(0, END)
            return False

    def test2():
        print("我被调用了...")

    v = StringVar()

    #focusout表示Entry组件失去焦点的时候验证,调用validatecommand的test函数
    #invalidcommand选项指定的函数只有在validatecommand的返回值为False的时候才被调用
    e1 = Entry(master, textvariable=v, validate="focusout", validatecommand=test,\
               invalidcommand=test2)
    e2 = Entry(master)
    e1.pack(padx=10, pady=10)
    e2.pack(padx=10, pady=10)

    mainloop()
     

    实例5:验证函数提供一些额外的选项

    validatecommand(f,s1,s2,...)

    其中,f是验证函数名,s1,s2,s3是额外的选项,这些选项会作为参数一次传给f函数。在此之前,需要调用register()方法将验证函数包装起来。

    from tkinter import *

    master = Tk()

    v = StringVar()

    def test(content, reason, name):
        if content == "小甲鱼":
            print("正确!")
            print(content, reason, name)
            return True
        else:
            print("错误!")
            print(content, reason, name)
            return False

    testCMD = master.register(test)
    e1 = Entry(master, textvariable=v, validate="focusout", \
               validat
               ecommand=(testCMD, '%P', '%v', '%W'))
    e2 = Entry(master)
    e1.pack(padx=10, pady=10)
    e2.pack(padx=10, pady=10)

    mainloop()
     

    实例6:设计一个 计算器

    from tkinter import *
    #计算函数
    def calc():
        result = int(v1.get())+int(v2.get())#强制转换为整型
        v3.set(result)#将result中的内容放到v3中

    #创建窗口
    root = Tk()
    #创建窗口中的一个frame框架
    frame = Frame(root)
    #设置框架位置并显示
    frame.pack(padx = 10,pady = 10)

    v1 = StringVar()
    v2 = StringVar()
    v3 = StringVar()

    #注意,这里不能使用e1.get()或者v1.get()来获取输入的内容,因为validate选项
    #指定为“key"的时候,有任何输入操作都会被拦截到这个函数中
    #也就是说先拦截,只有这个函数返回True,那么输入的内容才会到变量里去
    #所以要用%P来获取最新的输入框内容
    def test(content):
        if content.isdigit():
            return True
        else:
            return False

    #创建三个Entry组件
    testCMD = frame.register(test)
    #创建2个输入组件,输入的数据赋值给v1、v2
    e1 = Entry(frame, textvariable=v1,width=10, validate="key",\
               validatecommand=(testCMD, '%P'))
    e2 = Entry(frame, textvariable=v2,width=10, validate="key",\
               validatecommand=(testCMD, '%P'))
    #一个输出组件,设置为只读模式(readonly),v3的数据赋值给textvariable进行输出显示
    e3 = Entry(frame, textvariable=v3,width=10, validate="key",\
               validatecommand=(testCMD, '%P'),state="readonly")
    #位置设置
    e1.grid(row=0,column=0,padx=10,pady=10)
    e2.grid(row=0,column=2,padx=10)
    e3.grid(row=0,column=4,padx=10)

    #创建两个Label组件
    Label(frame,text="+").grid(row=0,column=1)
    Label(frame,text="=").grid(row=0,column=3)

    #创建一个按钮,宽度为10
    button=Button(frame,text="计算结果",width=10,command=calc)
    button.grid(row=1,column=2,pady=10)

    mainloop()

    068 GUI的终极选择:Tkinter5

    Listbox组件

    如果需要提供选项给用户选择,单选可以用Radiobutton组件,多选可以用Checkbutton,如果提供的选项非常多,可以考虑使用Listbox组件。Listbox是以列表的形式显示出来,并支持滚动条操作。

    实例1:

    from tkinter import *

    root = Tk()#创建主窗口

    theLB = Listbox(root,setgrid = True,selectmode=EXTENDED)#创建一个空列表
    theLB.pack()

    #往列表里添加数据
    for item in ["鸡蛋","鸭蛋","鹅蛋","李狗蛋"]:
        theLB.insert(END,item)#每次在列表最后插入一个数据

    #创建一个按钮,ACTIVE表示当前选中的数据
    theButton = Button(root,text="删除",command = lambda x = theLB:x.delete(ACTIVE))
    theButton.pack()

    #theLB.delete(0,END)删除所有列表数据

    mainloop()

    注:listbox.delete(0,END)可以删除列表中所有项目

    实例2:添加height选项

    from tkinter import *

    root = Tk()#创建主窗口

    #height=11表示可以显示11个项目
    theLB = Listbox(root,setgrid = True,\
                    selectmode=BROWSE,height=11)#创建一个空列表,选择模式为单选
    theLB.pack()

    #往列表里添加数据
    for item in range(11):
        theLB.insert(END,item)#每次在列表最后插入一个数据

    #创建一个按钮,ACTIVE表示当前选中的数据
    theButton = Button(root,text="删除",command = lambda x = theLB:x.delete(ACTIVE))
    theButton.pack()

    #theLB.delete(0,END)删除所有列表数据

    mainloop()

    Scrollbar组件

    实例1:

    from tkinter import *

    root = Tk()#创建主窗口

    sb = Scrollbar(root)
    sb.pack(side=RIGHT,fill=Y)

    lb = Listbox(root,yscrollcommand=sb.set)#创建一个空列表
    for i in range(1000):
        lb.insert(END,i)
    lb.pack(side=LEFT,fill=BOTH)

    sb.config(command = lb.yview)

    mainloop()

    事实上,这是一个互联互通的过程。当用户操作滚动条时,滚动条响应滚动并同时通过Listbox组件的yview()方法滚动列表框里的内容;同样,当列表框中可视范围发生改变的时候,Listbox组件通过调用Scrollbar组件的set()方法设置滚动条的最新位置。

    Scale组件

    Scale组件主要是通过滑块来表示某个范围内的一个数字,可以通过修改选项设置范围以及分辨率(精度)

    实例1:

    from tkinter import *

    root = Tk()#创建主窗口
    Scale(root,from_=0,to=42).pack()#创建铅锤方向滚动条
    Scale(root,from_=0,to=200,orient=HORIZONTAL).pack()#创建水平方向滚动条

    mainloop()

    实例2:打印当前位置

    from tkinter import *

    def show():
        print(s1.get(),s2.get())#使用get()方法获取当前滑块的位置

    root = Tk()#创建主窗口
    s1 = Scale(root,from_=0,to=42)#创建铅锤方向滚动条
    s1.pack()
    s2 = Scale(root,from_=0,to=200,orient=HORIZONTAL)#创建水平方向滚动条
    s2.pack()

    #创建一个按钮
    Button(root,text="获取位置",command=show).pack()

    mainloop()

    实例3:通过resolution选项控制分辨率(步长),通过tickinterval选项设置刻度

    from tkinter import *

    def show():
        print(s1.get(),s2.get())#使用get()方法获取当前滑块的位置

    root = Tk()#创建主窗口
    #tickinterval表示设置刻度,即每隔多少显示一个刻度
    #length表示滚动条的长度所占的像素数
    #resolution用来控制分辨率(步长)
    s1 = Scale(root,from_=0,to=42,tickinterval=5,length=200,\
               resolution=5,orient=VERTICAL)#创建铅锤方向滚动条
    s1.pack()
    s2 = Scale(root,from_=0,to=200,tickinterval=10,\
               length=600,orient=HORIZONTAL)#创建水平方向滚动条
    s2.pack()

    #创建一个按钮
    Button(root,text="获取位置",command=show).pack()

    mainloop()

    069 GUI的终极选择:Tkinter6

    Text组件

    Text(文本)组件用于显示和处理多种任务。虽然该组件的主要目的是显示多行文本,但它常常也被用于作为简单的文本编辑器和网页浏览器使用。

    实例1:插入内容

    from tkinter import *

    root = Tk()
    text = Text(root,width=30,height=2)
    text.pack()
    #INSERT索引表示插入光标当前的位置
    text.insert(INSERT,"I love\n")#光标当前的位置插入

    #END,对应Text组件的文本缓存区最后一个字符的下一个位置
    text.insert(END,"FishC.com!")

    mainloop()

    实例2:插入image对象windows组件

    from tkinter import *

    def show():
        print("哟,我被点了一下~")

    root = Tk()
    text = Text(root,width=30,height=5)
    text.pack()

    #INSERT索引表示插入光标当前的位置
    text.insert(INSERT,"I love FishC.com!")#光标当前的位置插入

    #创建一个按钮
    b1=Button(root,text="点我点我",command=show)
    text.window_create(INSERT,window=b1)

    mainloop()
     

    实例3:单击按钮显示一张图片

    from tkinter import *

    def show():
        text.image_create(INSERT,image=photo)

    root = Tk()
    text = Text(root,width=30,height=50)
    text.pack()

    #INSERT索引表示插入光标当前的位置
    text.insert(INSERT,"I love FishC.com!")#光标当前的位置插入

    photo = PhotoImage(file='fishc.gif')

    #创建一个按钮
    b1=Button(root,text="点我点我",command=show)
    text.window_create(INSERT,window=b1)

    mainloop()

    Indexer用法

    实例1:“line.column”

    from tkinter import *

    root = Tk()
    text = Text(root,width=30,height=5)
    text.pack()

    #INSERT索引表示插入光标当前的位置
    text.insert(INSERT,"I love FishC.com!")#光标当前的位置插入
    #注意,行号从1开始,列号则从0开始
    print(text.get(1.2,1.6))#获取第一行第2列到第一行第六列的数据

    mainloop()

    实例2:“line.end”

    行号加上字符串".end"格式表示为该行最后一个字符的位置

    实例:

    from tkinter import *

    root = Tk()
    text = Text(root,width=30,height=5)
    text.pack()

    #INSERT索引表示插入光标当前的位置
    text.insert(INSERT,"I love FishC.com!")#光标当前的位置插入
    #注意,行号从1开始,列号则从0开始
    print(text.get("1.2","1.end"))#获取第一行第2列到第一行第六列的数据

    mainloop()

    Mask用法

    mask(标记)通常是嵌入到Text组件文本中的不可见对象。事实上,Marks是指定字符间的位置,并跟随相应的字符一起移动。

    实例:Mark事实上就是索引,用于表示位置

    from tkinter import *

    root = Tk()
    text = Text(root,width=30,height=5)
    text.pack()

    #INSERT索引表示插入光标当前的位置
    text.insert(INSERT,"I love FishC.com!")#光标当前的位置插入
    #注意,行号从1开始,列号则从0开始
    text.mark_set("here","1.2")#设置光标位置为1.2
    text.insert("here","插")

    mainloop()

    实例2:如果Mark前面的内容发生改变,Mark的位置也会跟着移动

    from tkinter import *

    root = Tk()
    text = Text(root,width=30,height=5)
    text.pack()

    #INSERT索引表示插入光标当前的位置
    text.insert(INSERT,"I love FishC.com!")#光标当前的位置插入
    #注意,行号从1开始,列号则从0开始
    text.mark_set("here","1.2")#设置当前光标位置为1.2
    text.insert("here","插")#执行后当前光标位置(Mark位置)变成了1.3
    text.insert("here","入")
    #text.insert("1.3","入")

    mainloop()

    实例3:如果Mark周围的文本被删除了,Mark仍然存在

    from tkinter import *

    root = Tk()
    text = Text(root,width=30,height=5)
    text.pack()

    #INSERT索引表示插入光标当前的位置
    text.insert(INSERT,"I love FishC.com!")#光标当前的位置插入
    #注意,行号从1开始,列号则从0开始
    text.mark_set("here","1.2")#设置当前光标位置为1.2
    text.insert("here","插")#执行后当前光标位置变成了1.3
    text.delete("1.0",END)
    text.insert("here","入")#here表示当前Mark的位置,如果Mark左边并没有数据则会插入到最左边

    mainloop()

    例4:只有mark_unset()方法可以解除Mark的封印

    from tkinter import *

    root = Tk()
    text = Text(root,width=30,height=5)
    text.pack()

    #INSERT索引表示插入光标当前的位置
    text.insert(INSERT,"I love FishC.com!")#光标当前的位置插入
    #注意,行号从1开始,列号则从0开始
    text.mark_set("here","1.2")#设置当前光标位置为1.2
    text.insert("here","插")#执行后当前光标位置变成了1.3
    text.mark_unset("here")

    text.delete("1.0",END)
    text.insert("here","入")#here表示当前Mark的位置

    mainloop()

    默认插入内容是插入到Mark左侧(就是说插入一个字符后,Mark向后移动了一个字符的位置)

    实例5:插入内容到Mark的右侧

    from tkinter import *

    root = Tk()
    text = Text(root,width=30,height=5)
    text.pack()

    #INSERT索引表示插入光标当前的位置
    text.insert(INSERT,"I love FishC.com!")#光标当前的位置插入
    #注意,行号从1开始,列号则从0开始
    text.mark_set("here","1.2")#设置当前Mark位置为1.2
    text.mark_gravity("here",LEFT)

    text.insert("here","插")#执行后当前Mark位置变成了1.3
    text.insert("here","入")#here表示当前Mark的位置

    mainloop()

    070 GUI的终极选择:Tkinter7

    实例1:添加Tags

    from tkinter import *

    root = Tk()
    text = Text(root,width=30,height=5)
    text.pack()

    #INSERT索引表示插入光标当前的位置
    text.insert(INSERT,"I love FishC.com!")#光标当前的位置插入
    #注意,行号从1开始,列号则从0开始
    text.tag_add("tag1","1.7","1.12","1.14")#1.7(第一行第八列)到1.12,,与1.14设置Tag样式
    text.tag_config("tag1",background ="yellow",foreground="red")

    mainloop()

    实例2:Tags覆盖

    from tkinter import *

    root = Tk()
    text = Text(root,width=30,height=5)
    text.pack()

    #INSERT索引表示插入光标当前的位置
    text.insert(INSERT,"I love FishC.com!")#光标当前的位置插入
    #注意,行号从1开始,列号则从0开始
    text.tag_add("tag1","1.7","1.12","1.14")#1.7(第一行第八列)到1.12,,与1.14设置Tag样式
    text.tag_add("tag2","1.7","1.12","1.14")#1.7(第一行第八列)到1.12,,与1.14设置Tag样式

    text.tag_config("tag1",background ="yellow",foreground="red")
    text.tag_config("tag2",background ="blue")

    mainloop()
     

    实例2:降低Tag优先级

    from tkinter import *

    root = Tk()
    text = Text(root,width=30,height=5)
    text.pack()

    #INSERT索引表示插入光标当前的位置
    text.insert(INSERT,"I love FishC.com!")#光标当前的位置插入
    #注意,行号从1开始,列号则从0开始
    text.tag_add("tag1","1.7","1.12","1.14")#1.7(第一行第八列)到1.12,,与1.14设置Tag样式
    text.tag_add("tag2","1.7","1.12","1.14")#1.7(第一行第八列)到1.12,,与1.14设置Tag样式

    text.tag_config("tag1",background ="yellow",foreground="red")
    text.tag_config("tag2",background ="blue")

    text.tag_lower("tag2")#降低tag2的优先级

    mainloop()

    实例3:Tags事件绑定

    from tkinter import *
    import webbrowser#导入网页模块

    def show_hand_cursor(event):
        text.config(cursor="arrow")

    def show_arrow_cursor(event):
        text.config(cursor="xterm")

    def click(event):
        webbrowser.open("http://www.fishc.com")
        
    root = Tk()
    text = Text(root,width=30,height=5)
    text.pack()

    #INSERT索引表示插入光标当前的位置
    text.insert(INSERT,"I love FishC.com!")#光标当前的位置插入
    #注意,行号从1开始,列号则从0开始
    text.tag_add("link","1.7","1.16")#1.7(第一行第八列)到1.16
    #设置蓝色前景色并底部划线
    text.tag_config("link",foreground="blue",underline=True)

    #当进入绑定文本段时,鼠标样式切换为“arrow"形态
    text.tag_bind("link","<Enter>",show_hand_cursor)
    #当离开绑定文本段时,鼠标样式切换为“xterm"形态
    text.tag_bind("link","<Leave>",show_arrow_cursor)
    #当触发鼠标“左键单击”时,使用默认浏览器打开鱼C网址
    text.tag_bind("link","<Button-1>",click)

    mainloop()

    实例4:判断内容是否发生改变

    from tkinter import *
    import hashlib

    def getSig(contents):
        m = hashlib.md5(contents.encode())
        return m.digest()

    def check():#检查
        contents = text.get(1.0,END)
        if sig!=getSig(contents):
            print("警报,内容发生变动")
        else:
            print("风平浪静")
        
    root = Tk()
    text = Text(root,width=30,height=5)
    text.pack()

    #INSERT索引表示插入光标当前的位置
    text.insert(INSERT,"I love FishC.com!")#光标当前的位置插入
    #注意,行号从1开始,列号则从0开始
    #获取文本内容
    contents=text.get(1.0,END)

    sig = getSig(contents)

    Button(root,text="检查",command=check).pack()

    mainloop()

    实例5:查找操作(使用search()方法可以搜索Text组件中的内容)

    from tkinter import *
    import hashlib

    #将任何格式的索引号统一为元组(行,列)的格式输出
    def getIndex(text,index):
        #split这里以"."拆分字符串,将1.3拆分为字符1和3,然后通过map将字符转换为整型
        return tuple(map(int,str.split(text.index(index),".")))
        
    root = Tk()
    text = Text(root,width=30,height=5)
    text.pack()

    #INSERT索引表示插入光标当前的位置
    text.insert(INSERT,"I love FishC.com!")#光标当前的位置插入

    #将任何格式的索引号统一为元组(行、列)的格式输出
    start = 1.0
    while True:
        pos = text.search("o",start,stopindex=END)#从开始到结束全文搜索
        if not pos:
            break
        print("找到了,位置是:",getIndex(text,pos))
        start = pos + "+1c"#将start指向找到的字符位置的下一个字符,以便进行下一次搜索

    mainloop()

    Text组件内部有一个栈专门用于记录内容的每次变动,所以每次“撤销”操作就是一次弹栈操作,“恢复”就是再次压栈。

    实例6:撤销

    from tkinter import *

    #将任何格式的索引号统一为元组(行,列)的格式输出
    def show():
        text.edit_undo()
        
    root = Tk()
    text = Text(root,width=30,height=5,undo=True)
    text.pack()
    text.insert(INSERT,"I love FishC")

    Button(root,text="撤销",command=show).pack()

    mainloop()


    实例7:每次撤销一个字符

    from tkinter import *

    def callback(event):
        text.edit_separator()

    def show():
        text.edit_undo()#执行撤回操作
        
    root = Tk()

    #autoseparators表示一次完整的操作结束后自动插入“分隔符”,此处设置为False
    text = Text(root,width=30,height=5,autoseparators=False,undo=True,maxundo=10)
    text.pack()

    text.insert(INSERT,"I love FishC!")
    text.bind('<Key>',callback)#每次有输入就插入一个“分隔符”

    Button(root,text="撤销",command=show).pack()

    mainloop()

    071 GUI的终极选择:Tkinter8

    Canvas(画布)组件

    一个可以让你随心所欲绘制界面的组件。通常用于显示和编辑图形,可以用它来绘制直线、图形、多边形,甚至是绘制其他组件。

    实例1:

    from tkinter import *
    root = Tk()
    #创建canvas对象框,设置其宽度、高度与背景色
    w = Canvas(root,width=200,height=100,background="black")
    w.pack()

    #画一条黄色的线
    w.create_line(0,50,200,50,fill="yellow")
    #画一条红色的竖线(虚线)
    w.create_line(100,0,100,100,fill="red")
    #中间画一个蓝色的矩形
    w.create_rectangle(50,25,150,75,fill="blue")

    mainloop()

    实例2:

    from tkinter import *
    root = Tk()
    #创建canvas对象框,设置其宽度、高度与背景色
    w = Canvas(root,width=200,height=100,background="black")
    w.pack()

    #画一条黄色的线(参数为其x、y轴坐标)
    line1 = w.create_line(0,50,200,50,fill="yellow")
    #画一条红色的竖线(虚线)
    line2 = w.create_line(100,0,100,100,fill="red")
    #中间画一个蓝色的矩形
    rect1 = w.create_rectangle(50,25,150,75,fill="blue")

    w.coords(line1,0,25,200,25)#将line1移动到新的坐标
    w.itemconfig(rect1,fill="red")#重新设置矩形的填充色为红色
    w.delete(line2)#删除线2

    #创建一个按钮,按下时删除所有图形
    Button(root,text="删除全部",command=(lambda x=ALL:w.delete(x))).pack()

    mainloop()

    实例3:在Canvas上显示文本

    from tkinter import *
    root = Tk()
    #创建canvas对象框,设置其宽度、高度与背景色
    w = Canvas(root,width=200,height=100,background="black")
    w.pack()

    #画一条绿色的斜线(参数为其x、y轴坐标),宽度为三个像素点
    line1 = w.create_line(0,0,200,100,fill="green",width=3)
    #画一条绿色的斜线
    line2 = w.create_line(200,0,0,100,fill="green",width=3)
    #中间画两个矩形
    rect1 = w.create_rectangle(40,20,160,80,fill="blue")
    rect2 = w.create_rectangle(60,30,140,70,fill="yellow")
    #在矩形正中(默认)显示文本,坐标为文本正中坐标
    w.create_text(100,50,text="Hadley")

    #创建一个按钮,按下时删除所有图形
    Button(root,text="删除全部",command=(lambda x=ALL:w.delete(x))).pack()

    mainloop()

    实例4:绘制椭圆

    from tkinter import *
    root = Tk()
    #创建canvas对象框,设置其宽度、高度与背景色
    w = Canvas(root,width=200,height=100,background="white")
    w.pack()

    #绘制一个虚线的矩形
    w.create_rectangle(40,20,160,80,dash=(4,4))
    #绘制椭圆,粉色填充
    w.create_oval(40,20,160,80,fill="pink")
    #在矩形正中(默认)显示文本,坐标为文本正中坐标
    w.create_text(100,50,text="Hadley")

    mainloop()
    实例5:绘制圆形

    from tkinter import *
    root = Tk()
    #创建canvas对象框,设置其宽度、高度与背景色
    w = Canvas(root,width=200,height=100,background="white")
    w.pack()

    #绘制一个虚线的矩形
    w.create_rectangle(40,20,160,80,dash=(4,4))
    #绘制圆形,粉色填充
    #w.create_oval(40,20,160,80,fill="pink")
    w.create_oval(70,20,130,80,fill="pink")
    #在矩形正中(默认)显示文本,坐标为文本正中坐标
    w.create_text(100,50,text="Hadley")

    mainloop()

    实例6:绘制多边形

    from tkinter import *
    import math as m

    root = Tk()
    w=Canvas(root,width=200,height=150,background="red")
    w.pack()
    center_x = 100
    center_y = 80
    r = 70
    points = [
        #左上角A
        center_x - int(r*m.sin(2*m.pi/5)),
        center_y - int(r*m.cos(2*m.pi/5)),
        #右上角C
        center_x + int(r*m.sin(2*m.pi/5)),
        center_y - int(r*m.cos(2*m.pi/5)),
        #左下角E
        center_x - int(r*m.sin(m.pi/5)),
        center_y + int(r*m.cos(m.pi/5)),
        #顶点D
        center_x,
        center_y - r,
        #右下角B
        center_x + int(r*m.sin(m.pi/5)),
        center_y + int(r*m.cos(m.pi/5)),
        ]
    #创建多边形方法,会自动按ACEDBA的形式连线,如果构成闭环,则会自动填充
    w.create_polygon(points,outline="green",fill="yellow")

    w.create_text(100,80,text="Hadley")

    mainloop()

    实例7:

    from tkinter import *

    root = Tk()
    w=Canvas(root,width=400,height=200,background="white")
    w.pack()

    def paint(event):#画小圆
        x1,y1 = (event.x - 1),(event.y -1)
        x2,y2 = (event.x + 1),(event.y +1)
        w.create_oval(x1,y1,x2,y2,fill="red")

    w.bind("<B1 - Motion>",paint)#画布与鼠标进行绑定
    Label(root,text="按住鼠标左键并移动,开始绘制你的理想蓝图吧。。。").pack(side=BOTTOM)

    mainloop()

    073 GUI的终极选择:Tkinter10

    Munu组件

    Tkinter提供了一个Menu组件,用于实现顶级菜单、下拉菜单和弹出菜单。

    实例1:创建一个顶级菜单(或称窗口主菜单

    from tkinter import *

    def callback():
        print("被调用了")
        
    root = Tk()


    menubar = Menu(root)#创建一个顶级菜单
    menubar.add_command(label="Hello",command=callback)#创建一个顶级菜单对象
    menubar.add_command(label="Quit",command=root.quit)

    #显示菜单
    root.config(menu=menubar)

    mainloop()

    实例2:创建添加到主菜单上的下拉菜单

    from tkinter import *

    def callback():
        print("被调用了")
        
    root = Tk()

    #创建一个顶级菜单
    menubar = Menu(root)

    #创建下拉菜单filemenu包含内容
    filemenu=Menu(menubar,tearoff=False)#创建一个从属于menubar的子菜单(下拉菜单)filemenu
    filemenu.add_command(label="打开",command=callback)#创建一个下拉菜单对象
    filemenu.add_command(label="保存",command=callback)
    filemenu.add_separator()#插入分隔线
    filemenu.add_command(label="退出",command=root.quit)
    #创建一个顶级菜单对象“文件”,filemenu从属于这个对象(或称将filemenu添加到顶级菜单“文件”中)
    menubar.add_cascade(label="文件",menu=filemenu)

    #创建另一个下拉菜单editmenu包含内容
    editmenu=Menu(menubar,tearoff=False)#创建一个从属于menubar的子菜单(下拉菜单)editmenu
    editmenu.add_command(label="剪切",command=callback)
    editmenu.add_command(label="拷贝",command=callback)
    editmenu.add_separator()#插入分隔线
    editmenu.add_command(label="粘贴",command=callback)
    #创建一个顶级菜单对象“编辑”,editmenu从属于这个对象(或称将editmenu添加到顶级菜单“编辑”中)
    menubar.add_cascade(label="编辑",menu=editmenu)

    #显示菜单
    root.config(menu=menubar)

    mainloop()

    实例3:创建一个弹出菜单方法

    from tkinter import *

    def callback():
        print("被调用了")
        
    root = Tk()

    def popup(event):
        menu.post(event.x_root,event.y_root)#在此时鼠标位置弹出显示窗口
        
    #创建一个顶级菜单menu
    menu = Menu(root,tearoff=False)

    #创建顶级菜单menu包含内容
    menu.add_command(label="撤销",command=callback)#创建一个顶级菜单对象
    menu.add_command(label="重做",command=callback)
    #创建一个框架
    frame = Frame(root,width=100,height=100)
    frame.pack()

    #将鼠标右键与popup方法绑定
    frame.bind("<Button-3>",popup)

    #显示菜单
    #root.config(menu=menu)

    mainloop()

    实例4:菜单弹出

    from tkinter import *

    def callback():
        print("被调用了")
        
    root = Tk()

    def popup(event):
        menu.post(event.x_root,event.y_root)#在此时鼠标位置弹出显示窗口
        
    #创建一个顶级菜单menu
    menu = Menu(root,tearoff=True)

    #创建顶级菜单menu包含内容
    menu.add_command(label="撤销",command=callback)#创建一个顶级菜单对象
    menu.add_command(label="重做",command=callback)
    #创建一个框架
    frame = Frame(root,width=500,height=500)
    frame.pack()

    #将鼠标右键与popup方法绑定
    frame.bind("<Button-3>",popup)

    #显示菜单
    #root.config(menu=menu)

    mainloop()

    实例5:添加单选组件radiobutton和多选按钮checkbutton

    from tkinter import *

    def callback():
        print("被调用了")
        
    root = Tk()

    #创建一个顶级菜单
    menubar = Menu(root)
    #创建checkbutton关联变量
    openVar = IntVar()
    saveVar = IntVar()
    exitVar = IntVar()
    #创建下拉菜单filemenu包含内容
    filemenu=Menu(menubar,tearoff=True)#创建一个从属于menubar的子菜单(下拉菜单)filemenu
    filemenu.add_checkbutton(label="打开",command=callback,variable=openVar)#创建一个下拉菜单对象
    filemenu.add_checkbutton(label="保存",command=callback,variable=saveVar)
    filemenu.add_separator()#插入分隔线
    filemenu.add_checkbutton(label="退出",command=root.quit,variable=exitVar)
    #创建一个顶级菜单对象“文件”,filemenu从属于这个对象(或称将filemenu添加到顶级菜单“文件”中)
    menubar.add_cascade(label="文件",menu=filemenu)

    #创建radiobutton关联变量
    editVar = IntVar()
    editVar.set(1)

    #创建另一个下拉菜单editmenu包含内容
    editmenu=Menu(menubar,tearoff=True)#创建一个从属于menubar的子菜单(下拉菜单)editmenu
    editmenu.add_radiobutton(label="剪切",command=callback,variable=editVar,value=1)
    editmenu.add_radiobutton(label="拷贝",command=callback,variable=editVar,value=2)
    editmenu.add_separator()#插入分隔线
    editmenu.add_radiobutton(label="粘贴",command=callback,variable=editVar,value=3)
    #创建一个顶级菜单对象“编辑”,editmenu从属于这个对象(或称将editmenu添加到顶级菜单“编辑”中)
    menubar.add_cascade(label="编辑",menu=editmenu)

    #显示菜单
    root.config(menu=menubar)

    mainloop()

    Menubutton组件(希望菜单按钮出现在其它位置时)

    Menubutton组件是一个与Menu组件相关联的按钮,它可以放在窗口中的任意位置,并且在被按下时弹出下拉菜单

    实例1:

    from tkinter import *

    def callback():
        print("被调用了")
        
    root = Tk()

    #创建一个顶级菜单Menubutton按钮,设置为浮起显示(RAISED)
    mb = Menubutton(root,text="点我",relief=RAISED)

    mb.pack(side=RIGHT)#设置为右中显示

    #创建下拉菜单filemenu包含内容
    filemenu = Menu(mb,tearoff=False)#创建一个从属于mb的下拉菜单filemenu
    filemenu.add_checkbutton(label="打开",command=callback,selectcolor="yellow")
    filemenu.add_command(label="保存",command=callback)#创建一个下拉菜单对象"保存“
    filemenu.add_separator()
    filemenu.add_command(label="退出",command=root.quit)
    #显示菜单
    mb.config(menu=filemenu)

    mainloop()

    OptionMenu(选项菜单)组件

    选项菜单的发明弥补了Listbox组件无法实现下拉列表框的遗憾

    实例1:

    from tkinter import *

    def callback():
        print("被调用了")
        
    root = Tk()

    variable = StringVar()#创建字符串变量variable
    variable.set("one")#初始值设置为"one"
    w = OptionMenu(root,variable,"one","two","three")
    w.pack()

    mainloop()

    实例2:多个选项添加到选项菜单中

    from tkinter import *

    def callback():
        print("被调用了")
        
    root = Tk()

    OPTIONS = [
        "Hadley",
        "小土豆",
        "yiwofeiye",
        "RAN"
        ]

    variable = StringVar()#创建字符串变量variable
    variable.set(OPTIONS[0])#初始值设置为"one"
    w = OptionMenu(root,variable,*OPTIONS)
    w.pack()

    def callback():
        print(variable.get())

    Button(root,text="点我",command=callback).pack()

    mainloop()
     

    074  GUI的终极选择:Tkinter11

    事件绑定

    对于每个组件来说,可以通过bind()方法将函数或方法绑定到具体的事件上。当被触发的事件满足该组件绑定的事件时,Tkinter就会带着事件描述去调用handler()方法

    实例1:捕获单击鼠标位置

    from tkinter import*

    root = Tk()

    def callback(event):
        print("点击位置:",event.x,event.y)

    frame = Frame(root,width=200,height=200)
    #Button表示鼠标点击事件
    #1代表左键 2代表中间滚轮点击 3代表右键
    frame.bind("<Button-1>",callback)#按键按下时,调用callback方法
    frame.pack()

    mainloop()

    实例2:捕获键盘事件

    #捕获单击鼠标的位置
    from tkinter import*

    root = Tk()

    def callback(event):
        print("敲击位置:",repr(event.char))#打印当前按下按键的字符
        print(event.char)

    frame = Frame(root,width=200,height=200)
    #Key为键盘事件
    frame.bind("<Key>",callback)#按键按下时,调用callback方法
    frame.focus_set()#获得焦点
    frame.pack()

    mainloop()

    实例3:捕获鼠标在组件上的运动轨迹

    #当鼠标在组件内移动的整个过程均触发该事件

    from tkinter import*

    root = Tk()

    def callback(event):
        print("当前位置:",event.x,event.y)#打印当前按下按键的字符

    frame = Frame(root,width=200,height=200)
    frame.bind("<Motion>",callback)#按键按下时,调用callback方法
    frame.pack()

    mainloop()

    事件序列

    Tkinter使用一种称为事件序列的机制来允许用户定义事件,用户需要使用bind()方法将具体的事件序列与自定义的方法绑定

    Event对象(按键名keysym和按键码keycode)

    实例1:打印当前按下按键的按键名

    from tkinter import*

    root = Tk()

    def callback(event):
        print(event.keysym)#打印当前按下按键的按键名
        print(event.char)

    frame = Frame(root,width=200,height=200)
    #Key为键盘事件
    frame.bind("<Key>",callback)#按键按下时,调用callback方法
    frame.focus_set()#获得焦点
    frame.pack()

    mainloop()

    075 GUI的终极选择:Tkinter12

    Message组件

    Message(消息)组件是Label组件的变体,用于显示多行文本信息。Message组件能够自动换行,并调整文本的尺寸使其适应给定得尺寸。

    实例1:

    from tkinter import *

    root = Tk()
    w1 = Message(root,text="这是一则消息",width=100)
    w1.pack()
    w2 = Message(root,text="这是一条骇人听闻的长消息!",width=100)
    w2.pack()

    mainloop()

    Spinbox组件

    Entry组件的变体,用于从一些固定的值中选取一个。使用Spinbox组件,可以通过返回或者元组指定允许用户输入的内容。

    实例1:

    from tkinter import *

    root = Tk()

    #w = Spinbox(root,from_=0,to=10)#指定输入值为0-10
    w = Spinbox(root,value=("Hadley","小土豆","雅馨"))#指定输入
    w.pack()

    mainloop()

    PanedWindow组件

    与Frame类似,都是为组件提供一个框架,但其还允许让用户调整应用程序的空间划分

    实例1:两窗格

    from tkinter import *

    root = Tk()

    m = PanedWindow(orient = VERTICAL)#设置为上下分布
    m.pack(fill=BOTH,expand=1)#设置为框架覆盖全局

    top = Label(m,text="top pane")#顶窗格
    m.add(top)

    bottom = Label(m,text="bottom pane")#底窗格
    m.add(bottom)

    mainloop()

    实例2:三窗格

    from tkinter import *

    root = Tk()

    m1 = PanedWindow()#默认为左右分布
    m1.pack(fill=BOTH,expand=1)
    left = Label(m1,text="left pane")#左窗格
    m1.add(left)

    m2 = PanedWindow(orient=VERTICAL)
    m1.add(m2)
    top=Label(m2,text="top pane")#顶窗格
    m2.add(top)
    bottom = Label(m2,text="bottom pane")#底窗格
    m2.add(bottom)

    mainloop()

    实例3:显示“分割线”

    from tkinter import *

    root = Tk()

    #showhandle=True表示显示“手柄”
    #sashrelief=SUNKEN表示分隔线的样式设置为向下凹
    m1 = PanedWindow(showhandle=True,sashrelief=SUNKEN)
    m1.pack(fill=BOTH,expand=1)
    left = Label(m1,text="left pane")
    m1.add(left)

    m2 = PanedWindow(orient=VERTICAL,showhandle=True,sashrelief=SUNKEN)
    m1.add(m2)
    top=Label(m2,text="top pane")
    m2.add(top)
    bottom = Label(m2,text="bottom pane")
    m2.add(bottom)

    mainloop()

    Toplevel组件

    Topleve(顶级窗口)l组件类似于Frame组件,但其是一个独立的顶级窗口,通常拥有标题栏、边框等部件。通常用在显示额外的窗口、对话框和其他弹出窗口中。

    实例1:按钮按下创建一个顶级窗口

    from tkinter import *

    def create():
        top = Toplevel()#创建一个独立的顶级窗口
        top.title("FishC Demo")
        msg = Message(top,text="I love FishC.com")
        msg.pack()
        
    root = Tk()
    Button(root,text="创建顶级窗口",command=create).pack()

    mainloop()

    实例2:Toplevel的窗口设置为50%透明

    from tkinter import *

    def create():
        top = Toplevel()
        top.title("FishC Demo")
        top.attributes("-alpha",0.5)#设置为50%透明度
        msg = Message(top,text="I love FishC.com")
        msg.pack()
        
    root = Tk()
    Button(root,text="创建顶级窗口",command=create).pack()

    mainloop()

    076 GUI的终极选择:Tkinter13

    布局管理器

    布局管理器就是管理你的那些组件如何排列的家伙。Tkinter有三个布局管理器,分别是pack、grid和place

    pack:按添加顺序排列组件

    grid:按行/列形式排列组件

    place:允许程序员指定组件的大小和位置

    pack

    实例1:生成一个Listbox组件并将它填充到root窗口

    from tkinter import *

    root = Tk()
    listbox = Listbox(root)
    #fill选项是告诉窗口管理器该组件将怎样填充整个分配给它的空间
    #BOTH表示同时横向和纵向扩展;X表示横向;Y表示纵向
    #expand选项是告诉窗口管理器是否将父组件的额外空间也填满(任意拉伸窗口依旧会填满)

    #默认情况下pack是将添加的组件依次纵向排列
    listbox.pack(fill=BOTH,expand=True)
    for i in range(10):
        listbox.insert(END,str(i))

    mainloop()

    实例2:纵向排列,横向填充

    from tkinter import *

    root = Tk()
    #fill选项是告诉窗口管理器该组件将怎样填充整个分配给它的空间
    #BOTH表示同时横向和纵向扩展;X表示横向;Y表示纵向
    #expand选项是告诉窗口管理器是否将父组件的额外空间也填满

    #默认情况下pack的side属性是将添加的组件依次纵向排列
    Label(root, text="red", bg="red", fg="white").pack(fill=X)
    Label(root, text="green", bg="green", fg="black").pack(fill=X)
    Label(root, text="blue", bg="blue", fg="white").pack(fill=X)

    mainloop()

    实例3:横向排列,纵向填充

    from tkinter import *

    root = Tk()
    #fill选项是告诉窗口管理器该组件将怎样填充整个分配给它的空间
    #BOTH表示同时横向和纵向扩展;X表示横向;Y表示纵向
    #expand选项是告诉窗口管理器是否将父组件的额外空间也填满

    #将pack设置为横向排列
    Label(root, text="red", bg="red", fg="white").pack(side=LEFT)
    Label(root, text="green", bg="green", fg="black").pack(side=LEFT)
    Label(root, text="blue", bg="blue", fg="white").pack(side=LEFT)

    mainloop()

    grid

    使用一个grid就可以简单地实现你用很多个框架和pack搭建起来的效果。使用grid排列组件,只需告诉它你想要将组件放置的位置(行row/列column)。

    实例1:

    from tkinter import *

    root = Tk()

    #column默认值是0
    #默认情况下组件会居中显示在对应的网格里
    #Label(root,text="用户名").grid(row=0)
    #Label(root,text="密码").grid(row=1)
    #设置sticky=W使Label左对齐
    Label(root,text="用户名").grid(row=0,sticky=W)#左对齐
    Label(root,text="密码").grid(row=1,sticky=W)

    Entry(root).grid(row=0,column=1)
    Entry(root,show="*").grid(row=1,column=1)

    mainloop()

    实例2:设置rowspan与columnspan实现跨行和跨列功能

    from tkinter import *

    root = Tk()

    #column默认值是0
    #默认情况下组件会居中显示在对应的网格里
    #Label(root,text="用户名").grid(row=0)
    #Label(root,text="密码").grid(row=1)
    #设置sticky=W使Label左对齐
    #创建Label文本
    Label(root,text="用户名").grid(row=0,sticky=W)
    Label(root,text="密码").grid(row=1,sticky=W)
    #创建输入
    Entry(root).grid(row=0,column=1)
    Entry(root,show="*").grid(row=1,column=1)
    #插入Label图像
    photo = PhotoImage(file="logo.gif")
    #rowspan=2跨两行,边距5
    Label(root,image=photo).grid(row=0,column=2,rowspan=2,padx=5,pady=5)
    #columnspan=3跨三列(默认为居中显示),边距5
    Button(text="提交",width=10).grid(row=2,columnspan=3,pady=5)

    mainloop()

    place

    通常情况下不建议使用place布局管理器

    实例1:将子组件显示在父组件的正中间

    from tkinter import *

    def callback():
        print("正中靶心")
    root = Tk()
    #relx和rely指定的是子组件相对于父组件的位置,范围是(00`1.0),0.5则表示一半,正中间
    #anchor=CENTER表示正中显示
    Button(root,text="点我",command=callback).place(relx=0.5,rely=0.5,anchor=CENTER)

    mainloop()

    实例2:Button组件覆盖Label组件

    from tkinter import *

    def callback():
        print("正中靶心")
    root = Tk()

    photo = PhotoImage(file="logo_big.gif")
    Label(root,image=photo).pack()
    #relx和rely指定的是子组件相对于父组件的位置,范围是(00`1.0),0.5则表示一半,正中间
    Button(root,text="点我",command=callback).place(relx=0.5,rely=0.5,anchor=CENTER)

    mainloop()

    实例3:

    from tkinter import *

    root = Tk()

    #relx和rely指定的是子组件相对于父组件的位置,范围是(00`1.0),0.5则表示一半,正中间
    #relwidth和relheight选项指定相对父组件的尺寸
    Label(root,bg="red").place(relx=0.5,rely=0.5,relheight=0.75,relwidth=0.75,anchor=CENTER)
    Label(root,bg="yellow").place(relx=0.5,rely=0.5,relheight=0.5,relwidth=0.5,anchor=CENTER)
    Label(root,bg="green").place(relx=0.5,rely=0.5,relheight=0.25,relwidth=0.25,anchor=CENTER)

    mainloop()

    077 GUI的终极选择:Tkinter14

    Tkinter提供了三种标准对话框模块,分别是:messagebox、filedialog、colorchooser

    messagebox(消息对话框)

    实例1:askokcancel函数

    from tkinter import *

    print(messagebox.askokcancel("FishC Demo","发射核弹?"))

    mainloop()

    实例2:askquestion函数

    实例3:asiretrycancel函数

    实例4:askyesno函数

    实例5:showerror函数

    from tkinter import *

    #print(messagebox.askokcancel("FishC Demo","发射核弹?"))
    #print(messagebox.askquestion("FishC Demo","买个U盘?"))
    #print(messagebox.askretrycancel("FishC Demo","启动失败,重启?"))
    #print(messagebox.askyesno("FishC Demo","你确定要格式化硬盘吗?"))
    print(messagebox.showerror("FishC Demo","Error!!!"))

    mainloop()

    实例6:showinfo函数

    from tkinter import *

    #options参数可设置为default、icon与parent
    #print(messagebox.askokcancel("FishC Demo","发射核弹?"))
    #print(messagebox.askquestion("FishC Demo","买个U盘?"))
    #print(messagebox.askretrycancel("FishC Demo","启动失败,重启?"))
    #print(messagebox.askyesno("FishC Demo","你确定要格式化硬盘吗?"))
    #print(messagebox.showerror("FishC Demo","Error!!!"))
    messagebox.showinfo("Hadley","Great!!!",icon="info")

    mainloop()

    实例7:showwarning函数

    from tkinter import *

    #options参数可设置为default、icon与parent
    #print(messagebox.askokcancel("FishC Demo","发射核弹?"))
    #print(messagebox.askquestion("FishC Demo","买个U盘?"))
    #print(messagebox.askretrycancel("FishC Demo","启动失败,重启?"))
    #print(messagebox.askyesno("FishC Demo","你确定要格式化硬盘吗?"))
    #print(messagebox.showerror("FishC Demo","Error!!!"))
    #messagebox.showinfo("Hadley","Great!!!",icon="info")
    messagebox.showwarning("Hadley","Warning!!!",icon="warning")

    mainloop()

    filedialog(文本对话框)

    当应用程序需要使用打开文件或保存文件的功能时

    实例1:

    from tkinter import *

    root = Tk()

    def callback():
        #askopenfilename函数用来打开文件
        #asksaveasfilename函数用来保存文件
        fileName = filedialog.askopenfilename()
        print(fileName)

    Button(root,text="打开文件夹",command=callback).pack()

    mainloop()

    实例2:限制打开文件类型

    from tkinter import *

    root = Tk()

    def callback():
        #askopenfilename函数用来打开文件
        #asksaveasfilename函数用来保存文件
        #fileName = filedialog.askopenfilename()
        #限制打开文件类型
        fileName = filedialog.askopenfilename(filetypes=[("PNG",".png"),("GIF",".gif")])
        print(fileName)

    Button(root,text="打开文件夹",command=callback).pack()

    mainloop()

    colorchooser(颜色选择对话框)

    颜色对话框提供一个让用户选择颜色的界面

    实例1:

    from tkinter import *

    root = Tk()

    def callback():
        #colorchooser函数用于打开颜色选择对话框
        fileName = colorchooser.askcolor()
        print(fileName)

    Button(root,text="打开文件夹",command=callback).pack()

    mainloop()

    对应的RGB值及其对应的16进制值

    078 Pygame:初次见面,请大家多多关照

     

    展开全文
  • SIR及SEIR建模的简单示例

    万次阅读 多人点赞 2020-02-09 18:35:29
    V=\left[\frac{\partial V_i(x_0)}{\partial x_j}\right] V = [ ∂ x j ​ ∂ V i ​ ( x 0 ​ ) ​ ] 表示感染者的区间传播。 3 模型实现 编码采用R语言,对于SIR系列的建模,R语言中有现成的软件包:SimInf。...

    概述

    看了一些2019-nCoV相关的文章,摘录并总结了一些关于SIR和SEIR模型的定义。并通过代码进了简单模型的实现,使用R语言作为编程工具。

    1.一些定义

    1.1 一些名词

    序号词汇解释
    1Pneumonia肺炎
    2Coronavirus冠状病毒
    3Incubation潜伏
    4Quarantined隔离
    5Susceptible易感的,这里用于指易感人群,在CDC的公告中,所有人都属于易感人群。
    6zoonotic动物传播的
    7Reproductive再生,复制。这里指感染者再传播并产生新的感染者。
    8novel新的
    92019-nCoV2019新型冠状病毒

    1.2 一些符号

    序号符号含义
    1 R 0 R_0 R0基础再传播人数
    2 τ \tau τ传染概率,一名易感者和一名感染者接触时被感染的概率
    3 c ˉ \bar{c} cˉ单位时间内和感染者接触的易感人员的平均比例值
    4 d d d感染暴露时长
    5 S S S易感人群
    6 I I I感染人群
    7 R R R移除人群,是指,被隔离或治愈而消除影响的感染人群
    8E暴露人群, 处于潜伏期

    1.3 一些定义

    R 0 = τ ⋅ c ˉ ⋅ d R_0 = \tau \cdot \bar{c} \cdot d R0=τcˉd

    用1小时表示1单位时长,通俗的理解:
    再 传 播 人 数 = 传 染 率 ⋅ 接 触 易 感 人 数 的 平 均 值 ⋅ 感 染 暴 露 时 长 再传播人数=传染率\cdot 接触易感人数的平均值 \cdot 感染暴露时长 =
    假定 τ = 0.2 , c ˉ = 5 , d = 4 \tau=0.2,\bar{c}=5,d=4 τ=0.2,cˉ=5,d=4,则 R 0 = 4 R_0=4 R0=4

    2.方法论

    2.1 SIR

    SIR(Susceptible-Infected-Removed)模型,用于传染病的传播人数进行建模。

    关于模型的一些定义和假设:

    1. N,封闭系统内的总人口。
    2. 传染率、排除率等为常量。
    3. 不考虑出生和自然死亡。
    4. 人群是均匀混合的。任何感染者可以以概率接触任何一名易感者,这里的概率可以用总体均值来替代。

    通过模型的假设我们可以看到,SIR实际上是对传染病流行早期传播行为的建模。模型形式如下:
    { d s d t = − β s i d i d t = β s i − γ i d r d t = γ i \left \{ \begin{aligned} & \frac{ds}{dt} = -\beta s i \\ & \frac{di}{dt} = \beta s i -\gamma i \\ & \frac{dr}{dt} = \gamma i \end{aligned} \right. dtds=βsidtdi=βsiγidtdr=γi
    其中 β = τ c ˉ \beta = \tau\bar{c} β=τcˉ表示有效接触率, v v v表示消除率, $\gamma 表 示 移 除 率 , 都 是 常 量 。 因 而 传 染 暴 露 时 长 实 际 上 是 表示移除率,都是常量。因而传染暴露时长实际上是 v 的 倒 数 , 有 的倒数,有 d=\gamma^{-1}$。

    当传染病爆发时,感染者人数随着时间上升,因此有 d i / d t ≥ 0 di/dt\geq0 di/dt0,从而有:
    β s i − γ i > β s i γ > i \beta s i-\gamma i\gt \\ \frac{\beta s i}{\gamma}>i βsiγi>γβsi>i
    在一场疫情的爆发之初,每个人都可视为易感染群,因此这里 s ≈ 1 s\approx 1 s1,代入上式有:
    β γ = τ c ˉ d = R 0 > 1 \frac{\beta}{\gamma}=\tau\bar{c}d=R_0>1 γβ=τcˉd=R0>1
    因而当 R 0 > 1 R_0>1 R0>1时疫情是处于传染阶段的。

    对上述微分方程组求解得到:
    I = ( S 0 + I 0 ) − S + 1 R 0 ln ⁡ S S 0 I=(S_0+I_0)-S+\frac{1}{R_0}\ln\frac{S}{S_0} I=(S0+I0)S+R01lnS0S
    其中 S 0 , I 0 S_0,I_0 S0,I0表示初值。当 S 0 < 1 R 0 S_0<\frac{1}{R_0} S0<R01时传染降低,为了达到这个目的可采取以下措施:

    1. 降低 S 0 S_0 S0,即减少易感者数量,在这里也就是戴口罩、不外出等。
    2. 提高 1 R 0 \frac{1}{R_0} R01,即降低$\beta $(接触率),在这里也就是减少人员流动。
    3. 提高 γ \gamma γ(移除率),提高隔离率或治愈率。

    2.2 SEIR

    SEIR(Susceptible-Exposed-Infected-Removed),类似于SIR,但是增加了对潜伏期的定义,因此更适用于具有一定潜伏期的传染病。状态之间的转化如下所示:
    在这里插入图片描述

    其中, λ \lambda λ表示易感人群的输入(人口增加), μ \mu μ表示死亡率, k k k表示从暴露人群到确诊感染者的比率, γ \gamma γ是感染者的移除率。模型由如下四个等式组成:
    S ˙ = − β S I + λ − μ S E ˙ = β S I − ( μ + k ) E I ˙ = k E − ( γ + μ ) I R ˙ = γ I − μ R \begin{aligned} \dot{S} &=-\beta S I+\lambda-\mu S \\ \dot{E} &=\beta S I-(\mu+k) E \\ \dot{I} &=k E-(\gamma+\mu) I \\ \dot{R} &=\gamma I-\mu R \end{aligned} S˙E˙I˙R˙=βSI+λμS=βSI(μ+k)E=kE(γ+μ)I=γIμR

    2.3 代际传播

    2.3.1 传播矩阵

    对于同一种传染病而言,每一个患者的感染途径可能是不同的,比如:蝙蝠传人、男人传女人、狗传人等。定义代际传播矩阵 G \mathbf{G} G,其中元素 g i , j g_{i,j} gi,j表示下一代中由一个 j j j类病患导致的 i i i类病患的数量,由此可知 G \mathbf{G} G是方阵。同时 R 0 R_0 R0对应 G G G的谱半径(绝对值最大的特征值)。从 G \mathbf{G} G的数学性质来看,它是非奇异的,同时具有一个正的特征值并且严格大于其它特征值,实际上这个特征值就是 R 0 R_0 R0

    对于只有两种状态的传染病而言有:
    G = [ a b c d ] \mathbf{G}=\left[ \begin{array}{ll}{a} & {b} \\ {c} & {d} \end{array}\right] G=[acbd]
    其特征值为: λ ± = a + d 2 ± ( ( a + d ) / 2 ) 2 − ( a d − b c ) \lambda_{\pm}=\frac{a+d}{2}\pm\sqrt{((a+d)/2)^2-(ad-bc)} λ±=2a+d±((a+d)/2)2(adbc)

    此外, G \mathbf{G} G也可以写成入下形式:
    G = F V − 1 \mathbf{G}=FV^{-1} G=FV1
    其中 F = [ ∂ F i ( x 0 ) ∂ x j ] F=\left[\frac{\partial F_i(x_0)}{\partial x_j}\right] F=[xjFi(x0)]表示新增感染者, V = [ ∂ V i ( x 0 ) ∂ x j ] V=\left[\frac{\partial V_i(x_0)}{\partial x_j}\right] V=[xjVi(x0)]表示感染者的区间传播。

    3 模型实现

    编码采用R语言,对于SIR系列的建模,R语言中有现成的软件包:SimInf。为了展示数据的迭代过程,这里并不打算直接采用。

    3.1 参数设定

    结合当前实际情况,有如下设定:

    • N,以武汉为中心的辐射人口:19 000 000。
    • μ \mu μ, 患病死亡率:0.02。
    • I 0 I_0 I0,期初患病人数:1。
    • β γ \frac{\beta}{\gamma} γβ, 2.68。

    3.2 SIR

    library(deSolve) 
    library(ggplot2)
    

    (1)模型

    基于如下微分方程组构建模型
    d s d t = − β s i d i d t = β s i − γ i d r d t = γ i \begin{aligned} & \frac{ds}{dt} = -\beta s i \\ & \frac{di}{dt} = \beta s i -\gamma i \\ & \frac{dr}{dt} = \gamma i \end{aligned} dtds=βsidtdi=βsiγidtdr=γi

    sir <- function(time, state, pars) {
      with(as.list(c(state, pars)), {
        dS <- -beta * S * I/N
        dI <- beta * S * I/N - gamma * I
        dR <- gamma * I
        return(list(c(dS, dI, dR)))
      })
    }
    

    (2)参数

    N <- 1.9e8 # 总人口
    I0 <- 1 # 初始感染者数量
    RM0 <- 0 # 初始移除人员数量
    S0 <- N - I0 - RM0 # 初始易感人群数量
    init <- c(S = S0, I = I0, R = RM0) # 初始值
    # 以下参数在模型假定下是常量
    pars <- c(
      beta = 0.55, # 有效接触率
      gamma = 0.2, # 移除率
      N = N # 人口
      ) 
    # 迭代次数,以天计
    times <- seq(0, 150, by = 1) 
    

    (3)计算

    res <- as.data.frame(ode(y = init, times = times, func = sir, parms = pars))
    

    (4)绘图

    ggplot(res) +
      geom_line(aes(x = time, y = S, col = '易感'))+
      geom_line(aes(x = time, y = I, col = '感染'))+
      geom_line(aes(x = time, y = R, col = '移除'))+
      theme_light(base_family = 'Kai') +
      scale_colour_manual("",
      values=c("易感" = "cornflowerblue", "感染" = "darkred", "移除" = "forestgreen")
      ) +
      scale_y_continuous('')
    
    

    在这里插入图片描述

    3.3 SEIR

    (1)模型

    基于如下微分方程组构建模型
    d s d t = − β S I N d e d t = β S I N − k E d I d t = k E − ( γ + μ ) I R d t = γ I \begin{aligned} \frac{ds}{dt} &= -\beta S \frac{I}{N} \\ \frac{de}{dt} &= \beta S \frac{I}{N}-k E \\ \frac{dI}{dt} &=k E-(\gamma+\mu) I \\ \frac{R}{dt} &=\gamma I \end{aligned} dtdsdtdedtdIdtR=βSNI=βSNIkE=kE(γ+μ)I=γI

    seir<-function(time, state, pars){ 
      with(as.list(c(state, pars)),{ 
        dS <-- S * beta * I/N 
        dE <- S * beta * I/N - E * k 
        dI <- E * k - I * (mu + gamma) 
        dR <- I * gamma
        dN <- dS + dE + dI + dR 
        
        list(c(dS,dE,dI,dR,dN)) 
      }) 
    } 
    

    (2)参数

    N <- 1.9E8 # 总人口
    I0 <- 89 # 期初感染数
    E0 <- 0 # 期初潜伏数
    RM0 <- 0 # 期初移除数
    S0 = N - I0 - RM0 # 期初易感人数
    init<-c(S = S0, E = E0, I = I0, R = RM0, N = N)	
    time <- seq(0, 150, 1) 
    pars<-c( 
      beta = 0.55,	#有效接触率
      k = 1,	#潜伏到感染的转化率 
      gamma = 0.2,	#RECOVERY 
      mu=0.02	#感染期死亡率 
    ) 
    

    (3)计算

    res.seir<-as.data.frame(lsoda(y = init, times = time, func = seir, parms = pars)) 
    

    (4)绘图

    ggplot(res.seir) +
      geom_line(aes(x = time, y = S, col = '2 易感'))+
      geom_line(aes(x = time, y = E, col = '3 潜伏'))+
      geom_line(aes(x = time, y = I, col = '4 感染'))+
      geom_line(aes(x = time, y = R, col = '5 移除'))+
      geom_line(aes(x = time, y = N, col = '1 人口'))+
      theme_light(base_family = 'Kai') +
      scale_colour_manual("",
      values=c(
        "2 易感" = "cornflowerblue", "3 潜伏" = "orange",
        "4 感染" = "darkred", "5 移除" = "forestgreen", 
        "1 人口" = "black"
        )
      ) +
      scale_y_continuous('')
    
    

    在这里插入图片描述

    3.4 小结

    对比SIR和SEIR模型的结果,可以看到,相同条件下具有潜伏期的疾病其感染人数峰值的到来要晚于没有潜伏期的疾病,并且持续时间更长。

    参考文献

    1. Joseph T Wu*, Kathy Leung*, Gabriel M Leung. Nowcasting and forecasting the potential domestic and
      international spread of the 2019-nCoV outbreak originating
      in Wuhan, China: a modelling study.Lancet,2020.
    2. Gerardo Chowell.Fitting dynamic models to epidemic outbreaks with quantified uncertainty: A primer for parameter uncertainty, identifiability, and forecasts.Infectious Disease Modelling,2017.
    3. James Holland Jones.Notes On R0.2007.
    展开全文
  • 集合

    千次阅读 多人点赞 2019-04-28 20:25:50
    4.部分集合是有序的,部分集合是无序的 (这里的有序的是存储有序,并不是排序) 5.部分集合是唯一的,部分集合是可重复 (11, 22 ,33, 33, 22) 6.部分集合是可排序的,部分集合是不可排序的 33 44 55 11 -> 11 33 44 ...

    1 Collection

    1 集合概念

    2 集合特点

    1.集合能够对数据进行增加删除修改查询的操作
    2.集合能够存储引用类型,如果是基本类型可以是包装类类型
    3.集合的长度是可变的
    --------------------数据结构------------------------
    4.部分集合是有序的,部分集合是无序的 (这里的有序指的是存储有序,并不是排序)
    5.部分集合是唯一的,部分集合是可重复 (11, 22 ,33, 33, 22)
    6.部分集合是可排序的,部分集合是不可排序的 33 44 55 11 -> 11 33 44 55
    7.部分集合是线程安全的,部分集合是线程不安全 (synchronized)
    集合应该设计成一个类,还是一个框架?
    集合框架应该设计成一个接口,不同的集合的实现不一样,那么效率不一样,
    特点不一样,我们可以自由选取

    数据结构: 数据的存储方式。
    常见的和集合相关的数据结构: 数组,栈,队列,链表,哈希表,二叉树
    存储方式不一样决定了该集合的性能效率不一样

    3 集合的功能

    1.增加功能
    boolean add(E e)
    boolean addAll(Collection<? extends E> c)
    2.删除功能
    void clear()
    boolean remove(Object o)
    boolean removeAll(Collection<?> c)
    3.修改功能
    Iterator iterator()
    Object[] toArray()
    4.查询功能
    Iterator iterator()
    Object[] toArray()
    T[] toArray(T[] a)
    5.获取功能
    int size()
    6.判断功能
    boolean contains(Object o)
    boolean containsAll(Collection<?> c)
    boolean isEmpty()
    7.其他功能
    boolean retainAll(Collection<?> c)
    返回原集合是否发生改变
    改变了返回true
    没改变返回false

    public class CollectionDemo01 {
    	public static void main(String[] args) {
    		Collection c = new ArrayList();
    		c.add("张三");
    		c.add("李四");
    		c.add("王五");
    		c.add("赵六");
    		System.out.println(c); // [张三, 李四, 王五, 赵六]
    		
    		// boolean addAll(Collection c)
    		Collection c2 = new ArrayList(); 
    		c2.add("曹操");
    		c2.add("萨达姆");
    		c2.add("本拉登");
    		c.addAll(c2);
    		
    		System.out.println(c);
    		
    		// boolean remove(Object o) 
    		System.out.println("remove: " + c.remove("张三"));
    		System.out.println(c);
    		// boolean removeAll(Collection<?> c) 
    //		System.out.println("removeAll: " + c.removeAll(c2));
    //		System.out.println(c);
    		
    		// void clear() 
    //		c.clear();
    //		System.out.println(c);
    		
    		System.out.println(c.size());
    		
    		System.out.println("contains: " + c.contains("李四"));
    		System.out.println("contains: " + c.contains("曹操"));
    		System.out.println("contains: " + c.contains(""));
    		System.out.println("containsAll: " + c.containsAll(c2));
    		System.out.println("isEmpty: " + c.isEmpty());
    		
    		Collection c3 = new ArrayList();
    //		c3.add("张三");
    //		c3.add("李四");
    //		c3.add("王五");
    //		c3.add("赵六");
    //		c3.add("曹操");
    //		c3.add("萨达姆");
    //		c3.add("本拉登");
    //		c3.add("秦始皇");
    		System.out.println(c);
    		System.out.println(c3);
    		System.out.println("retainAll:" + c.retainAll(c3));
    		System.out.println("c:" + c);
    		
    	}
    
    }
    
    

    4 集合的遍历

    1 iterator 迭代器

    查询功能
    Iterator<E> iterator() 
     	Object[] toArray() 
    遍历 	
     	while (it.hasNext()) {
    		Object oj = it.next();
    		System.out.println(oj);
    	}
    
    public class CollectionDemo02 {
    	public static void main(String[] args) {
    		// Object[] toArray() 
    		Collection c = new ArrayList();
    		c.add("希特勒");
    		c.add("杨贵妃");
    		c.add("貂蝉");
    		c.add("赛西施");
    //		c.add(c);
    //		c.add(100);
    		System.out.println(c);
    //		Object[] objs = c.toArray();
    //		for (Object oj : objs) {
    //			String s = (String) oj;
    //			System.out.println(s);
    //		}
    		
    //		Iterator<E> iterator() 
    //		获取迭代器对象
    		Iterator it = c.iterator();
    		
    //		Object oj = it.next();
    //		System.out.println(oj);
    //		
    //		oj = it.next();
    //		System.out.println(oj);
    //		
    //		oj = it.next();
    //		System.out.println(oj);
    //		
    //		oj = it.next();
    //		System.out.println(oj);
    //		
    //		oj = it.next();
    //		System.out.println(oj);
    		
    		while (it.hasNext()) {
    			Object oj = it.next();
    			System.out.println(oj);
    		}
    		
    	}
    }
    

    2 并发修改异常

    java.util.ConcurrentModificationException
    异常名称:

     并发修改异常
    

    产生原因:

    表示在使用迭代器的同时,使用原集合修改了元素
    

    解决办法:

    		1.只操作原集合,使用原集合修改
    			toArray
    			普通for  如下
    			Object[] objs = c.toArray();
    			for (Object oj : objs) {
    			String s = (String) oj;
    		
    		2.只操作迭代器修改
    			使用ListIterator
    

    注意:

    	foreach遍历集合底层也是使用了迭代器不能够解决并发修改异常
    
    public class CollectionDemo03 {
       public static void main(String[] args) {
       	Collection c = new ArrayList();
       	c.add("希特勒");
       	c.add("杨贵妃");
       	c.add("貂蝉");
       	c.add("赛西施");
       	
    //		Iterator it = c.iterator();
    //		while (it.hasNext()) {
    //			Object oj = it.next();
    //			String s = (String) oj;
    //			if (s.equals("杨贵妃")) {
    //				c.remove("杨贵妃");
    //			}
    //		}
    //		Object[] objs = c.toArray();
    //		for (Object oj : objs) {
    //			String s = (String) oj;
    //			if (s.equals("杨贵妃")) {
    //				c.remove("杨贵妃");
    //			}
    //		}
       	
    //		for (Object oj : c) {
    //			String s = (String) oj;
    //			if (s.equals("杨贵妃")) {
    //				c.remove("杨贵妃");
    //			}
    //		}
       	
    //		for (Iterator iterator = c.iterator(); iterator.hasNext();)
    //		{
    //			Object oj = iterator.next();
    //			String s = (String)oj;
    //			if (s.equals("杨贵妃"))
    //				c.remove("杨贵妃");
    //		}
       	
    //		for(Iterator iterator = c.iterator();iterator.hasNext();) System.out.println(iterator.next());
       		
       }
    }
    

    3 练习

    使用集合存储学生对象,并且去除重复学生, 学生编号相同即为同一个学生

    使用集合存储员工对象 Employee
    1.要求员工对象不能够重复
    2.员工的编号和姓名相同认为是同一个员工
    3.使用至少三种方式遍历集合输出员工的信息
    4.如果员工中存在 隔壁老王,就删除他

    public class CollectionDemo04 {
    	public static void main(String[] args) {
    		// 1.创建容器对象
    		Collection c = new ArrayList();
    		// 2.创建学生元素对象
    		Student s1 = new Student("1001", "张三", 18);
    		Student s2 = new Student("1002", "李四", 18);
    		Student s3 = new Student("1003", "王五", 18);
    		Student s4 = new Student("1003", "王五丰", 18);
    		Student s5 = new Student("1004", "赵六", 18);
    		Student s6 = new Student("1005", "孙七", 18);
    		// 3.将学生存储到集合中
    		c.add(s1);
    		c.add(s2);
    		c.add(s3);
    		c.add(s4);
    		c.add(s5);
    		c.add(s6);
    		c.add("hello");
    		c.add(100);
    		
    		// 遍历集合
    		Iterator it = c.iterator();
    		while (it.hasNext()) {
    			Object oj = it.next();
    			if (oj instanceof Student) {
    				Student s = (Student) oj;
    				System.out.println(s);
    			} else if (oj instanceof String) {
    				String s = (String) oj;
    				System.out.println(s);
    			}
    			
    //			System.out.println(((Student)it.next()).getName() + "|" + ((Student)it.next()).getAge());
    		}
    		
    		// 去除重复元素
    		// 1.创建一个新的集合
    //		Collection c2 = new ArrayList();
    //		// 2.遍历旧集合
    //		for (Object oj : c) {
    //			// 3.判断新集合中是否存在这个元素
    //			if (!c2.contains(oj)) {
    //				// 4.如果新集合中不存在该元素就存储到集合中
    //				c2.add(oj);
    //			}
    //		}
    //		System.out.println("------------------");
    //		// 地址传递
    //		c = c2;
    //		System.out.println("------------------");
    //		for (Object object : c) {
    //			System.out.println(object);
    //		}
    //		
    	}
    }
    
    class Student {
    	private String id;
    	private String name;
    	private Integer age;
    	public Student() {
    		super();
    	}
    	public Student(String id, String name, Integer age) {
    		super();
    		this.id = id;
    		this.name = name;
    		this.age = age;
    	}
    	public String getId() {
    		return id;
    	}
    	public void setId(String id) {
    		this.id = id;
    	}
    	public String getName() {
    		return name;
    	}
    	public void setName(String name) {
    		this.name = name;
    	}
    	public Integer getAge() {
    		return age;
    	}
    	public void setAge(Integer age) {
    		this.age = age;
    	}
    	@Override
    	public String toString() {
    		return "Student [id=" + id + ", name=" + name + ", age=" + age + "]";
    	}
    	
    	@Override
    	public boolean equals(Object obj) {
    		if (this == obj)
    			return true;
    		if (obj == null)
    			return false;
    		if (getClass() != obj.getClass())
    			return false;
    		Student other = (Student) obj;
    		if (id == null) {
    			if (other.id != null)
    				return false;
    		} else if (!id.equals(other.id))
    			return false;
    		return true;
    	}
    }
    

    2 泛型

    1 泛型的引入

    问题一: 安全隐患问题,如果集合存储的是任意类型,那么我们需要对Object的所有子类做判断,显然安全隐患永远存在
    问题一: 就算我们判断了类型,如果新增一个不同类型的元素,那么我们不能遍历完全
    
    没有直接解决方案
    模仿数组和方法
    
    1.数组在编译的时候就必须确定类型,如果确定了类型再存储不同类型会编译报错,不存在类型转换问题
    2.参数化类型
    

    2 泛型的概念:
    泛型属于一种独立的技术,泛型是JDK1.5之后引入的新特性,是一种将元素的数据类型在编译的时候 就确定的类型,
    同时是一种参数化类型,一旦确定类型,泛型相关的类,接口,方法所有的类型都会被统一

    3 泛型的格式
    <E,H,T,K,V>
    1. <>里面可以是任意的字母,一般泛型类会使用E,泛型方法会使用T
    2. 这里只能够定义引用类型,不能够定义基本书类型
    3. <>里面既可以定义一个泛型,也可以定义多个泛型

    4 泛型的分类
    泛型类
    泛型接口
    泛型方法

    5 泛型的好处:
    1. 简化了代码
    2. 取消了黄色警告线
    3. 取消了强制类型转换,提高了程序的效率
    4. 提高了程序的安全性
    5. 提高了程序的扩展性和可维护性,满足了开闭原则【对扩展开放,对修改关闭】

    2 泛型类

    把泛型定义在类上
    泛型接口或者泛型类在使用的时候必须确定类型
    JDK1.5之前没有使用泛型的时候,代码如下:

    public class GernericDemo02 {
    	public static void main(String[] args) {
    		GenericClass gc = new GenericClass();
    		gc.setObj("张三");
    		
    		Object oj = gc.getObj();
    		String s = (String) oj;
    		System.out.println(s + "|" + s.length());
    	}
    }
    
    class GenericClass {
    	private Object obj;
    
    	public Object getObj() {
    		return obj;
    	}
    
    	public void setObj(Object obj) {
    		this.obj = obj;
    	}
    	
    }
    

    以上代码存在安全隐患,如果添加如下代码:

    gc.setObj(10);
    

    会出现类型转换异常,我们可以使用泛型类来改进,继续看如下代码:

    泛型类改进:
    public class GernericDemo02 {
    	public static void main(String[] args) {
    		GenericClass<String> gc = new GenericClass<String>();
    		gc.setE("张三");
    //		gc.setE(10);
    		
    		String s = gc.getE();
    		System.out.println(s + "|" + s.length());
    	}
    }
    
    class GenericClass<E> {
    	private E e;
    
    	public E getE() {
    		return e;
    	}
    
    	public void setE(E e) {
    		this.e = e;
    	}
    }
    

    3泛型接口

    把泛型定义在接口上

    1.泛型接口实现类的方式
    2.泛型接口匿名内部类的方式
    
    泛型接口或者泛型类在使用的时候必须确定类型
    

    泛型接口代码如下:

    interface GenericInterface<E, T> {
    	
    	void test(E e);
    	
    	T add(T t);
    }
    

    泛型接口的使用方式有如下三种:

    1. 实现类确定泛型类型
       // 1.实现类确定泛型类型
       class GenericInterfaceImpl implements GenericInterface<String, Integer> {
       
       	@Override
       	public void test(String e) {
       		System.out.println(e);
       	}
       
       	@Override
       	public Integer add(Integer t) {
       		return t;
       	}
       	
       }
    
    1. 实现类不确定泛型,在调用的时候确定泛型
       // 1 实现类不确定泛型
       class GenericInterfaceImpl<E,T> implements GenericInterface<E, T> {
       
       	@Override
       	public void test(E e) {
       		System.out.println(e);
       	}
       
       	@Override
       	public T add(T t) {
       		return t;
       	}
       	
       }
    
       // 2 在调用的时候确定泛型
       GenericInterface<String, Double> gi = new GenericInterfaceImpl<String, Double>();
       System.out.println(gi.add(2.5));
       gi.test("hello");
    
    1. 匿名内部类确定泛型类型
       GenericInterface<String, Boolean> gi = new GenericInterface<String, Boolean>(){
       
           @Override
           public void test(String e) {
               System.out.println(e);
           }
       
           @Override
           public Boolean add(Boolean t) {
               return t;
           }
       
       };
    

    4 泛型方法

    泛型方法: 把泛型定义在方法上,泛型方法可以理解为局部泛型,独立于泛型类

    泛型方法的特点:

    1. 泛型方法独立于泛型类或者泛型接口
    2. 泛型方法在方法调用的时候确定类型
    3. 一个泛型接口或者泛型类中可以有多个泛型方法
    4. 一个泛型方法也可以定义多个泛型

    泛型方法示例代码如下:

    public class GenericDemo04 {
    	public static void main(String[] args) {
    		GenericMethod<String, Integer> gm = new GenericMethod<String, Integer>();
            // 2.泛型方法在方法调用的时候确定类型
    		gm.show(20.5);
    		
    		Character c = gm.test('c');
    		System.out.println(c);
    		
    		gm.method(25, 2.5);
    	}
    }
    
    class GenericMethod<E,H> {
    	
    	private E e;
    	private H h;
    	
    	// 1.泛型方法独立于泛型类或者泛型接口
    	public <T> void show(T t) {
    		System.out.println(t);
    	}
    	// 3.一个泛型接口或者泛型类中可以有多个泛型方法
    	public <K> K test(K K) {
    		return K;
    	}
    	// 4.一个泛型方法也可以定义多个泛型
    	public <V, U> void method(V v, U u) {
    		System.out.println(v);
    		System.out.println(u);
    	}
    	
    	public E getE() {
    		return e;
    	}
    	public void setE(E e) {
    		this.e = e;
    	}
    	public H getH() {
    		return h;
    	}
    	public void setH(H h) {
    		this.h = h;
    	}
    	
    }
    

    泛型方法的应用:

    大家知道集合Collection中有一个将集合转换成数组的方法,如下所示:

    Object[] toArray();
    

    该方法存在安全隐患,代码如下所示:

    Collection<String> con = new ArrayList<String>();
    con.add("周星驰");
    con.add("成龙");
    con.add("李连杰");
    
    Object[] objs = con.toArray();
    for (Object oj : objs) {
        Integer integer = (Integer) oj;
        System.out.println(integer.intValue());
    }
    

    但是其实该方法也存在着另外一个重载的方法,如下所示:

    <T> T[] toArray(T[] a);
    

    方法的设计者无法知道使用者会往集合中存储何种数据类型,所以将将确定类型的权限交给调用来确定类型,那么我们就可以考虑使用泛型方法,使用泛型方法改进后,代码如下所示:

    Collection<String> con = new ArrayList<String>();
    con.add("周星驰");
    con.add("成龙");
    con.add("李连杰");
    
    // <T> T[] toArray(T[] a); 取消了强制类型转换和安全隐患
    String[] strs = con.toArray(new String[] {});
    for (String s : strs) {
        System.out.println(s);
    }
    

    注:泛型方法在我们写框架的时候应用非常广泛,所以我们有必要掌握它。

    5泛型限定符

    概念: 用来限定泛型的符号
    泛型限定符
    ? : 表示泛型类型可以是任意类型
    ? extends E : 表示泛型类型可以是E或者E的子类
    ? super E : 表示泛型类型可以是E或者E的父类

    public class GenericDemo05 {
    	public static void main(String[] args) {
    		Collection<?> c = new ArrayList<Object>();
    		Collection<?> c2 = new ArrayList<Father>();
    		Collection<?> c3 = new ArrayList<Son>();
    		Collection<?> c4 = new ArrayList<Daughter>();
    		
    //		Collection<? extends Father> c5 = new ArrayList<Object>();
    		Collection<? extends Father> c6 = new ArrayList<Father>();
    		Collection<? extends Father> c7 = new ArrayList<Son>();
    		Collection<? extends Father> c8 = new ArrayList<Daughter>();
    		
    		Collection<? super Father> c9 = new ArrayList<Object>();
    		Collection<? super Father> c10 = new ArrayList<Father>();
    //		Collection<? super Father> c11 = new ArrayList<Son>();
    //		Collection<? super Father> c12 = new ArrayList<Daughter>();
    
    //		boolean addAll(Collection<? extends E> c);
    		/*
    		 * 1.当一个方法需要传入一个接口的时候,实际上希望传入该接口的实现类或者匿名内部类
    		 * 2.当一个方法的泛型是? extends E实际上希望是 E或者E的子类
    		 */
    		Collection<Father> cc = new ArrayList<Father>();
    		cc.addAll(new ArrayList<Son>());
    		cc.addAll(new ArrayList<Daughter>());
    		cc.addAll(new ArrayList<Father>());
    		
    	}
    }
    
    class Father {}
    
    class Son extends Father {}
    
    class Daughter extends Father {}
    

    6 泛型嵌套

    泛型嵌套:泛型中可以包含泛型

    有以下常见几种情况:

    1. Collection嵌套Collection集合
    2. Collection嵌套Map集合
    3. Map嵌套Collection集合

    使用集合存储如下数据
    一个学校有3个班级,每个班级有4个学生

    存储学生到集合中同时遍历集合中的每一个学生
    存储:由内到外
    遍历:由外到内

    public class GenericDemo06 {
    	public static void main(String[] args) {
    		Student s1 = new Student("张三", 18);
    		Student s2 = new Student("李四", 18);
    		Student s3 = new Student("王五", 18);
    		Student s4 = new Student("赵六", 18);
    		List<Student> list = new ArrayList<Student>();
    		list.add(s1);
    		list.add(s2);
    		list.add(s3);
    		list.add(s4);
    		
    		Student s5 = new Student("张三2", 18);
    		Student s6 = new Student("李四2", 18);
    		Student s7 = new Student("王五2", 18);
    		Student s8 = new Student("赵六2", 18);
    		List<Student> list2 = new ArrayList<Student>();
    		list2.add(s5);
    		list2.add(s6);
    		list2.add(s7);
    		list2.add(s8);
    		
    		Student s9 = new Student("张三3", 18);
    		Student s10 = new Student("李四3", 18);
    		List<Student> list3 = new ArrayList<Student>();
    		list3.add(s9);
    		list3.add(s10);
    		
    		List<List<Student>> outList = new ArrayList<List<Student>>();
    		outList.add(list);
    		outList.add(list2);
    		outList.add(list3);
    		
    		// 遍历: 由外到内
    		int index = 1;
    		for (List<Student> innerList : outList) {
    			System.out.println(index + "班");
    			for (Student s : innerList) {
    				System.out.println("\t" + s.getName() + "|" + s.getAge());
    			}
    			index++;
    		}
    		
    	}
    }
    
    class Student {
    	private String name;
    	private Integer age;
    	public Student() {
    		super();
    	}
    	public Student(String name, Integer age) {
    		super();
    		this.name = name;
    		this.age = age;
    	}
    	public String getName() {
    		return name;
    	}
    	public void setName(String name) {
    		this.name = name;
    	}
    	public Integer getAge() {
    		return age;
    	}
    	public void setAge(Integer age) {
    		this.age = age;
    	}
    	@Override
    	public String toString() {
    		return "Student [name=" + name + ", age=" + age + "]";
    		}	
    	}
    

    7 泛型案例

    1. 使用LinkedList模拟栈结构和队列结构 【要求使用泛型】
    2. 使用反射 + 泛型 编写 Map <-> Bean 相互转换的工具类
    3. 使用反射 + 泛型 编写 Map <-> List 相互转换的工具类
    4. 使用 反射 + 泛型 + 注解 实现 数据库的查询 【要求能够查询数据库的单条记录和多条记录】

    3 list接口

    1 Collection将集合划分为两大类:

    1. List集合
    2. Set集合

    List接口的特点:

    1. 有序【存储有序】

    2. 可重复

    3. 可以存储 null

    4. 部分子集合线程安全,部分不安全 例如 ArrayListVector

    5. 有索引,针对每个元素能够方便地查询和修改

    6. 判断元素是否重复依赖于equals方法

      ​ a. 如果元素是系统类,不需要重写equals方法

      ​ b. 如果是自定义类,就需要我们按需求重写 equals方法

      方法:
      添加

       void add(int index, E element)  //在指定 index 索引处理插入元素 element
       boolean addAll(int index, Collection<? extends E> c)  // 在指定 index 索引处理插入集合元素 c
      

      删除

         E remove(int index)  //删除指定索引 index 处的元素
      

      修改

        E set(int index, E element) // 修改指定索引 index 处的元素为 element	
      

      获取

          E get(int index) 获取指定索引处的元素
          
          int indexOf(Object o) 从左往右查找,获取指定元素在集合中的索引,如果元素不存在返回 -1
          
          int lastIndexOf(Object o) 从右往左查找,获取指定元素在集合中的索引,如果元素不存在返回 -1
          
          List<E> subList(int fromIndex, int toIndex) 截取从 fromIndex 开始到 toIndex-1 处的元素
      

      遍历

      E get(int index) + int size() for循环遍历集合中的每一个元素
      ListIterator<E> listIterator() 通过列表迭代器遍历集合中的每一个元素
      ListIterator<E> listIterator(int index) 通过列表迭代器从指定索引处开始正向或者逆向遍历集合中的元素
      
    public class ListDemo01 {
       public static void main(String[] args) {
       	List list = new ArrayList();
       	list.add("疯狂的外星人");
       	list.add("流浪地球");
       	list.add("惊奇队长");
       	list.add("新喜剧之王");
       	System.out.println(list);
       	
       	list.add(1, "绿皮书");
       	System.out.println(list);
       	
       	Object oj = list.remove(1);
       	System.out.println(oj);
       	
       	System.out.println(list);
       	
       	list.set(3, "新喜剧之王2");
       	System.out.println(list);
       	
       	System.out.println(list.get(0));
       	
       	/*
       	 * int indexOf(Object o)  
       	 *  int lastIndexOf(Object o)  
       	 *  List<E> subList(int fromIndex, int toIndex) 
       	 */
       	System.out.println(list.indexOf("流浪地球1"));
       	System.out.println(list.lastIndexOf("流浪地球"));
       	List subList = list.subList(1, 3);
       	System.out.println(list);
       	System.out.println(subList);
       }
    }
    

    2 List接口的遍历

    1 List接口的遍历方式

    1. toArray

    2. Iterator

    3. foreach

    4. 普通for

    5. ListIterator

    2 List接口去除重复元素

    ​ 方式一:创建一个新的集合去除重复元素再使用地址传递

    ​ 方式二:在原集合的基础上使用选择排序思想去除重复元素

    List<String> list = new ArrayList<String>();
    		list.add("张三");
    		list.add("李四");
    		list.add("李四");
    		list.add("李四");
    		list.add("王五");
    
    for (int i = 0; i < list.size(); i++) {
        for (int j = i + 1; j < list.size(); j++) {
            if (list.get(i).equals(list.get(j))) {
                list.remove(j);
                j--;
            }
        }
    }
    

    3 并发修改异常的处理:

    异常名称:并发修改异常 java.util.ConcurrentModificationException

    产生原因:在使用迭代器迭代的同时使用原集合对元素做了修改

    解决办法:

    1. 使用 toArray 方法

    2. 使用 普通 for 遍历

    3. 使用 ListIterator 遍历集合并且使用 列表迭代器修改元素

    3 ArrayList

    1 ArrayList

    概述

    List 接口的大小可变数组的实现。实现了所有可选列表操作,并允许包括 null 在内的所有元素。除了实现
    List 接口外,此类还提供一些方法来操作内部用来存储列表的数组的大小。(此类大致上等同于 Vector类,除了此类是不同步的。)

    特点

    1. 底层数据结构是数组
    2. 增加和删除的效率低,查询和修改的效率高
    3. 能够存储 null 值
    4. 线程不安全,效率高 可以通过 Collections.synchronizedList();变安全
    5. 有索引,能够方便检索
    6. 元素可重复,我们自己可以通过 选择排序去重复
    7. 不可以排序,但是可以通过 Collections.sort();方法排序

    注:ArrayList中常用的方法全部来自于 父类 Collection,List,Object.这里不再做详细叙述。

    public class ArrayListDemo {
       public static void main(String[] args) {
       	ArrayList<String> list = new ArrayList<>();
       	list.add("abc");
       	list.add("efg");
       	list.add("hij");
       	
       	for (String string : list) {
       		System.out.println(string);
       	}
       }
    }
    

    2 Vector

    概述

    Vector 类可以实现可增长的对象数组。与数组一样,它包含可以使用整数索引进行访问的组件。但是,Vector 的大小可以根据需要增大或缩小,以适应创建 Vector 后进行添加或移除项的操作。

    特点

    1. 底层数据结构是数组
    2. 有索引,能够方便检索
    3. 增加和删除的效率低,查询和修改的效率高
    4. 线程安全,效率低
    5. 能够存储 null 值
    6. 元素可重复【我们自己可以通过选择排序思想去除重复元素】
    7. 不可以排序,但是可以通过 Collections.sort();方法排序

    常用方法

    增加

    public synchronized void addElement(E obj) 添加元素 obj 到集合中
    public synchronized void insertElementAt(E obj, int index) 在指定索引 index 处插入元素 obj
    

    删除

    public synchronized void removeElementAt(int index) 移除指定索引 index 处的元素
    public synchronized void removeAllElements() 移除所有元素
    

    修改

    public synchronized void setElementAt(E obj, int index) 修改指定索引 index 的元素为 obj
    

    遍历

    public synchronized E elementAt(int index) + size() for循环遍历集合中的所有元素
    public synchronized Enumeration<E> elements() 使用 Enumeration 迭代器遍历集合中的元素
    

    获取

    public synchronized E firstElement() 获取集合中的第一个元素
    public synchronized E lastElement() 获取集合中的最后一个元素
    public synchronized E elementAt(int index) 获取指定索引 index 的元素
    

    相关面试题

    ArrayList和Vector的区别?
    1Vector的方法都是同步的(Synchronized),是线程安全的(thread-safe),而ArrayList的方法不是,由于线程的同步必然要影响性能,因此,ArrayList的性能比Vector好。 
    2) 当Vector或ArrayList中的元素超过它的初始大小时,Vector会将它的容量翻倍,而ArrayList只增加50%的大小,这样,ArrayList就有利于节约内存空间。
    

    ArrayList 和 Vector的区别

    public class VectorDemo {
    	public static void main(String[] args) {
    		Vector<String> v = new Vector<String>();
    		v.addElement("abc");
    		v.addElement("efg");
    		v.addElement("hij");
    		
    		Enumeration<String> e = v.elements();
    		while (e.hasMoreElements()) {
    			String element = e.nextElement();
    			System.out.println(element);
    		}
    		
    		System.out.println("=================");
    		
    		for (int i = 0; i < v.size(); i++) {
    			String element = v.elementAt(i);
    			System.out.println(element);
    		}
    	}
    }
    

    3 Stack

    概述

    Stack 类表示后进先出(LIFO)的对象堆栈。它通过五个操作对类 Vector 进行了扩展 ,允许将向量视为堆栈。它提供了通常的 pushpop 操作,以及取堆栈顶点的 peek 方法、测试堆栈是否为空的 empty 方法、在堆栈中查找项并确定到堆栈顶距离的 search 方法。

    特点

    1. 基于栈结构的集合,先进后出
    2. Stack 类是 Vector类的子类,所以该类也是线程安全的,效率低,建议使用 Deque接口的实现类

    常用方法
    E push(E item) 将元素压入栈底
    E pop() 将元素从栈结构中弹出,并作为此函数的值返回该对象,此方法会影响栈结构的大小
    E peek() 查看堆栈顶部的对象,但不从栈中移除它。
    boolean empty() 测试栈是否为空。
    int search(Object o) 返回对象在栈中的位置,以 1 为基数。

    注:如果栈中元素为空,再尝试弹栈,将会抛出 EmptyStackException 异常, 而不是 NoSuchElementException

    **示例代码

    Stack<String> stack = new Stack<>();
    // 压栈
    stack.push("A");
    stack.push("B");
    stack.push("C");
    
    while (!stack.isEmpty()) {
        System.out.println("栈顶元素:" + stack.peek());
        // 弹栈
        System.out.println("弹出栈顶元素:" + stack.pop());
    }
    

    4 Queue

    1 Queue

    概述

    在处理元素前用于保存元素的 collection。除了基本的 Collection 操作外,队列还提供其他的插入、提取和检查操作。每个方法都存在两种形式:一种抛出异常(操作失败时),另一种返回一个特殊值(null
    false,具体取决于操作)。插入操作的后一种形式是用于专门为有容量限制的 Queue 实现设计的;在大多数实现中,插入操作不会失败。

    特点

    1. Deque是一个Queue的子接口,是一个双端队列,支持在两端插入和移除元素
    2. deque支持索引值直接存取。
    3. Deque头部和尾部添加或移除元素都非常快速。但是在中部安插元素或移除元素比较费时。
    4. 插入、删除、获取操作支持两种形式:快速失败和返回nulltrue/false
    5. 不推荐插入null元素,null作为特定返回值表示队列为空

    常用方法

    1 ,boolean add(E e)
    将指定的元素插入此队列(如果立即可行且不会违反容量限制),在成功时返回 true,如果当前没有可用的空间,则抛出 IllegalStateException。

    2, E element()
    获取,但是不移除此队列的头。

    3, boolean offer(E e)
    将指定的元素插入此队列(如果立即可行且不会违反容量限制),当使用有容量限制的队列时,此方法通常要优于 add(E),后者可能无法插入元素,而只是抛出一个异常。

    4,E peek()
    获取但不移除此队列的头;如果此队列为空,则返回 null。

    5, E poll()
    获取并移除此队列的头,如果此队列为空,则返回 null。

    6,E remove()
    获取并移除此队列的头。

    public class QueueDemo {
    	public static void main(String[] args) {
    		Queue<String> queue = new ArrayDeque<>();
    		queue.offer("abc");
    		queue.offer("efg");
    		queue.offer("hij");
    		
    //		for (String s : queue) {
    //			System.out.println(s);
    //		}
    		
    //		String s = queue.poll();
    //		System.out.println(s);
    //		
    //		s = queue.poll();
    //		System.out.println(s);
    //		
    //		s = queue.poll();
    //		System.out.println(s);
    //		
    //		s = queue.poll();
    //		System.out.println(s);
    		
    		while (!queue.isEmpty()) {
    			System.out.println(queue.poll());
    		}
    		
    	}
    }
    

    2双端列操作(Deque)

    具备了 Queue 接口的方法 如下

     抛出异常          	           返回特殊值 
    插入 add(e) 	                offer(e) 
    移除 remove()                    poll() 
    检查 element()                   peek() 
    

    同时有自己的双端队列方法

    第一个元素(头部)最后一个元素(尾部)
    抛出异常特殊值抛出异常特殊值
    插入addFirst(e)offerFirst(e)addLast(e)offerLast(e)
    移除removeFirst()pollFirst()removeLast()pollLast()
    检查getFirst()peekFirst()getLast()peekLast()

    双向队列操作

    插入元素

    • addFirst(): 向队头插入元素,如果元素为null,则发生空指针异常
    • addLast(): 向队尾插入元素,如果为空,则发生空指针异常
    • offerFirst(): 向队头插入元素,如果插入成功返回true,否则返回false
    • offerLast(): 向队尾插入元素,如果插入成功返回true,否则返回false

    移除元素

    • removeFirst(): 返回并移除队头元素,如果该元素是null,则发生NoSuchElementException
    • removeLast(): 返回并移除队尾元素,如果该元素是null,则发生NoSuchElementException
    • pollFirst(): 返回并移除队头元素,如果队列无元素,则返回null
    • pollLast(): 返回并移除队尾元素,如果队列无元素,则返回null

    获取元素

    • getFirst(): 获取队头元素但不移除,如果队列无元素,则发生NoSuchElementException
    • getLast(): 获取队尾元素但不移除,如果队列无元素,则发生NoSuchElementException
    • peekFirst(): 获取队头元素但不移除,如果队列无元素,则返回null
    • peekLast(): 获取队尾元素但不移除,如果队列无元素,则返回null

    栈操作

    pop(): 弹出栈中元素,也就是返回并移除队头元素,等价于removeFirst(),如果队列无元素,则发生NoSuchElementException

    push(): 向栈中压入元素,也就是向队头增加元素,等价于addFirst(),如果元素为null,则发生NoSuchElementException,如果栈空间受到限制,则发生IllegalStateException

    引用场景

    1. 满足FIFO场景时
    2. 满足LIFO场景时,曾经在解析XML按标签时使用过栈这种数据结构,但是却选择Stack类,如果在进行栈选型时,更推荐使用Deque类,应为Stack是线程同步

    同时还有Stack结构的方法

    push(e)     addFirst(e) 
    pop()   	removeFirst() 
    peek() 	    peekFirst() 
    
     public class DequeDemo {
    	public static void main(String[] args) {
    		Deque<String> deque = new ArrayDeque<>();
    //		deque.addFirst("Hello");
    //		deque.addFirst("World");
    //		deque.addFirst("Java");
    		
    //		deque.addLast("Hello");
    //		deque.addLast("World");
    //		deque.addLast("Java");
    //		
    //		System.out.println(deque);
    		
    		deque.push("A");
    		deque.push("B");
    		deque.push("C");
    		
    		while (!deque.isEmpty()) {
    			System.out.println(deque.pop());
    		}
    	}
    }
    

    3 ArrayDeque

    概述

    Deque 接口的大小可变数组的实现。数组双端队列没有容量限制;它们可根据需要增加以支持使用。它们不是线程安全的;在没有外部同步时,它们不支持多个线程的并发访问。禁止 null 元素。此类很可能在用作堆栈时快于 Stack,在用作队列时快于 LinkedList

    特点:
    1.基于数组实现的双端队列
    2.数组双端队列没有容量限制
    3.线程不安全效率高
    4.此类很可能在用作堆栈时快于 Stack,在用作队列时快于 LinkedList。

    4 LinkedList

    LinkedList类
    1.基于链表实现的双端队列实现
    2.数组双端队列没有容量限制
    3.线程不安全效率高
    4.如果增加和删除操作比较多,可以优先选择此类,如果查询和修改操作比较多,可以使用ArrayDeque

    使用LinkedList模拟栈结构和队列结构

    后期发现 TreeSet底层就是TreeMap的实现

    5 Set接口

    1 Set接口的特点:

    1.无序 【存储无序】
    

    2.唯一
    3.可以存储null值,但是null不能重复

    public class SetDemo01 {
       public static void main(String[] args) {
       	Set<String> set = new HashSet<>();
       	
       	set.add("ab");
       	set.add("ac");
       	set.add("ba");
       	set.add("bc");
       	
       	System.out.println(set);
       }
    }
    

    2 HashSet

    1 HashSet底层数据结构是哈希表
    1.为什么hashset能够保证元素唯一? – 依赖于 hashCode 和 equals 方法
    2.为什么是无序的? – 因为 对象的 hashCode的值和哈希表存储的索引有关,hashCode是相对随机的,所以是无序的
    3.为什么除了第一次运行,每次结果都是一样的?

    需要了解 HashSet集合是如何存储?
    集合存储方式依赖于 数据结构

    **HashMap **
    哈希算法
    1.哈希算法和对象本身有关
    2.哈希算法返回的是一个整数值
    3.哈希算法和传入的对象本身的hashCode有关
    4.哈希算法返回的整数值就是作为哈希表的索引存储到对应的位置

    public class HashSetDemo01 {
    	public static void main(String[] args) {
    		HashSet<String> hs = new HashSet<>();
    		hs.add("张三");
    		hs.add("李四");
    		hs.add("李四");
    		hs.add("王五");
    		
    		System.out.println(hs);
    		
    	}
    }
    

    **2 LinkedHashSet **
    底层数据结构是链表 + 哈希表
    链表保证元素有序
    哈希表保证元素唯一

    public class LinkedHashSetDemo {
    	public static void main(String[] args) {
    		LinkedHashSet<String> lhs = new LinkedHashSet<>();
    		lhs.add("AFAF");
    		lhs.add("BDAD");
    		lhs.add("CDAD");
    		lhs.add("DFDS");
    		lhs.add("DFDS");
    		lhs.add("QE");
    		for (String s : lhs) {
    			System.out.println(s);
    		}
    	}
    }
    

    3 TreeSet

    TreeSet特点
    1.无序
    2.唯一
    3.可排序
    4.线程不安全的,效率高
    5.可以存储null值
    6.底层数据结构是二叉树

    a.为什么二叉树结构能够去除重复元素?
    b.如何保证元素可排序?
    1.TreeSet是如何保证元素唯一?
    2.TreeSet是如何保证元素可排序的?

    public class TreeSetDemo01 {
    	public static void main(String[] args) {
    		TreeSet<Integer> ts = new TreeSet<>();
    		ts.add(40);
    		ts.add(38);
    		ts.add(43);
    		ts.add(42);
    		ts.add(37);
    		ts.add(44);
    		ts.add(39);
    		ts.add(38);
    		ts.add(44);
    		
    		for (Integer i : ts) {
    			System.out.println(i);
    		}
    	}
    }
    

    排序
    1.TreeSet的排序方式有两种: 自然排序和比较器排序
    2.具体使用哪种排序方式,取决于构造方法,无参构造方法就是自然排序,带Comparator接口的构造方法就是比较器排序
    3.如果同时使用自然排序和比较器排序,比较器排序优先

    public class TreeSetDemo03 {
    	public static void main(String[] args) {
    //		TreeSet<Student> ts = new TreeSet<Student>();
    //		TreeSet<Student> ts = new TreeSet<>(new MyComparatorImpl());
    //		匿名内部类的方式
    		TreeSet<Student> ts = new TreeSet<>(new Comparator<Student>() {
    			@Override
    			public int compare(Student s1, Student s2) {
    				System.out.println("我是比较器排序");
    				Collator c = Collator.getInstance(Locale.CHINESE);
    				// 年龄相等,按照姓名排序
    				int cmp = s1.getAge() - s2.getAge();
    				int cmp2 = (cmp == 0) ? c.compare(s1.getName(), s2.getName()) : cmp;
    				return cmp2;
    			}
    		});
    		ts.add(new Student("张三", 18));
    		ts.add(new Student("张三", 18));
    		ts.add(new Student("李四", 20));
    		ts.add(new Student("王五", 22));
    		ts.add(new Student("赵六", 18));
    		ts.add(new Student("孙七", 18));
    		ts.add(new Student("孙七", 18));
    		ts.add(new Student("孙哈", 18));
    		ts.add(new Student("钱八", 19));
    		ts.add(new Student("周九", 18));
    		ts.add(new Student("周拔", 18));
    		ts.add(new Student("周啊", 18));
    		ts.add(new Student("刘十", 18));
    		ts.add(new Student("双十一", 15));
    		
    		for (Student student : ts) {
    			System.out.println(student);
    		}
    	}
    }
    
    class MyComparatorImpl implements Comparator<Student> {
    
    	@Override
    	public int compare(Student s1, Student s2) {
    		Collator c = Collator.getInstance(Locale.CHINESE);
    		// 年龄相等,按照姓名排序
    		int cmp = s1.getAge() - s2.getAge();
    		int cmp2 = (cmp == 0) ? c.compare(s1.getName(), s2.getName()) : cmp;
    		return cmp2;
    	}
    }
    

    6 map

    collection 单列集合

    1 map 双列集合

    1 Map的特点:

    1.Map设计为一个接口
    2.Map针对的是键和值有一定的映射关系
    3.键应该是唯一的,无序的,类似于Set接口
    4.值应该是可重复,类似于Collection
    5.Map也应该具备集合应该有的方法
    6.值的顺序取决于键的顺序,map的数据结构完全取决于键的数据结构,与值无关

    2 map方法

    添加
    V put(K key, V value) 
    void putAll(Map<? extends K,? extends V> m) 
    删除
    V remove(Object key) 
    void clear() 
    修改
    V put(K key, V value)
    遍历
    get(Object key)
    Set<K> keySet() 
    Set<Map.Entry<K,V>> entrySet() 
    判断
    boolean containsKey(Object key) 
    boolean containsValue(Object value) 
    boolean isEmpty() 
    获取
    get(Object key)
    Set<K> keySet()
    Collection<V> values() 
    int size() 
    static interface Map.Entry<K,V> 
    K getKey();
    V getValue();
    V setValue(V value);
    

    示例如下

    public class MapDemo01 {
       public static void main(String[] args) {
       	Map<String, String> map = new HashMap<String, String>();
       	map.put("文章", "姚笛");
       	map.put("文章", "马伊琍");
       	map.put("陈羽凡", "白百何");
       	map.put("王宝强", "马蓉");
       	map.put("汪峰", "章子怡");
    //		System.out.println(map);
    //		System.out.println("put:" + map.put("文章", "姚笛"));// null
    //		System.out.println("put:" + map.put("文章", "马伊琍"));// 姚笛
       	System.out.println(map);
       	
       	System.out.println("remove:" + map.remove("文章"));
       	System.out.println(map);
       	
    //		map.clear();
       	System.out.println(map);
       	
       	System.out.println(map.size());
       	
       	System.out.println(map.isEmpty());
       	
       	/*
       	 * boolean containsKey(Object key) 
       	 * boolean containsValue(Object value) 
       	 */
       	System.out.println("containsKey:" + map.containsKey("汪峰"));
       	System.out.println("containsValue:" + map.containsValue("章子怡1"));
       	/*
       	 *  get(Object key)
       	 *  Set<K> keySet()
       	 *  Collection<V> values() 
       	 *  int size() 
       	 */
       	System.out.println("get: " + map.get("汪峰1"));
       	
       	// 获取键的集合
       	Set<String> keys = map.keySet();
       	for (String key : keys) {
       		System.out.println(key);
       	}
       	
       	// Collection<V> values()
       	Collection<String> values = map.values();
       	for (String value : values) {
       		System.out.println(value);
       	}
       	
       }
    }
    

    3 map 的遍历方式

    Map的遍历方式
    方式1:根据Key查找Value Set set = map.keySet()

    	获取所有Key的集合 
    	遍历Key的集合,获取到每一个Key 
    	根据Key查找Value
    

    示例如下

    public class MapDemo02 {
    	public static void main(String[] args) {
    		Map<String, String> map = new HashMap<String, String>();
    		map.put("文章", "姚笛");
    		map.put("文章", "马伊琍");
    		map.put("陈羽凡", "白百何");
    		map.put("王宝强", "马蓉");
    		map.put("汪峰", "章子怡");
    //		// 获取键的集合
    //		Set<String> keys = map.keySet();
    //		// 遍历键的集合获取到每一个键
    //		for (String key : keys) {
    //			// 通过键找值
    //			String value = map.get(key);
    //			System.out.println(key + "=" + value);
    //		}
    		
    		// 获取键的集合
    		// 遍历键的集合获取到每一个键
    		for (String key : map.keySet()) {
    			// 通过键找值
    			System.out.println(key + "=" + map.get(key));
    		}
    		
    		System.out.println("=====================");
    		// 方式二: 通过键值对分别找键找值
    		// Set<Map.Entry<K,V>> entrySet() 
    //		Set<Entry<String, String>> keyValues = map.entrySet();
    		for (Entry<String, String> keyValue : map.entrySet()) {
    			System.out.println(keyValue.getKey() + "=" + keyValue.getValue());
    		}
    		
    		System.out.println("=====================");
    		//方式三
    		Set<String> keys = map.keySet();
    		Iterator<String> it = keys.iterator();
    		while (it.hasNext()) {
    			String key = it.next();
    			String value = map.get(key);
    			System.out.println(key + "=" + value);
    		}
    		
    		System.out.println("=====================");
    		//方式四
    		Set<Entry<String, String>> keyValues = map.entrySet();
    		Iterator<Entry<String, String>> iterator = keyValues.iterator();
    		while (iterator.hasNext()) {
    			Entry<String, String> keyValue = iterator.next();
    			System.out.println(keyValue.getKey() + "=" + keyValue.getValue());
    		}
    		
    		System.out.println("=====================");
    		System.out.println(map);
    		
    	}
    }
    

    2HashMap

    HashMap 底层数据结构仅对键有效,数据结构是哈希表
    哈希表原理:
    如何保证无序?
    依赖的是哈希算法,因为哈希算法返回的整数值和对象本身有关,
    也和对象本身的hashCode有关,所以这个哈希值作为索引存储在哈希表就是随机无序的
    如何保证唯?
    首先判断两个对象hashCode是否相等
    相等
    判断两个对象的equals方法是否相等
    相等
    重复元素,不存储到哈希表中
    不相等
    存储到哈希表中
    不相等
    不存储到哈希表中

    示例如下

    /*
     *	去重复元素
     * 学生id			姓名		年龄 		成绩
     * 2018050401	张三		18		80.0
     * 2018050402	李四		20		85.0
     * 2018050403	李四		21		89.0
     * 2018050404	王五		21		89.0
     * Set<Student>
     * Map<String, Student>
     */
    public class HashMapDemo01 {
    	public static void main(String[] args) {
    		HashMap<String, Student> hm = new HashMap<>();
    		hm.put("2018050401", new Student("2018050401", "张三", 18, 80.0));
    		hm.put("2018050402", new Student("2018050402", "李四", 20, 85.0));
    		hm.put("2018050402", new Student("2018050402", "李四", 20, 85.0));
    		hm.put("2018050403", new Student("2018050403", "李四", 21, 89.0));
    		hm.put("2018050404", new Student("2018050404", "王五", 21, 89.0));
    		
    		Set<String> keys = hm.keySet();
    		for (String key : keys) {
    			Student s = hm.get(key);
    			System.out.println(key + "=" + s);
    		}		
    	}
    }
    

    3 TreeMap

    基于红黑树(Red-Black tree)的 NavigableMap 实现。
    该映射根据其键的自然顺序进行排序,或者根据创建映射时提供的 Comparator 进行排序,具体取决于使用的构造方法。

    特点:
    键可排序,唯一,
    值可重复
    底层数据结构是自平衡的二叉树,可排序
    排序方式类似于TreeSet,分为自然排序和比较器排序,具体取决于使用的构造方法

    示例如下

    public class TreeMapDemo02 {
    	public static void main(String[] args) {
    		TreeMap<Student, String> tm = new TreeMap<>(new Comparator<Student>() {
    
    			@Override
    			public int compare(Student s1, Student s2) {
    				Collator c = Collator.getInstance(Locale.CHINESE);
    				// 学号 姓名 年龄 成绩
    				int cmp = s1.getId().compareTo(s2.getId());
    				int cmp2 = (cmp == 0) ? c.compare(s1.getName(), s2.getName()): cmp;
    				int cmp3 = (cmp2 == 0) ? s1.getAge() - s2.getAge() : cmp2;
    				double cmp4 = (cmp3 == 0) ? s1.getScore() - s2.getScore() : cmp3;
    				return cmp4 > 0 ? 1 : (cmp4 == 0 ? 0: -1);
    			}
    		});
    		tm.put(new Student("1001", "隔壁老王1", 30, 80.0), "哈哈2");
    		tm.put(new Student("1002", "隔壁老王2", 60, 80.0), "哈哈4");
    		tm.put(new Student("1003", "隔壁老王3", 30, 780.0), "哈哈4235");
    		tm.put(new Student("1009", "隔壁老王4", 30, 50.0), "哈哈6");
    		tm.put(new Student("1009", "隔壁老王4", 30, 50.0), "哈哈6");
    		tm.put(new Student("1009", "隔壁老王", 30, 40.0), "哈哈6");
    		tm.put(new Student("1009", "隔壁老王", 30, 50.0), "哈哈6");
    				
    		Set<Entry<Student, String>> keyValues = tm.entrySet();
    		for (Entry<Student, String> keyValue : keyValues) {
    			Student stu = keyValue.getKey();
    			String s = keyValue.getValue();
    			System.out.println(stu + "=" + s);
    		}		
    	}
    }
    

    4 Hashtable

    底层数据结构也是哈希表和HashMap是完全兼容的
    但是 Hashtable是线程安全的,效率低,不可以存储null值,null键

    public class HashtableDemo {
    	public static void main(String[] args) {
    		Hashtable<String, String> table = new Hashtable<>();
    		table.put("hello", "231");
    		table.put("world", "231");
    		table.put("java", "231");
    		table.put("hello", "231");
    		table.put("hello", "231");
    //		table.put(null, "313");
    		table.put("32131", null);
    		
    		System.out.println(table);
    		
    	}
    }
    

    5 LinkedHashMap

    Map 接口的哈希表和链接列表实现,具有可预知的迭代顺序
    特点:
    键有序,唯一,
    值有序,可重复,类似于List
    底层数据结构是哈希表和链表,哈希表保证键唯一,链表保证键有序

    public class LinkedHashMapDemo01 {
    	public static void main(String[] args) {
    		LinkedHashMap<String, String> lhm = new LinkedHashMap<>();
    		lhm.put("hello", "dasdada");
    		lhm.put("world", "dasdada");
    		lhm.put("java", "dasdada");
    		lhm.put("andorid", "dasdada");
    		lhm.put("andorid", "dasdada");
    		lhm.put("andorid", "dasdada");
    		System.out.println(lhm);
    	}
    }
    

    6 WeakHashMap

    WeakHashMap类讲解
    示例演示

    public class WeakHashMapDemo {
    	public static void main(String[] args) {
    		WeakHashMap<String, String> whm = new WeakHashMap<>();
    //		whm.put("hello", "12313");
    //		whm.put("world", "12313");
    //		whm.put("java", "12313");
    //		whm.put("hello", "12313");
    		
    		whm.put(new String("hello"), "12313");
    		whm.put(new String("world"), "12313");
    		whm.put(new String("java"), "12313");
    		whm.put(new String("hello"), "12313");
    		whm.put("heihei", "12313");
    		
    		System.gc();
    		System.runFinalization();
    //		try {
    //			Thread.sleep(3000);
    //		} catch (InterruptedException e) {
    //			// TODO Auto-generated catch block
    //			e.printStackTrace();
    //		}
    		System.out.println(whm);
    	}
    }
    

    7 Enum(枚举)

    1 Enum 的概念

    枚举是在一定范围内取值,并且这个值必须是枚举类型中的任意一个,并且只能有一个

    枚举的本质就是一个Java类
    枚举是一个类,那么枚举就有构造方法,成员方法,静态方法,静态变量,成员变量,抽象方法,
    但是除了抽象方法,其他的方法都没有意义。

    2Enum的特点

    1.必须在规定范围内取值
    2.这个值只能取一个
    3.这个值可以是规定范围内的任意一个
    4.枚举中所有的成员,必须出现在枚举对象的下面
    5.如果枚举类中有一个成员,那么 枚举对象最后不能省略分号
    6.枚举中构造方法必须私有
    7抽象方法有意义 - 可以用来描述某个枚举成员的信息,提高程序的可读性
    8.枚举也是switch语句中 的常量 形式之一
    switch语句中可以有哪些?
    byte short int char String 枚举

    // Java设计了更简便的方式 枚举
    enum Game4 {
    START, OVER, RUNNING
    }

    public class EnumDemo02 {
    	public static void main(String[] args) {
    		Color c = Color.GREEN;
    //		c.show();
    //		Color.RED.desc();
    
    		switch (c) {
    		case RED:
    			Color.RED.desc();
    			break;
    		case GREEN:
    			Color.GREEN.desc();
    			break;
    		case YELLOW:
    			Color.YELLOW.desc();
    			break;
    
    		default:
    			break;
    		}
    	}
    }
    
    enum Color {
    //抽象方法可以用来描述某个枚举成员的信息
    //匿名内部类
    	RED () {
    
    		@Override
    		public void desc() {
    			System.out.println("我是红色");
    		}
    
    	},
    	GREEN() {
    
    		@Override
    		public void desc() {
    			System.out.println("我是绿色");
    		}
    
    	},
    	YELLOW() {
    		@Override
    		public void desc() {
    			System.out.println("我是黄色");
    		}
    	};
    	public int num;
    	public final static int A = 10;
    
    	private Color() {
    	}
    
    	private Color(int num) {
    		this.num = num;
    	}
    
    	public void show() {
    		System.out.println("show");
    	}
    
    	public abstract void desc();
    }
    

    3 Enum常用方法

    枚举中常用的方法
    String name()
    返回此枚举常量的名称,与其枚举声明中声明的完全相同。
    int ordinal()
    返回此枚举常数的序数(其枚举声明中的位置,其中初始常数的序数为零)。
    static <T extends Enum>
    T valueOf(类 enumType, String name)
    返回具有指定名称的指定枚举类型的枚举常量。
    T valueOf(String name)
    T[] values();

    需求: 实现枚举对象 、 枚举下标、 枚举名称之间的相互转换

    public class EnumDemo03 {
    	public static void main(String[] args) {
    //		method01(TrafficLight.GREEN);
    //		method02("GREEN");
    //		method03(2);
    		
    		TrafficLight t = TrafficLight.valueOf(TrafficLight.class, "GREEN");
    		System.out.println(t);
    	}
    
    	/**
    	 * 已知枚举的下标,获取枚举的名称,枚举的对象
    	 */
    	public static void method03(int index) {
    		// values方法返回枚举数组
    		TrafficLight trafficLight = TrafficLight.values()[index];
    		System.out.println(trafficLight);
    		String name = trafficLight.name();
    		System.out.println(name);
    	}
    
    	/**
    	 * 已知枚举的名称,获取枚举的下标和枚举对象
    	 */
    	public static void method02(String name) {
    		// T valueOf(String name)
    		TrafficLight trafficLight = TrafficLight.valueOf(name);
    		int index = trafficLight.ordinal();
    		System.out.println(trafficLight + ":" + index);
    	}
    
    	/**
    	 * 已知枚举对象,获取枚举的下标和名称
    	 */
    	public static void method01(Enum<TrafficLight> e) {
    		System.out.println(e.ordinal() + ":" + e.name());
    	}
    }
    
    enum TrafficLight{
    	RED, GREEN, YELLOW
    }
    

    4 Enum 练习

    package com.sxt.enumdemo;
    
    /*
     * 使用枚举来描述一个星期多少天
     * 并且要使用switch测试
     * 要求枚举中用抽象方法来描述每一天
     */
    public enum Weekend {
    
    	MONDAY {
    		@Override
    		void desc() {
    			System.out.println("星期一");
    		}
    	},
    	TUESDAY {
    		@Override
    		void desc() {
    			System.out.println("星期二");
    		}
    	},
    	WEDNESDAY {
    		@Override
    		void desc() {
    			System.out.println("星期三");
    		}
    	},
    	THURSDAY {
    		@Override
    		void desc() {
    			System.out.println("星期四");
    		}
    	},
    	FRIDAY {
    		@Override
    		void desc() {
    			System.out.println("星期五");
    		}
    	},
    	SATURDAY {
    		@Override
    		void desc() {
    			System.out.println("星期六");
    		}
    	},
    	SUNDAY {
    		@Override
    		void desc() {
    			System.out.println("星期天");
    		}
    	};
    
    	abstract void desc();
    
    	@Deprecated
    	public static void main(String[] args) {
    		Weekend day = Weekend.SATURDAY;
    		switch (day) {
    		case MONDAY:
    			Weekend.MONDAY.desc();
    			break;
    		case TUESDAY:
    			Weekend.TUESDAY.desc();
    			break;
    		case WEDNESDAY:
    			Weekend.WEDNESDAY.desc();
    			break;
    		case THURSDAY:
    			Weekend.THURSDAY.desc();
    			break;
    		case FRIDAY:
    			Weekend.FRIDAY.desc();
    			break;
    		case SATURDAY:
    			Weekend.SATURDAY.desc();
    			break;
    		case SUNDAY:
    			Weekend.SUNDAY.desc();
    			break;
    
    		default:
    			System.out.println("非法星期");
    			break;
    		}
    
    	}
    }
    
    
    展开全文
  • 测试开发笔记

    万次阅读 多人点赞 2019-11-14 17:11:58
    V模型 9 2.内部测试 10 3外部测试: 10 验收测试:(在系统测试之后) 11 回归测试: 11 4.测试过程(干什么,怎么干) 12 5.各阶段输入、输出标准以及入口、出口准则:(测试阶段过程要素) 1...
  • TensorFlow入门

    千次阅读 多人点赞 2019-04-23 10:09:29
    TensorFlow入门 参考资料: TensorFlow中文社区教程 TENSORFLOW从入门到精通之——TENSORFLOW基本操作 TensorFlow升级到1.0版本的问题 Tensorflow save&restore遇到问题及解决应对 NotFoundError: Key Variable...
  • 【数据库学习】数据库总结

    万次阅读 多人点赞 2018-07-26 13:26:41
    5)关系完整性 在关系模型中,关系完整性主要是以下三方面: 实体完整性 所谓的实体完整性就是关系(所谓的关系就是表)的主码不能取空值; 比如学生表的主码通常是取学号为主码 参照完整性 是参照关系中每个...
  • 数据库面试

    千次阅读 多人点赞 2019-02-13 09:03:42
    持久性Durability,一个事务一旦提交并执行成功,那么对数据库中数据的改变就是永久性的,即便是在数据库系统遇到故障的情况下也不会丢失提交事务的操作。 9. 事务的并发问题?事务的隔离级别有哪些? 事务的并发...
  • python数组的使用

    千次阅读 2018-07-07 12:22:38
    S.find(substring, [start [,end]]) #可范围查找子串,返回索引值,否则返回-1 S.rfind(substring,[start [,end]]) #反向查找 S.index(substring,[start [,end]]) #同find,只是找不到产生ValueError异常 S....
  • C#基础教程-c#实例教程,适合初学者

    万次阅读 多人点赞 2016-08-22 11:13:24
    C:\WINNT\Microsoft.NET\Framework\v1.0.3705\csc welcome.cs 如果一切正常welcome.cs文件将被编译,编译后生成可执行文件Welcome.exe。可以在命令提示符窗口运行可执行文件Welcome.exe,屏幕上出现一行字符提示您...
  • JavaWeb

    千次阅读 多人点赞 2017-12-26 09:09:24
    修改数据库是修改数据库的字符集和校队规则: alter database 数据库名 character set 新字符集 collate 校对规则 切换数据库: use 数据库名 使用sql语句操作数据库中的表(对数据库表的CRUD操作) 创建表: ...
  • Lucene DocValues索引文件详解

    千次阅读 2018-11-29 14:37:55
    解密DocValues索引的存储结构,为何正向索引能给搜索结果再处理带来更多可能性和不一样的体验。由哪里结构完成存储需求,相对FieldCache又有哪些优点?
  • Stata: 空间面板数据模型及Stata实现

    万次阅读 多人点赞 2019-05-10 10:37:56
      作者:游万海 (福州大学) Stata 连享会: 知乎 | 简书 | 码云 | CSDN ...由于面板数据模型所具有的众多优点 (刻画个体异质性,减弱模型共线性和增加自由度等),其被广泛应用于实证计量中。...
  • 2.12 使用字典对象的 items() 方法可以返回字典的“键 - 值对”列表,使用字典对象的 keys() 方法可以返回字典的“键”列表,使用字典对象的 values() 方法可以返回字典的“值”列表。 2.13 假设有列表 a = ...
  • v-for中label和value的问题

    千次阅读 2019-10-22 16:01:22
    :key=“item.id” :label=“item.name”//显示值 :value=“item.id”//传给后台的值
  • : when force or torque data is acquired by the force sensor, then it is accumulated and can be filtered in order to obtain less jittery values. Sample size : the number of values that should be used...
  • uniapp v-show v-for

    千次阅读 2019-04-11 16:46:07
    v-for="(value, index, key) in listData" value值 key值键 index数组 bug 不能再相互嵌套的时候,同时弄for,否则部分功能失效 <view v-for="(value, ...view v-for="(values, indexs, keys) in list">...
  • 另附: 查询字符集:select * from v$nls_parameters t where t.PARAMETER='NLS_CHARACTERSET'; Length与LengthB比较 lengthb(string)计算string所占的字节长度 length(string)计算string所占的字符长度 MySql 5.X ...
  • Android 8.0适配

    万次阅读 2018-07-09 09:44:43
    Android 8.0适配北 Android 9.0 适配指南 又到了7月,这是我一年一度的写适配文章的时间,今年到了安卓8.0。为什么我会总会选在这个时间点,因为国内的手机升级总是慢一拍,还有好多的新特性可能也不...
  • v$database:数据库的信息,如数据库名,创建时间等。 v$instance 实例信息,如实例名,启动时间。 v$parameter 参数信息,select * from v$parameter where name like '%name' ----> show parameter name...
  • 全网目前最全python例子(附源码)

    万次阅读 多人点赞 2019-12-30 14:55:05
    values = [ 'Price' ] , aggfunc = np . sum ) 5 Python机器学习 Python机器学习库 Sklearn 功能强大,接口易用,包括数据预处理模块、回归、分类、聚类、降维等。一行代码创建一个KMeans聚类模型: from ...
  • 2020最新PHP面试题(附带答案)

    万次阅读 多人点赞 2020-03-02 16:04:59
    1.什么事面向对象?主要特征是什么? 面向对象是程序的一种设计方式,它利于提高程序的重用性,使程序结构更加清晰。主要特征:封装、继承、多态。 ... ...2.SESSION 与 COOKIE的区别是什么,请从协议,产生的原因与作用...
  • 你知道程序都是怎么处理时区问题的么?

    万次阅读 多人点赞 2021-01-20 21:59:25
    主要看一下缴税和审核接口,分别的对应的SQL语句如下: 缴税 -- 缴税接口的对应的SQL insert into tax_form(tax_id,amount,tax_payer_id,status) values('T001', 1234.56, 'U001', 0) 审核 -- 修改审核状态 update ...
  • python数组使用(超级全面)

    万次阅读 多人点赞 2019-04-18 19:43:46
    1、Python的数组分三种类型: (1) list 普通的链表,初始化后可以通过特定方法动态增加元素。 定义方式:arr = [元素] ...定义方式:arr = {元素k:v} 2、下面具体说明这些数组的使用方法和技巧: (1) lis...
  • 不够的我们用[000000]补上 # vec_size 的是我们本身vector的size def transform_to_matrix(x, padding_size=256, vec_size=128): res = [] for sen in x: matrix = [] for i in range(padding_size): try: matrix....
  • 前言 为啥学习MySQL呢?因为MySQL是最流行的关系...数据库管理系统, 数据库系统中对数据进行管理的软件系统。 让我来整理一张思维导图: 细节掌握: 安装配置,常用命令,操作数据库; 整型与浮点型,日期时间型与
  • 因为DrawerLayout里包含一个ListView作为左边栏侧滑菜单,所以我们需要首先初始化这个抽屉列表,并且为这个列表适配上数据,数据适配器使用的是最简单的ArrayAdapter,模拟数据被简单的定义在res/values/strings.xml...
  • Android截屏的方式:1.获取DecorView截屏通过获取DecorView的方式来实现截屏(前提是当前Activity已经加载完成),DecorView为整个Window界面的最顶层View,因此截屏不包含状态栏(SystemUI)部分. View view = getWindow()...
  • Log Explorer for SQL Server v4.22 含注册机

    热门讨论 2011-11-24 09:36:41
    注意:如果你选中了'Do not restore column values that have been changed by subsequent modifications'项,只对事物1逆转将不会产生任何结果。 自增序列(IDENTITY Property) 如果被删除数据与有IDENTITY ...
  • 从决策树学习谈到贝叶斯分类算法、EM、HMM

    万次阅读 多人点赞 2012-05-17 21:06:53
    (Outlook=Sunny ^Humidity)V (Outlook = Overcast)V (Outlook=Rain ^ Wind=Weak) 1.2、ID3算法 1.2.1、决策树学习之ID3算法  ID3算法是决策树算法的一种。想了解什么是ID3算法之前,我们得先明白一个概念: ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 58,101
精华内容 23,240
关键字:

vvalues指的是