元组

  1. 元组既能像列表那样容纳多种类型的对象,也拥有字符串不可变的特性。

  2. 列表用的是方括号,元组用的是圆括号

  3. 元组可以不带括号。

  4. 元组也可以通过下标来获取元素

  5. 元组的内容不可以被修改

  6. 列表是支持修改的,元组不支持,所以元组只支持count和index方法。

  7. 元组也可以嵌套,嵌套的方式是直接加个逗号。逗号是构成元组的基本条件

  8. 只有列表推导式,没有元组推导式子

  9. 定义元组的时候,与其纠结什么时候加上圆括号,什么时候省略,还不如一直都加上圆括号。这样也有助于增加代码的可读性。

  10. 生成一个元组我们有时候也称为元组的打包

  11. 将元组的元素一次性赋值给三个变量的行为称为解包

  12. 赋值号左边的变量名数量必须和右边序列的元素的数量一致。

  13. python可以实现多重赋值

    >>> x, y = 10 ,20
    >>> x
    10
    >>> y
    20
    

    其实背后的逻辑就是先将元组进行打包,然后再将元组进行解包

    >>> _ = (10, 20)
    >>> x, y = _
    >>> x
    10
    >>> y
    20
    
  14. 元组中的元素是不可变的,但是如果元组中的元素是指向一个可变的列表,那我们依然可以修改列表里面的内容

    >>> s = [1, 2, 3]
    >>> t = [4, 5, 6]
    >>> w = (s, t)
    >>> w
    ([1, 2, 3], [4, 5, 6])
    >>> w[0][0] = 0
    >>> w
    ([0, 2, 3], [4, 5, 6])
    >>> 
    
  15. 如果可能,能用tuple代替list就尽量用tuple代替list

字符串

  1. 字符串归根到底是像元组那样一个不可变的序列。

  2. 字符串有许多方法,封装在内部,是用实现效率更高的C语言来编写的。是属于官方的东西

  3. 大小写字母换来换去:

    capitalize() // 这是将字符串的首字母变成大写,其余字母变成小写。字符串是不可变的对象,调用这个方法也只是按照这个规则生成一个新的字符串
    casefold() // 返回一个所有字母都是小写的新字符串,除了英文字母之外还可以处理其余一些字母
    title() // 将字符串中每个单词的首字母变成大写,该单词的其余字母变成小写
    swapcase() // 将字符串中的所有字母的大小写翻转
    upper() // 将所有的字母都变成大写。
    lower() // 将所有的字母都变成小写。只能处理英文字母。
    
  4. 左中右对齐

    center(width, fillchar = '') // width参数用来指定整个字符串的宽度。如果说指定的宽度小于或等于源字符串,那就直接输出源字符串
    ljust(width, fillchar = '')
    rjust(width, fillchar = '')
    zfill(width)
    
  5. 如果一个变量连续调用多个函数,python是从左往右依次执行。

  6. \n这个转义字符不是一个可打印字符。

  7. format方法支持未知参数和关键词参数两个。如果是综合未知参数和关键字参数一起使用,未知参数必须在关键字参数之前

  8. 冒号表示格式化符号的开始

  9. format方法是字符串格式化的方法, %运算符也是用来格式化字符串的,%会把任何类型转换为字符串。format()方法相比较于%的方法写起来要麻烦一些。

  10. 格式化如果有多个参数的话,用元组的方式将其括起来。

  11. %f可指定小数点的精度

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

  1. 都可以通过索引得到每一个元素
  2. 默认索引值总是从0开始
  3. 可以通过分片的方式得到一个范围内的集合
  4. 有很多共同的操作符。把这三种数据结构统称为序列
  5. 迭代就是重复反馈过程的活动,其目的是接近并达到所需的目标或结果。每一次对过程重复我们称之为迭代。每一次迭代得到的结果,都会被用来作为下一次迭代的初始值。所以迭代可以初步理解为for循环。
  6. 序列天生就是可迭代的对象

内置方法

  1. list()生成空列表,list([iterable]),把一个可迭代对象转换为列表。

    就是新建一个列表,然后通过索引,将括号内元组或者字符串的每个值都插入到列表里。迭代完成再把整个列表返回。

  2. tuple([iterable]),把一个可迭代对象转换为元组

  3. str(obj) 把obj对象转换为字符串。

  4. len(sub),返回参数sub的长度。

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

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

  7. 使用max()方法或者min()方法要保证参数或者序列的数据类型是统一的。

    max = tuple1[0]
    for each in tuple1:
        if each > max:
            max = each
            
    return max
    
  8. sum(iterable[, start = 0])返回序列iterable(元组、列表)和可选参数start的总和

  9. sorted()

函数

  1. 对象,函数,模块是学习python的重点
  2. 函数就是把代码打包成不同功能的代码块,一个程序可以按照不同功能切割成小小的个体,而函数就是可以完成某一个功能的代码块,在python中创建函数用def关键字
  3. python根据函数名找到这个函数,依次执行这个函数内的代码
  4. 如果找不到某个函数而去调用,则会报错
  5. 调用函数只需要一条语句。
  6. 函数的功能和参数的意义一定要写好相应的注释

形参和实参

  1. 形式参数即形参指的是函数创建(定义)的时候小括号中的参数

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

    某个地方调用这个函数,而传递进来的参数叫做实参,因为这个参数是具体的参数值

    def MyFirstFunction(name)

    name是形参

  2. 函数文档和注释不完全一样

    .__doc__ 是函数的特殊属性,能够看到函数文档
    
  3. 关键字参数,调用函数传入参数的时候可以指定关键字。

  4. 默认参数就是在定义的过程中为形参赋初值,当函数调用的时候,如果忘了传递参数,就会自动去找默认值。

  5. 收集参数(可变参数),在形参前面加*号,传多少个参数都可以。原理是把标记为收集参数的参数用一个元组打包起来

  6. 函数是有返回值的,过程是简单的、特殊并且没有返回值的。

  7. python严格来说只有函数,没有过程

  8. 就算python的函数没有返回语句,用print来输出,python也会返回一个None对象

  9. 我们说一个函数是整型的函数,是说这个函数会返回一个整型的函数值。python不这样,python会动态地确定类型,赋值的时候,编译器会自动确定需要什么类型。

    在python里面,一个变量拿来用就行了, 不用去关心它是什么类型。包括返回值也是一样,不用去关注它是什么类型

函数变量的作用域问题

  1. 一般的编程语言都是由局部变量和全局变量
  2. 在函数里定义的参数,以及变量,都叫做局部变量,出了这个函数,这些变量都是无效的。函数外是无法访问到函数内部的变量的
  3. 在函数外边定义的变量叫做全局变量,拥有更大的作用域,它们的作用域是整个代码段。
  4. 如果在函数内试图去修改全局变量的话,那么python会在函数内创建一个新的局部变量代替,这个局部变量和全局变量名称是一样的
  5. 全局变量在整个代码中都是可以访问到的,但是不要试图在函数内部去修改它,可以在函数内部去访问全局变量的值,但是不要试图去修改它,如果试图在函数内部去修改全局变量,python会在函数内部创建一个和全局变量名称一样的局部变量代替。很容易犯错
  6. global关键字,在函数内部修改全局变量

内嵌函数

  1. 也叫做内部函数

  2. python支持函数的嵌套

  3. 内部函数整个作用域,都在外部函数之内

    内部函数的定义和调用,都在外部函数之内

  4. 闭包:如果在一个内部函数里,对外部作用域(但不是在全局作用域)的变量进行引用,内部函数就会被认为是闭包

  5. python可以直接返回函数对象

匿名函数

  1. lambda表达式。冒号左边是原函数的参数,冒号的右边是原函数的返回值
  2. lambda语句返回一个没有名字的函数对象
  3. python写一些执行脚本时,使用lambda就可以省下定义函数过程,使用lambda可以使得代码更加精简
  4. 对于一些比较抽象,并且整个程序执行下来只需要调用一两次的函数,有时候取名比较麻烦,使用lambda就不需要考虑命名的问题
  5. 使用lambda可以简化代码的可读性,普通的函数阅读经常要跳到开头的def定义部分,使用lambda函数可以省去这样的步骤。

两个内置函数

  1. filter(),通过过滤器可以保留我们所关注的信息

  2. filter()有两个参数,第一个参数可以是一个function,也可以是一个none对象,第二个参数是可迭代的数据iterable,如果第一个参数是函数,那么就把第二个参数的每个数据作为函数的输入,把返回结果为true的数据筛选出来

  3. filter()如果第一个参数是None,就是过滤掉0和false

  4. map(),在编程领域,map一般是指映射

  5. map()这个内置函数仍然有两个参数,仍然是一个函数和一个可迭代的序列,将序列的每一个元素作为函数的参数进行加工,直到可迭代的序列的每一个元素都加工完毕,构成一个可迭代的新序列。

  6. 这两个内置函数和java的lambda表达式一样,一个是对可迭代序列的每一个元素进行处理即map(),一个是对可迭代序列对每一个元素进行筛选即过滤,即filter()。

    testList.steam().filter(t -> t.....).map(w -> w...).collect(Collectors.toList()))
    

递归

  1. 定义树结构,使用递归的方式来定义,比普通的方式来定义要方便很多。

  2. 设置递归的深度

    import sys
    sys.setrecursionlimit(1000000)
    
  3. python提供一个range()函数,可以生成一个整数序列。

  4. python的循环有两种,一种是for...in...循环,一次把list或tuple的每个元素迭代出来

    第二种是while循环,只要条件满足,就不断循环,条件不满足时退出循环。

  5. 递归的两个条件

    1. 调用函数自身
    2. 设置自身正确的返回值。设置某个值就返回了。有进去就必须要有返回。递归必须要有一个正确的返回条件
  6. 递归有一个正确的返回值,就像很多数学题,都必须有一个初始值,f(0) = 0之类,实际上是递归的逆过程。

  7. 递归的实现原理是调用自身函数,并且设置有返回值,那每次调用函数,都要进行压栈弹栈,保存和恢复寄存器的栈操作,很消耗时间和空间,如果忘记设置返回,就会使程序崩溃。

  8. 递归在python是有默认限制。

  9. 递归算法是分治思想,把一个复杂问题分成小的问题,把小的问题再继续分。

字典

  1. python的字典把单词称之为key,把单词的含义称之为value

  2. 字典是python唯一的一个映射类型。映射是指两个元素集之间,元素相互对应的关系。通过某种关系进行映射,可以是一对一的关系也可以是一对多的关系

  3. 序列类型是以数组的类型进行存储的,通过索引的方式来取值。一般索引值和对应存储的数据是毫无关系的

  4. 最好是不要通过下标即索引来进行映射。不能通过下标来保证两个序列的元素是一一对应的。

  5. 字典在python里的标志性是大括号,由多个键和对应的值组成。元组的标志是()

  6. dict3 = dict((("F", 2), ("U", 1)))
    

    因为字典的参数只有一个mapping类型即映射类型的参数,通过元素的方式传入这种映射类型的参数就可以,也可以通过列表来传入

  7. 用关键词传入,键不能加引号,如下:

    dict4 = dict(小甲鱼 = "让编程改变世界", a = "b")
    

    key会自动用字符串实现

  8. 字典和序列不一样的是,如果在序列中,试图为一个不存在的位置去赋值的时候会报错,会报越界,如果是在字典中,如果创建的一个键值对的键在原先的字典中存在,则会改变原先的键所对应的value,如果键在原先的字典中不存在,则会自动创建相应的键并添加相应的值进去。

  9. dict()是工厂函数,调用它会生成该类型的一个实例,就像工厂一样。

  10. 遍历字典(像这些内容都在java中有对应的知识):for eachkey in dict1.values(): print(eachkey)

    1. 遍历字典的键
    for eachkey in dict1.keys():
    	print(eachkey)
    2. 遍历字典的value
    for eachkey in dict1.values():
    	print(eachkey)
    3. 遍历整个键值对(在java中即对应map的entrySet)
    for eachItem in dict1.items():
    	print(eachItem)
    
  11. 浅拷贝和赋值是不一样的,赋值是贴了一个不同的标签在相同的数据上

  12. popitem()是随机从字典里弹出一个数据

  13. 字典和java的map一样,不能依赖顺序

集合

  1. {}并不是字典的特权。用{}括起一堆数字,但是这些数字没有映射关系,那他们就是一个集合。
  2. python中的集合和java中的集合不一样。python中集合的元素是唯一的, 而java中的list,map,set都叫集合,只有set才有这个唯一的特性
  3. 集合会直接把重复的数据清理掉,集合是无序的,不能试图去索引集合中的某个元素
  4. python中的集合不支持索引
  5. 如何创建一个集合,有两种方法:
    1. 一种是直接把一堆元素用花括号括起来
    2. 使用set()工厂函数,这个工厂函数可以传列表,元组,字符串,返回的都是集合。
  6. list()这个工厂函数,也可以传入集合,就会返回一个列表
  7. set()创造的集合中的元素是无序的
  8. 如何访问集合中的值:
    1. 可以使用for把集合中的数据一个个读取出来
    2. 可以通过in和not in判断一个元素是否在集合中已经存在

文件

  1. 内存和cpu之间的数据传输速度比硬盘和cpu的数据传输速度快很多。
  2. windows是以扩展名指出文件是什么类型
  3. python和java一样有垃圾收集机制,在python里面如果忘记关闭文件,不会造成内存泄漏。不过要养成使用完文件就要进行关闭的习惯
  4. OS的意思就是操作系统
  5. 不同操作系统的底层对于文件系统的访问工作原理是不一样的
  6. 有了OS模块,我们不需要关心什么操作系统下使用什么模块,OS模块会帮你选择正确的模块并调用
  7. rmdir()是删除目录,应该先把目录里面的文件删掉,然后再删除目录,要确保删除的目录是空的,确保这个目录下面没有其他的子目录,也没有文件
  8. 在Windows和Linux里面用.表示当前目录,用..表示上一级目录
  9. os.sep 输出操作系统特性的路径分隔符(Win下为“\\”, Linux下为“/”)
  10. 每个字节一般是8位。
  11. 数据存储是以字节(Byte)为单位,数据传输大多是以bit为单位,一个位就代表一个0或1,每8个位组成一个字节
  12. 将对象转化为二进制称为pickling,将二进制文件转换为对象称为unpickling

异常处理

  1. 在编程的时候要把用户想象成不会计算机的用户和黑客,要保证自己程序的稳固,不要认为用户的输入都是合法的。

  2. 在python里所有东西包括一个变量名都是一个对象

  3. python的异常后缀都是error(目前看到的)

  4. 异常并不会致命,我们需要捕获这些异常并纠正这些错误

  5. 常见异常:https://fishc.com.cn/thread-45814-1-1.html

  6. 异常检测用try语句实现,任何在try语句范围内的异常都会被检测到

    try:
        检测范围
    except Exception[as reason]:
        出现异常后处理的代码
    
  7. 如果except指定的异常不是try语句代码里抛出的异常,则仍然会报异常。

  8. 如果不清楚是要对哪一类异常进行处理,只是希望try语句里一旦出现异常,就可以捕获并给用户看到对应的信息,(这里的捕获其实就是指捕获到try语句代码块里的异常并进行一个对应的处理),那么就把except后面的内容全部都去掉(只是可以这样做,但是不推荐)

  9. try语句代码块里的语句一旦出现异常,那么剩下的语句就不会被执行,这里和java是一样的

  10. finally里是指无论如何都会被执行的代码

else语句和with语句

  1. else语句还可以和for语句、while语句进行搭配,还可以和异常处理语句进行搭配

  2. 和if语句是构成要么怎样,要么不怎样

    和循环语句是构成干完了能怎样,干不完就别想怎样

    和异常处理语句是构成没有问题,那就干吧

  3. 如果循环语句中使用了break跳出了循环,那么else语句就不会执行

    只有是没有break,没有跳出循环的情况下,循环执行完了,才会执行else里面的代码

  4. 和异常处理语句搭配是只要try语句块里没有出现异常,那么就会执行else语句里的内容

  5. 使用with语句可以大大减少代码量,会自动考虑文件关闭的问题

类和对象

  1. 把乱七八糟的数据都扔到列表里面,这是一种封装,这是数据层面的封装,我们还可以把常用的代码段封装成一个函数,这是语句层面的封装

  2. 对象是模拟真实世界,把数据和代码都封装在一起。

  3. 对象可以从属性和方法(行为)两个方面来描述

  4. 对象 = 属性 + 方法,把静态的特征称为属性,把动态的动作称为方法。但是从另一个角度来说,类是抽象的,是静态的,对象是类的具体,是类的实例化,是动态的。

  5. class Turtle: # Python中的类名约定以大写字母开头,在java中类是一个抽象的东西,应该通过实例化来创建一个具体的对象(对类进行实例化),但是在这个类中,属性和方法都具体地定义了出来
        #---关于类的一个简单例子---#
        # 属性
        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("睡了")
    
            
    这整个代码都是在定义对象看上去是什么样,会做什么,也就是在定义对象的属性以及方法,但是这并不是对象,这充其量称之为类对象
    

    对象是类的实例(instance),有这个类是使得对象可以达到量产的效果。做玩具的时候有一个模具,然后可以进行批量的生产。

  6. python中的类名是以大写字母开头,函数名是以小写字母开头,和java一样

  7. self是什么?当一个对象的方法被调用的时候,对象会将自身作为第一个参数传给self参数

  8. 在类的定义的时候,把self写进第一个参数

  9. __init__(self) 这个方法称之为构造方法,只要实例化一个对象的时候,那么这个方法就会在对象被创建的时候自动调用,实例化对象的时候也是可以传入参数的
    __init__(self, param1, param2...) # 这种情况定义类的时候就要重写__init__方法
    
  10. python里面找不到和java中类似的关键字来区分是公有的还是私有的,默认上来说,对象的属性和方法都是公有的。python为了实现私有的特征,采用了**name mangling(名字改编、名字重整)**的技术

  11. 在Python中定义私有变量,只需要在变量名或函数名前加上“__”两个下划线,那么这个函数或变量就会变成私有的了。

  12. Python目前的私有机制是伪私有机制,python的类是没有权限控制的,变量是可以被外部调用的。

  13. 组合就是把类的实例化放到一个新类里面,那就不用继承了,组合就是把横向关系的几个类放在一起,要实现纵向关系的类的关系,就用继承。

OO的特征

1. 封装

  1. OO(Object Oriented)的特征,python就是一门纯粹的面向对象编程的语言
  2. 对象封装了属性和方法,成为一个独立性很强的模块,封装更是一种信息隐蔽技术,使得数据更加安全。
  3. 列表是python的一个序列对象。(实例化之后的才叫对象,对象是具体的,而类是抽象的),提供了若干种方法, 供我们根据需求来调整列表,但是我们不知道列表对象里面的这些方法是如何实现的,我们也不知道列表对象具有哪些变量。列表是对象,提供方法名字,我们去使用

2. 继承

  1. 继承是子类自动共享父类之间数据和方法的机制。

    class MyList(list)
    class DerivedClassName(BaseClassName):
        ...
    
  2. 一个子类可以继承它的父类的任何属性和方法

  3. 如果子类中定义与父类同名的方法或属性,则会自动覆盖父类对应的方法或属性,(覆盖的是子类中调用父类的属性或方法, 父类的实例化对象是可以正常调用父类的方法的。

  4. 调用未绑定的父类方法

    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 Carp(Fish):
        pass
    
    class Salmon(Fish):
        pass
    
    class Shark(Fish):
        def __init__(self):
            Fish.__init__(self) # 这个地方没有绑定父类,给的是子类的实例对象
            self.hungry = True
    
        def eat(self):
            if self.hungry:
                print("吃东西")
                self.hungry = False
            else:
                print("不吃东西")
    
    
  5. 使用super()方法

    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 Carp(Fish):
        pass
    
    class Salmon(Fish):
        pass
    
    class Shark(Fish):
        def __init__(self):
            super().__init__() # 不用给父类的名字
            self.hungry = True
    
        def eat(self):
            if self.hungry:
                print("吃东西")
                self.hungry = False
            else:
                print("不吃东西")
    
    
  6. python还支持多重继承,就是可以同时继承多个父类的属性和方法,

    class DerivedClassName(Base1, Base2, Base3):
        ...
    

    当不确定是否是必须使用多继承的时候请尽量避免使用它,容易导致代码混乱

3. 多态

类、类对象和实例对象

  1. 类定义--->类对象--->实例对象

  2. 如果属性的名字和方法相同,属性会把方法覆盖掉

  3. 因为python的变量不需要声明,所以直接给变量赋值,就相当于定义了一个变量

  4. 不要试图在一个类里面定义出所有能想到的特性和方法,应该利用继承和组合机制来进行扩展

  5. 用不同的词性命名,如属性名用名词,方法名用动词

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

  7. >>> class CC:
    		def setXY(self, x, y):
    				self.x = x
    				self.y = y
    		def printXY(self):
    				print(self.x, self.y)
            
        dd.setXY(4, 5) (其实等于 dd.setXY(dd, 4, 5))
        
        类中定义的函数必须要有self参数,因为要与实例相绑定
    

    类中定义的属性是静态变量,方法也一样,就算类对象被删除了,它们依然是存放在内存中的,只有当程序退出的时候,这个变量才会被释放。

    dd = CC(),这里的dd是实例化对象,CC是类对象,当CC即类对象被删除之后,想再通过ee = CC()这种形式实例化对象当然是不行的,但是原先的实例化对象dd还是存在于内存中的,只有当程序退出,才会被释放。

    所以在绝大多数情况下,在python中,我们要用实例化对象,而不要用类对象来进行处理。在Java中,现在只遇到工具类里的静态方法, 在不实例化对象的前提下就可以使用

  8. 自身可以认为是自身的子类

  9. isinstance(object, classinfo)
    # 1. 如果第一个参数不是对象,则永远返回false
    # 2. 如果第二个参数不是类或者由类对象组成的元组,会抛出一个TypeError异常
    
  10. >>> 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)
    
    
    

魔法方法

  1. 魔法方法总是被双下划线包围,例如

    __init__(self[, ...])
    
    在类定义的时候,有时候写__init__方法,有的时候没有写,根据需求
    
    >>> class Rectangle:
    	def __init__(self, x, y):
    		self.x = x
    		self.y = y
            # 左边的self.x 是类实例化之后的实例对象的局部变量,右边是传入的参数
            
    # __init__ 必须返回None
    
  2. 魔法方法的魔力体现在他们总是能够在适当的时候被调用

  3. __init__方法并不是实例化对象调用的第一个魔法方法
    __new__(cls[, ...])才是实例化对象调用的第一个魔法方法,一般不重写,python默认地执行它
    
  4. list(),tuple()通通是工厂函数,所谓的工厂函数就是类对象

  5. int("123") # 以前这样的做法是调用int函数,把参数"123"转化为整型,但是在现在,是实例化int类的对象,返回一个实例化后的对象,传入的参数是"123"
    
    a = int("123")
    b = int("456")
    a + b
    579
    # 发现对象是可以进行计算的,因为python无处不对象,当求a+b的时候,python实际上在将两个对象进行相加的操作
    
  6. python的魔法方法还提供了对对象自定义数字的处理,通过对魔法方法的重写,可以自定义任何对象间的运算

    >>> class Try_int(int):
    	def __add__(self, other): # 这里的self和other都是指的对象!!!
    		return self + other
    	def __sub__(self, other): # 这里的self和other都是指的对象!!!
    		return self - other
    
  7. 一个字节由8位组成,这个位(bit)就是二进制

  8. 默认的魔法方法会以合乎逻辑的方式让程序进行

  9. 通过对指定魔法方法的重写,完全可以让python根据我们的意图执行程序

  10. 随着深入,python允许我们做的事情就更多,比如对魔法方法的重写。

  11. a = int("5")
    b = int("3")
    a + b # 这些都是对象之间的运算
    # 当a对象的add方法没有实现,python就会自动找到对象b的__radd__方法。
    
  12. 用工厂函数来定义或者说生成某种数据,返回的是对象

  13. self是实例化对象的时候默认传入的一个对象,在其他魔法方法中也要有self

    class C:
    	def __init__(self):
    		self.x = "Xman"
            # 即使括号内,没有x这个参数,也能这样设置,因为这是在设置self.x, self后面加上点,再在后面加什么都可以,这是在定义这个对象自身的属性,而括号里的x只是当作函数的参数进行传入。self.x则是对这个对象自身属性的一个设置。
            
            
    >>> class C:
    	def __init__(self):
    		self.x = "Xman"
    
    		
    >>> c = C()
    >>> c.x
    'Xman'
    
  14. __getattr__(self, name)
    # 定义当用户试图获取一个不存在的属性时的行为
    __getattribute__(self, name)
    # 定义当该类的属性被访问时的行为
    __setattr__(self, name, value)
    # 定义当一个属性被设置时的行为
    __delattr__(self, name)
    # 定义当一个属性被删除时的行为
    
  15. 描述符:描述符就是将某种特殊类型的类的实例指派给另一个类的属性

    __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()
    
    	
    >>> test = Test()
    >>> test.x
    getting... <__main__.MyDecriptor object at 0x00000269E3FF80D0> <__main__.Test object at 0x00000269E3FAE400> <class '__main__.Test'>
    >>> test
    <__main__.Test object at 0x00000269E3FAE400>
    >>> Test
    <class '__main__.Test'>
    >>> test.x = "X-man"
    setting... <__main__.MyDecriptor object at 0x00000269E3FF80D0> <__main__.Test object at 0x00000269E3FAE400> X-man
    >>> test.x
    getting... <__main__.MyDecriptor object at 0x00000269E3FF80D0> <__main__.Test object at 0x00000269E3FAE400> <class '__main__.Test'>
    >>> del test.x
    deleting... <__main__.MyDecriptor object at 0x00000269E3FF80D0> <__main__.Test object at 0x00000269E3FAE400>
    

    这里的instance是指拥有者的实例对象

  16. class Celsius:
        def __init__(self, value = 26.0):
            self.value = float(value)
    
        def __get__(self, instance, owner):
            return self.value
    
        def __set__(self, instance, value):
            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()
        
    # 这里对上面的代码进行分析,其实__init__魔法方法可以和java的构造函数对应起来,__get__和__set__方法可以分别对应java的get和set方法,都是通过set来进行对值的定义(set),通过get来进行return。
    # 下面的cel = Celsius(), fah = Fahrenheit()其实就是在另一个类中对别的类进行实例化,不要想得太复杂了,实例化之后能够进行set和get操作。
    # 比如,
    >>> temp = Temperature()
    >>> temp.cel
    26.0
    >>> temp.cel = 30
    >>> temp.fah
    86.0
    >>> temp.fah = 100
    >>> temp.cel
    37.77777777777778
    # 对上面的代码进行分析,Temperature本身是一个类,这个类中对另外的两个类进行了实例化,现在对它又进行实例化。
    # temp.cel 就是直接调用类中的这个对象,cel是类Celsius的实例化对象,这里python会自动调用Celsius的__get__魔法方法,返回的是self.value,显然这个self.value是设置有初始值的,即为26.0
    # 然后输入temp.cel = 30, 这里是对temp这个对象的cel对象进行操作,相当于对cel对象进行一个set,那么python会调用Celsius类中的__set__方法,然后输入temp.fah,这里会对temp对象的fah对象进行操作,python会调用Fahrenheit这个类的__get__方法,返回的是实例instance.cel*1.8 + 32,显然instance是temp,temp.cel = 30,那会return 30 * 1.8 + 32
    # 然后是输入temp.fah = 100,这里是对temp对象的fah对象进行处理,会调用Fahrenheit的__set__方法,会对instance即temp的cel进行设置为37.7777,那相当于temp.cel = 37.7777,和上面的temp.cel = 30一样,那python会调用Celsius的__set__方法,最后调用Celsius的get方法来获得设置后的结果
    # 其实整个过程很简单,把整个过程想象成java中的set和get方法就行了,然后在某个类中实例化另两个类,分别进行get和set操作也是很常有的事。
    
    
  17. 定制序列:

    1. 协议与其他编程语言中的接口很相似,它规定你哪些方法必须要定义,比如java,java中的接口,规定了要定义哪些方法,但是在接口类中不能写方法的具体实现过程,接口之所以叫接口,就是因为把方法内部的实现过程隐藏了起来,到具体的类中去实现。接口只提供表面。

    2. 在python中,协议显得不正式,更像是一种指南

    3. 字典、列表、元组都是属于容器类型,因为里面存放各种各样的对象。

    4. 如果希望定制的容器是不可变的话,只需要定义__len__()和__getitem__()方法
      如果希望定制的容器是可变的话,除了__len__()和__getitem__()方法,还需要定义__setitem__()和__delitem__()两个方法
      
  18. 迭代器

    1. 迭代的意思就类似于循环,每一次重复的过程被称之为迭代的过程,每一次迭代的结果将会被用来作为下一次迭代的初始值。

    2. 提供迭代方法的容器称之为迭代器

    3. 迭代器:Iterator

    4. list、dict、str虽然是Iterable,却不是Iterator

    5. 每次从容器中依次拿出数据,这就是所谓的迭代操作

    6. iter(),对一个容器对象调用iter(),则得到迭代器,调用next()则会得到下一个值

    7. 可以直接作用于for循环的数据类型有以下几种:

      一类是集合数据类型,如List、tuple、dict、set、str等

      一类是generator,包括生成器和带yield的generator function

      这些可以直接作用于for循环的对象统称为可迭代对象:Iterable

      可以使用isinstance()判断一个对象是否是Iterable对象。

    8. 可以被next()函数调用并不断返回下一个值的对象称为迭代器:Iterator

    9. 生成器是Iterator对象,但是list、dict、str虽然是Iterable,即可迭代对象,但是却不是Iterator

    10. Iterator对象可以被next()函数调用并不断返回下一个数据,直到没有数据时抛出StopIteration错误

    11. Python的Iterator对象表示的是一个数据流,可以把这个数据流看做是一个有序序列,但我们却不能提前知道序列的长度,只能不断通过next()函数实现按需计算下一个数据,只有在需要返回下一个数据时它才会计算。

      Iterator甚至可以是一个无限大的数据流,因为我们无法提前知道长度,只有在需要的时候,用next()函数返回下一个数据,甚至可以是全体自然数,而使用list是永远不可能存储全体自然数的。

    12. 凡是可以作用于for循环对象都是Iterable类型。即可迭代对象。

    13. 凡是可以作用于next()函数的对象都是Iterator类型,它们表示一个惰性计算的序列。

    14. 集合数据类型如list,dict,str等是Iterable但不是Iterator,不过可以通过iter()函数获得一个Iterator对象

    15. python的for循环会自动调用next()方法

  19. 生成器

    1. 生成器并不涉及到魔法方法,甚至避开了类和对象。

    2. 生成器是迭代器的一种实现

    3. 生成器是一个特殊的函数,可以暂停或者挂起,并在需要的时候从程序离开的地方继续或者重新开始。

    4. 一旦一个函数里面出现yield语句,说明这个函数被定义为生成器。相当于return,但是普通函数一遇到return,代表函数结束,但是对于生成器来说,就是把yield后面的参数返回,然后暂停,并不是函数结束,下一次执行从这个地方开始执行。

    5. c = {i for i in [1, 1, 2, 3, 4, 5, 5, 6, 7, 8, 3, 2, 1]}
      像这种大括号里没有冒号,就是集合推导式,Python的集合里没有重复的数字,和java不一样,java的list map set都称为集合。
      
    6. Python有列表推导式、字典推导式、集合推导式,但是没有字符串推导式子。

    7. 用普通的圆括号括起来的不是元组推导式,而是生成器推导式

      生成器属于迭代器,可以被next()函数调用并不断返回下一个数据,直到没有数据时抛出StopIteration错误

    8. 生成器推导式如果作为某个函数的参数可以不加最外面的圆括号。

    9. g = (x * x for x in range(10))
      g是一个generator即生成器,创建生成器只需要把一个列表生成式的[]改成(),可以通过next()函数获得generator的下一个返回值。
      # generator保存的是算法,每次调用next(g),就计算出g的下一个元素的值,直到计算出最后一个元素,没有更多的元素时,抛出StopIteration错误。生成器是可迭代对象。这些可以直接作用于for循环的对象统称为可迭代对象:Iterable。所以正确的方式是使用for循环
      
    10. 我们创建了一个generator后,基本上永远不会调用next(),而是通过for循环来迭代它,并且不需要关心StopIteration的错误。

模块

  1. 容器 --- 数据的封装

    函数 --- 语句的封装

    类 ---- 方法和属性的封装

  2. 模块就是程序,就是我们平时写的任何代码,保存为.py这样的文件,那就是一个独立的模块。

  3. 导入模块之后,要想调用这个模块中的函数,要加上命名空间

  4. 导入模块

    1. import 模块名
    2. from 模块名 import 函数名(这里的函数名可以使用通配符*来导入这个模块的所有函数,但是不建议这样写,因为这样会使得这种写法的优势荡然无存,会将函数名搞混)
    3. import 模块名 as 新名字(推荐这种方式来导入)
  5. 每个模块之间都是独立开的, 增强了可读性。每个人肯定都是更愿意去阅读和调试一小段代码。

  6. 写好的模块应该放在哪里

    1. 放在和导入这个模块的文件在同一个路径下。

    2. 也可以不放在同一个路径下,python模块的导入需要一个路径搜索的过程,如果导入一个hello.py的模块,python会在预定好的搜索路径里找到这个hello.py这个文件,如果没有则导入失败,这个搜索路径是一个目录。

      sys.path可以查看到python会在哪些路径下去找模块,如果我们要导入的模块没有放在这些路径下的其中一个路径,就会导入失败,如果不想移动模块的位置,那么通过sys.path.append将模块所在的路径添加进python的搜索路径

  7. python也有包的概念,不要和模块搞混,

    1. 创建一个文件夹,用于存放相关的模块,文件夹的名字即包的名字。可以理解为一个包下面有许多模块,一个.py文件是模块,一个包是由多个.py文件组成。可以和java类比一下,一个jar包是由多个类组成,这里的类在java程序中也是用来import,对应于.py文件,而一个jar包下有多个类,相关的类放在一起组成一个jar包。

    2. 在文件夹中创建一个__init__.py的模块文件,内容可以为空
      
    3. Python标准库中包含一般任务所需要的模块(.py文件)

    4. Python除了官方的标准库中的模块,pypi社区收集了全球python爱好者发布的模块。一个py文件就是模块,一个包下面有许多模块。

    5. 用C/C++给python编写扩展模块

    6. __all__显示的就是这个模块可以供外界调用的所有信息。
      不是所有的模块都有__all__这个属性,__all__是这个模块的作者希望这个模块被调用的东西
      
      如果一个模块有__all__属性,
      from timeit import * 则__all__属性里面的名字(类、方法(函数))才会被导入
      
    7. 导入模块方式:

      1. import xxx

        这种方式使用导入模块里的变量或者函数的时候,必须是模块名.变量名(函数名)的形式。

      2. import A as B

        这种方式同上

      3. from A import B

        这种方式如果当前导入的模块里有跟当前名称空间相冲突的名字,那么下面的名字就会覆盖上面

        去调用模块里的函数名或者变量名的时候,不需要以模块名作为前缀。

        这里的B也可以是通配符*

        要记住这种导入方式,右边的B,仍然是指的模块里的内容

    8. 导入包的方式:

      1. 包就是一个目录,在Python中,一个文件夹中有__init__.py的文件

        是一个有层级的目录结构,包含n个模块或者n个子包,包中一定要有__init__.py文件

        也就是包下面可以是子包和模块,并不是说包里面就一定全是模块。

      2. python的库是完成一定功能的代码集合,表现形式是一个模块,或包。

        第三方库可以是模块,也可以是包

      3. 无论是import形式还是from...import形式,凡是在导入语句中(而不是在使用时)遇到带点的,都要第一时间提高警觉:这是关于包才有的导入语法

        在导入的时候出现了.,说明这是包的导入方式。

        凡是在导入时带.的,.的左边必须是一个包,否则非法。

      4. 需要注意的是from...import导入的模块,import后面必须是导一个具体的目标,错误语法(from a import b.c)正确语法(from a.b.c import d)

        from 模块 import 方法,这个a.b.c就代表模块,其中a和b都是包

        from glance.api.policy import get

      5. 没有from 包 import 模块这种写法。 因为可以写成import 包.模块

爬虫

  1. 什么是网络爬虫?

    网络爬虫又称为网络蜘蛛,如果把整个互联网想象成蜘蛛网的构造,每个网站都是一个节点,蜘蛛在上面爬来爬取,抓取我们最有用的资源。

  2. 之所以百度或谷歌这种搜索引擎检索到网页,靠的就是每天派出大量的蜘蛛在互联网上爬,对网页中的关键字建立索引,数据库,排序,结果按照搜索的相关度的高低展现给用户。

  3. python怎么连接互联网,通过库urllib

  4. URL的一般格式为:

    protocal://hostname[:port]/path

  5. URL由三部分组成:

    第一部分是协议:http、https、ftp、file、ed2k...

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

    https://www.bilibili.com/video/BV1xs411Q799?p=54
        其中www.bilibili.com是域名系统
    

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

    第一部分和第二部分用://隔开,第三部分用/隔开。

  6. urlopen这个函数的参数既可以是字符串,也可以是requestObject对象。
    
  7. 在客户端和服务器之间进行请求相应的方法最常用的是GET和POST,在定义上来说,GET是指从服务器请求获得数据,而POST是指向指定服务器提交被处理的数据,但是在现实情况中,GET也常常用来提交数据

  8. Request Headers是客户端(可以是网页,可以是python,可以是java...)

    服务端可以通过这个Request Header判断访问是否是来自于人类。通过User-Agent的内容,不过User-Agent的内容可以进行简单地自定义。

    Form Data是表单数据,是POST提交的主要内容。

  9. urlopen这个函数有一个data参数,data参数如果被赋值,那么就是以POST形式取代GET形式提交,如果这个参数没赋值即默认是None状态,就默认以GET形式提交
    
  10. json是一种轻量级的数据交换格式。

  11. 有一些网站不喜欢被爬虫程序访问,会检查链接的来源,如果来源不是正常的途径,就会被拒绝,所以我们需要对代码进行隐藏,让程序看起来是普通人经过正常浏览器的点击

    服务器一般检查链接,是检查链接里的headers里的userAgent来判断来自于代码还是浏览器。

  12. headers必须是字典,一种方法是在作为Request方法的参数传入之前,先进行定义,然后传入

    另一种方法是生成request对象的时候,Request方法里没有传入headers参数,进行add_header来添加。Requset.add_header()方法修改。

  13. 网站屏蔽爬虫的一种方法是记录IP的访问频率,如果IP的访问频率很快,那么就会被认为是爬虫,就可以不管User-Agent是什么,就会拒绝。我们可以延迟提交的时间,使爬虫看起来更像是人类在浏览,另一种方法就是代理。

  14. 代理

    把需要访问的网址告诉代理,代理进行访问,把看到的内容转发给我们。服务器看到的是代理的IP地址,而不是我们的IP地址。(代理 肉鸡??搭梯子??)

    步骤

    1. 参数是一个字典{""类型": "代理IP:端口号"}

      proxy_support = urllib.request.ProxyHandler({})

    2. 定制、创建一个opener

      opener = urllib.request.build_opener(proxy_support)

      opener可以看作是一个私人定制。定制一个opener(加上特殊的headers,或者指定代理)来访问。

    3. 两种方法

      a. 安装opener

      urllib.request.install_opener(opener)

      这是一劳永逸的做法,在此之后,只要使用普通的urlopen函数,就会自动使用定制好的opener进行工作

      b. 定制opener之后调用opener

      opener.open(url)

  15. 正则表达式是描述复杂规则的工具

  16. search()方法用于在字符串中搜索正则表达式模式第一次出现的位置。范围下标是前闭后开区间

  17. 正则表达式也有通配符,是用一个点号来表示。点号能够匹配除了反斜杠之外的任何字符。

  18. 在正则表达式中,前面加上反斜杠\就是代表匹配元字符。

  19. 字符类就是中括号[]括起来的里面的字符,里面的字符只要有一个匹配成功,就算匹配成功

  20. \

    1. 将一个普通字符变成特殊字符,例如\d表示匹配所有十进制数字。
    2. 解除元字符的特殊功能,例如\.表示匹配点号本身
    3. 如果在\后加的是数字,引用序号对应的子组所匹配的字符串
    
  21. 子组(子表达式)就是用小括号括起来的。

  22. 字符类[]就是一个字符集合的意思,匹配所包含的任意一个字符

    1. 连字符-如果出现在字符串中间表示字符范围描述,如果出现在字符串首位则仅作为普通字符
    2. 特殊字符仅有反斜线\保持特殊含义,用于转义字符,其他特殊字符如*、+、?等均作为普通字符匹配。
    3. 脱字符^如果出现在首位则表示匹配不包含其中的任意字符,如果^出现在字符串中间就仅作为普通字符匹配。
    字符类的意思将里面的内容作为普通的字符看待。
    
  23. {M,N}

    M和N均为非负整数,其中M<=N,表示前边的字符匹配M~N次
    1. {M,}表示前边的RE至少匹配M次
    2. {,N}等价于{0,N}
    3. {N}表示前边的RE需要匹配N次。
    4. *表示匹配前面的子表达式零次或多次,等价于{0,}
    5. +表示匹配前面的子表达式一次或多次,等价于{1,}
    6. ?表示匹配前面的子表达式零次或一次,等价于{0,1}
    加上小括号就是子表达式
    
  24. \序号
    1. 引用序号对应的子组所匹配的字符串,子组的序号从1开始计算
    2. 如果序号是以0开头,或者3个数字的长度,那么不会被用于引用对应的子组,而是用于匹配八进制数字所表示的ASCII码值对应的字符。
    
  25. 如果你需要重复地使用某个正则表达式,那么你可以先将该正则表达式编译成模式对象

    我们使用re.compile()方法来编译

    >>> p = re.compile(r"[A-Z]")
    >>> type(p)
    <class 're.Pattern'>
    >>> p.search("I love FishC.com!")
    <re.Match object; span=(0, 1), match='I'>
    >>> p.findall("I love FishC.com!")
    ['I', 'F', 'C']
    用这种方式第一个参数就省掉了。
    
  26. findall()方法,找到所有匹配的内容,组织成列表的形式返回。

    findall()方法中,正则表达式如果包含子组的话,会把子组的内容单独返回回来

  27. HTTPError是URLError的子类,服务器上每一个HTTP的响应都包含一个数字的状态码。

    需要关注的是400~599这个范围的状态码,因为它们代表响应出了问题,其中出现4xx的状态码,说明问题来自客户端,就是自己哪里做错了,出现5xx的状态码,就是来自服务器的问题。

    处理异常的第一种写法
    from urllib.request import Request, urlopen
    from urllib.error import URLError, HTTPError
    req = Request(someurl)
    try:
        response = urlopen(req)
    except HTTPError as e:
    	print("The server couldn\'t fulfill the request.")
        print(e.code)
    except URLError as e:
        print("We failed to reach a server.")
        print(e.reason)
    else:
        # everything is fine.
        
        
    处理异常的第二种写法
    from urllib.request import Request, urlopen
    from urllib.error import URLError, HTTPError
    req = Request(someurl)
    try:
        response = urlopen(req)
    except URLError as e:
    	if hasattr(e, "reason"):
            print("We failed to reach a server.")
            print("Reason: ", e.reason)
        elif hasattr(e, "code"):
    		print("The server couldn\'t fulfill the request.")
            print(e.code)
    else:
    	# everything is fine.
    
    
  28. Scrapy

    Scrapy是一个为了爬取网站数据,提取结构性数据而编写的应用框架,可以应用在一系列包括数据挖掘,信息处理或存储历史数据等一系列的程序中

    Scrapy最初是为了页面抓取所设计的,也可以应用在获取API所返回的数据或者通用的网络爬虫。

  29. pip是python安装软件的工具,python会默认安装pip,会在pypi社区自动搜索模块,输入命令进行安装。

  30. 使用Scrapy抓取一个网站一共需要四个步骤

    1. 创建一个Scrapy项目

    2. 定义Item容器

      Item是保存爬取到的数据的容器,其使用方法和python字典类似,并且提供了额外保护机制来避免拼写错误导致的未定义字段错误。

      首先我们需要对需要获取的数据进行建模(items.py文件里创建字段)。

    3. 编写爬虫

      接下来是编写爬虫类Spider,Spider是用户编写用于从网站上爬取数据的类。

      其包含了一个用于下载的初始URL,然后是如何跟进网页中的链接以及如何分析页面中的内容,还有提取生成item的方法(parse())。

      1. scrapy crawl dmoz,就会来找name的蜘蛛或者爬虫,所以这个name是唯一的
        
      2. # 找到爬虫之后,就会知道下面的start_urls列表里的两个初始化地址,这个地址会提交给Scheduler,Scheduler再安排好顺序发给Downloader去下载,下载之后返回response给Spiders
        # 也就是下面的函数parse会接收到这个response
        
      3. # parse()方法接收Downloader返回的response,然后进行分析处理,提取items给Item Pipeline
        
      4. 爬的过程完成之后,就是取的过程,就要用到Scrapy框架的Item容器。从得到的网页内容提取出我们需要的数据,这一步我们之前使用过正则表达式,现在在Scrapy框架中,可以用Selector。

        Selector是一个选择器,它有四个基本的方法:

      xpath(): 传入xpath表达式,返回该表达式所对应的所有节点的
      # XPath是一门在网页中查找特定信息的语言,所以用XPath来筛选数据,要比使用正则表达式更容易些
      /html/head/title: 选择HTML文档中<head>标签内的<title>元素
      /html/head/title/text(): 选择上面提到的<title>元素的文字
          response.xpath() == response.selector.xpath()
      selector list列表。
      >>> response.xpath('//section/div/div/div/div[@class="title-and-desc"]/a/@href').extract()
      >>> response.xpath('//section/div/div/div/div[@class="title-and-desc"]/a/div/text()').extract()
      
      >>> sites = response.xpath('//section/div/div/div/div[@class="title-and-desc"]')
      >>> for site in sites:
      ...     title = site.xpath('a/div/text()').extract()
      ...     print(title)
      
      
      
      css(): 传入CSS表达式,返回该表达式所对应的所有节点的selector list列表
          
          
          
          
      extract(): 序列化该节点位unicode字符串并返回list
          
          
          
          
      re(): 根据传入的正则表达式对数据进行提取,返回unicode字符串list列表。
      
      1. /html/body/div[5]/div/section[3]/div/div/div[5]/div[3]/a
    4. 存储内容

  31. Scrapy项目创建好之后,初始项目结构如下:

    tutorial/
    	scrapy.cfg   # 项目的配置文件,不要删除,保持默认。
        tutorial/    # 存放的是模块的代码
        	__init__.py
            items.py  # 是容器。
            pipelines.py
            settings.py  # 设置文件
            spiders/
            	__init__.py
                ...
                
                
    # 这是一个框架,它提供了基本的部分,剩余的部分需要我们来完成。
    
  32. 字符串里涉及到需要双引号的,最外层用单引号便可以解决这个转义问题

GUI Tkinter

  1. 获取输入框里面的内容可以用entry组件的get方法。
  2. 为了在某个组件上安装垂直滚动条,你需要做两件事:
    1. 设置该组件的yscrollbarcommand选项为Scrollbar组件的set()方法
    2. 设置Scrollbar组件的command选项为该组件的yview()方法

pygame

  1. 一个包里面包含着各种不同功能的模块,一个.py文件就是一个模块。

  2. 用户的一切行为都会变成一个个事件消息。

  3. 什么是surface对象

    surface对象就是pygame里面用来表示图像的对象。

    以后在pygame里面说图像,其实就是指的surface对象

  4. 将一个图像绘制到另一个图像上是怎么回事

    bilt方法将一个图像放到另一个图像上,并不是真的说将一个图像拷贝到另一个图像上去,实际上是修改另一个图像某一部分像素的颜色,最终每一刻呈现出来的仍然是一个图像而不是两个图像。

  5. 移动图像

    调用rect对象(矩形)的move方法,修改矩形的位置

  6. pygame的效率高不高

    不高

  7. rect(Surface, color, Rect, width = 0)

    • Surface 指定的是矩形将绘制在哪个surface对象上
    • color 是指定矩形的颜色
    • Rect 指定矩形的范围,其实就是矩形对象
    • width 指定边框的大小
  8. 图像是特定像素的组合,Surface对象是pygame里面对图像的描述,在pygame中,到处都是surface对象。

  9. 小乌龟在画布上运动,其实是小乌龟也是一个surface对象,画布也是surface对象,把一个surface对象放到另一个surface对象上,占的位置为一个矩形对象。运动的话就是改变像素。

  10. 载入图片image.load会返回surface对象

事件

  1. 事件是pygame提供给我们去干预游戏的机制

    比如说点关闭是quit事件

    处理quit事件的方法就是调用system.exit()方法

  2. 事件随时都可能发生,移动鼠标,点击鼠标,敲击键盘都会产生事件。

    pygame的做法就是把所有产生的事件都放到一个事件队列里面

    通过for语句迭代取出每一个事件,对我们关注的事件进行处理

  3. pygame并不可以直接让我们在surface即图像对象上绘制想要的文字

    font的render方法,将文字渲染成surface对象

飞机大战

  1. 把能独立分开的代码独立成一个一个的模块,一个.py文件就是一个模块,这个是类似于java中的一个类

    导入模块和导入包是不同的,具体的区分一定要弄清楚。

  2. 写程序的逻辑一定要清楚,在一个项目里面,资源(resource)都装在对应的文件夹里。

Last Updated:
Contributors: 陈杨