Python进阶-史上最牛X

715 阅读41分钟

一:理解什么是写代码与python的基本数据类型

1 数字类型

1-1 python的基本数据类型

整数:int

浮点数:float

# / 表示除法,结果是float类型
print(8 / 4)

# // 表示取整,结果是整型
print(8 // 3)

1-2 10,2,8,16进制

10进制就是满10进1

以此类推

1-3 各进制的表示与转换

二进制:0b开头(0b12)

八进制: 0o开头(0o11)

十进制:10

十六进制: 0x11

其他进制向二进制的转换: bin()

其他进制向八进制的转换: oct()

其他进制向十进制的转换: int()

其他进制向十六进制的转换: hex()

# 二进制的转换为十进制 2
print(0b10)
# 八进制
print(0o10)
# 16进制
print(0x11)

print(type(0o12))

# 其他进制转化成二进制
print(bin(10))
print(bin(0o10))
print(bin(0x10))

# 其他进制转换成八进制
print(oct(10))

# 其他进制转换成16进制
print(hex(10))

# 其他进制转换成十进制
print(int(0x10))

1-4 布尔类型和复数

bool 布尔类型:表示真、假

​ 所有的非空对象都是True

​ 这些都是False ('',[],{},(),0,None)

complex 复数

print(True)
print(False)
print(1 + 1 == 1)  # True
print(1 + 1 == 2)  # False

那为什么说布尔类型会归类成数字呢

print(int(True)  # 1
print(int(False))  # 0
      
print(bool(1))  # True
print(bool(0))  # False
# 一正一反就证明在python中布尔类型属于数字大分类的一种

python中复数的表示

36j

2 字符串

2-1 单引号与双引号

如何表示字符串

单引号,双引号,三引号

字符串的引号必须成对出现

# 为什么要有单双引号
# 举个例子,我们用字符串表示let's go
"let's go"
# 在表示字符串的时候不管是使用单引号还是双引号,我么要保证作用域不会被干扰,且成对出现合理的去使用单双引号

# 要是我们非要使用'let's go'这种方式表示字符串的话,在中间引号左边加上转义字符'\'
'let\'s go'

2-2 多行字符串:三引号

为了将多长的字符串换行

'''
hello word
hello word
hello word
hello word
'''

#注 '\n' 表示换行

三个双引号和单引号是一样的

2-3 转义字符

概念:特殊的字符

应用场景

# 有的时候表示无法'看见'的字符
# 与语言本身语法又冲突的字符
\n  # 换行
\'  # 单引号
\t  # 横向制表符
\r  # 回车
qwertyuiopasdfghjkl;'zxcvbnm,./'

2-3 原始字符串

​ 我们要把输出\n而不是将其转义,表示的方法就是在\n前面再加一个\

print("今天天气不错\\n,挺风和日丽的")

#比如我们要输出一个文件的路径
    print('\nor\nid\two\right,.jpg')
    # 就会变成一个个换行的字符串

    # 方法1,多加一个\
    print('\\nor\\nid\\two\\right,.jpg')
    # 方法2:在字符串的前面加r
    print(r'\nor\nid\two\right,.jpg')

# 注:加\表示转,加r表示该字符串输出为原始字符串

2-4 字符串运算

# 两个字符串的拼接
t1 = 'hello'
t2 = 'word'
print(t1 + ' ' + t2)

# 字符串的乘法
print(t1 * 3)

# 字符串的切片,靠下标取值
t3 = 'hello world'
print(t3[6])  # w
print(t3[-1])  # d
print(t3[-3])  # l

# 步长:获取一个字符串中的一组字符
print(t3[0:5])  # hello

# 从t3中取world
print(t3[6:11])
print(t3[-5:])
print(t3[6:])

二:Python中表示“组”的概念与定义

1 list列表

定义:

[1,2,3,4,5,6]
将一组元素使用中括号包含且用逗号隔开这样的类型的数据叫做列表
列表里面的元素可以是python的任意类型

列表的操作

# 列表的取值
l1 = ['新月打击', '苍白之瀑', '月之降临', '月神冲刺']
l2 = ['点燃', '虚弱']
print(l1[0])  # 新月打击
print(l1[0:2])  # ['新月打击', '苍白之瀑']
# 两个列表元素相加
print(l1 + l2)  # ['新月打击', '苍白之瀑', '月之降临', '月神冲刺', '点燃', '虚弱']
# 列表元素加倍
print(l2 * 3)  # ['点燃', '虚弱', '点燃', '虚弱', '点燃', '虚弱']

2 tuple元组

定义:

用小括号将一组元素包含起来,每个元素使用逗号隔开
元组里面的数据可以是任何类型

元组的操作

t1 = (1,2,3,4,5)
t2 = (6,7)
print(t1[1])
print(t1[1:2])
print(t1[1:3])
print(t1+t2)
print(t2*3)

# 运行结果
2
(2,)
(2, 3)
(1, 2, 3, 4, 5, 6, 7)
(6, 7, 6, 7, 6, 7)

元组里面单独放一个元素,不管是str类型还是int类型,最后元组的值和类型都会变成该元素

print((1), type((1)))  # 1 <class 'int'>
print(('hello'), type('hello'))  # hello <class 'str'>

发现这种情况的原因是因为这样写的话python会将会语法识别为数学运算

类似于(1+1)*2

为了避免这种情况,在元组的只有一个元素的情况下,后面加一个逗号

print((1,), type((1,)))  # (1,) <class 'tuple'>

3 插曲--序列

像str,list,tuple都是序列

他们的共有的操作方式总结

a = 'hello world'
1 通过索引取值  a[1]
2 切片取值  a[1:4]
3 按照一定的步长切片 a[1::2] 
4 print('h' in a)  # 判断a是否在序列a中
5 print('h' not in a)  # 判断h是否不在序列a中
6 len(a)  # 序列的长度
7 max([1,2,3,4,5])  # 序列中最大的元素
8 min([1,2,3,4,5])  # 序列中最小的元素
9 max('hello world')  # 输出的是'w' ,因为在字符串中按照ascll码对字符进行排序

ascll

# 将字符转换成ascll码
print(ord('a'))  # 97
# 将ascll转换成字符串
print(chr(65))  # A

4 set集合

定义

集合是使用大括号包含一组元素{1,2,3,4}
注:集合的特性
1集合的元素是无序的,就是说不能使用索引取值
2集合里面的元素都是唯一的,不存在重复元素

集合的操作

a={1,2,3}
len(a)  # 3
print(1 not in a)  # True

s1 = {1, 2, 3, 4, 5, 6}
s2 = {4, 5, 7, 8}
print(s1 - s2)  # 求差集
print(s1 & s2)  # 求交集
print(s1 | s2)  # 求并集

s = set{}  # 定义一个空的集合

5 dict字典

定义:

使用大括号包含,使用key:value的方式存放数值,每个键值对之间使用逗号分隔
字典的key不能重复,否则将会被覆盖
字典的key可以是数字或字符串
字典的value可以是python任意类型的数据


字典的操作

d1 = {"name":"andy","age"10"addr":"中国"}
print(d1['name'])  # andy
# 定义一个空字典
d = {}

6 思维导图总结基本数据类型

三:变量和运算符

1 什么是变量

变量就是对象的名字,方便对对象的调用

变量的使用

a = [1,2,3,4,5,6]
# '=' 再python中是赋值符号

对于变量的命名,一定要有意义,使用英文,不要想当然

2 变量的命名规则

  1. 变量名包含数字,字母,下划线
  2. 变量不能以数字开头
  3. 变量命名不能使用系统的保留关键字

3值类型和引用类型

int值类型

list引用类型

4 列表的可变和元组的不可变

变量的值改变,内存地址变化,是不可变类型

变量的值该表,内存地址不变,是可变类型

字符串,数字,元组是不可变类型

列表,集合,字典是可变类型

访问多为数组内部的数据

a=(1,2,3,[1,2,4])
a[3][2]  # 4

元组是不可变的,但是元组里面的列表是可变的,举例如下

a=(1,2,3,[1,2,4])
a[2][2] == '1'
print(a)  # a=(1,2,3,[1,2,'1'])

5 运算符号

算术运算符

以下假设变量: a=10,b=20

运算符 描述 实例
+ 加 - 两个对象相加 a + b 输出结果 30
- 减 - 得到负数或是一个数减去另一个数 a - b 输出结果 -10
* 乘 - 两个数相乘或是返回一个被重复若干次的字符串 a * b 输出结果 200
/ 除 - x除以y b / a 输出结果 2
% 取模 - 返回除法的余数 b % a 输出结果 0
** 幂 - 返回x的y次幂 a**b 为10的20次方, 输出结果 100000000000000000000
// 取整除 - 返回商的整数部分(向下取整 >>> 9//2 4 >>> -9//2 -5

比较运算符

以下假设变量: a=10,b=20

运算符 描述 实例
== 等于 - 比较对象是否相等 (a == b) 返回 False。
!= 不等于 - 比较两个对象是否不相等 (a != b) 返回 true.
<> 不等于 - 比较两个对象是否不相等。python3 已废弃。 (a <> b) 返回 true。这个运算符类似 != 。
> 大于 - 返回x是否大于y (a > b) 返回 False。
< 小于 - 返回x是否小于y。所有比较运算符返回1表示真,返回0表示假。这分别与特殊的变量True和False等价。 (a < b) 返回 true。
>= 大于等于 - 返回x是否大于等于y。 (a >= b) 返回 False。
<= 小于等于 - 返回x是否小于等于y。 (a <= b) 返回 true。

示例

b = 1
b += b >= 1
print(b)

# 结果为2,因为int(True)==1 ,所以不只是数字才能做运算或大小比较

# 判断'a'>'b'
print('a'>'b')  # False  因为字符串做比较运算使用的是ascll之间的比较,可以使用ord方法查看单个字符的ascll
# 判断字符串之间的大小
print('aas'>'aag')  # True 两个字符串都从第一个字符开始成对的比较
只要是序列作关系运算,都跟上面字符串一样,一个个的往后比较

赋值运算符

以下假设变量: a=10,b=20

运算符 描述 实例
= 简单的赋值运算符 c = a + b 将 a + b 的运算结果赋值为 c
+= 加法赋值运算符 c += a 等效于 c = c + a
-= 减法赋值运算符 c -= a 等效于 c = c - a
*= 乘法赋值运算符 c *= a 等效于 c = c * a
/= 除法赋值运算符 c /= a 等效于 c = c / a
%= 取模赋值运算符 c %= a 等效于 c = c % a
**= 幂赋值运算符 c **= a 等效于 c = c ** a
//= 取整除赋值运算符 c //= a 等效于 c = c // a

位运算符

按位运算符是把数字看作二进制来进行计算的。Python中的按位运算法则如下:

下表中变量 a 为 60,b 为 13,二进制格式如下:

a = 0011 1100

b = 0000 1101

-----------------

a&b = 0000 1100

a|b = 0011 1101

a^b = 0011 0001

~a  = 1100 0011
运算符 描述 实例
& 按位与运算符:参与运算的两个值,如果两个相应位都为1,则该位的结果为1,否则为0 (a & b) 输出结果 12 ,二进制解释: 0000 1100
| 按位或运算符:只要对应的二个二进位有一个为1时,结果位就为1。 (a | b) 输出结果 61 ,二进制解释: 0011 1101
^ 按位异或运算符:当两对应的二进位相异时,结果为1 (a ^ b) 输出结果 49 ,二进制解释: 0011 0001
~ 按位取反运算符:对数据的每个二进制位取反,即把1变为0,把0变为1 。~x 类似于 -x-1 (~a ) 输出结果 -61 ,二进制解释: 1100 0011,在一个有符号二进制数的补码形式。
<< 左移动运算符:运算数的各二进位全部左移若干位,由 << 右边的数字指定了移动的位数,高位丢弃,低位补0。 a << 2 输出结果 240 ,二进制解释: 1111 0000
>> 右移动运算符:把">>"左边的运算数的各二进位全部右移若干位,>> 右边的数字指定了移动的位数 a >> 2 输出结果 15 ,二进制解释: 0000 1111

逻辑运算符

Python语言支持逻辑运算符,以下假设变量 a 为 10, b为 20:

运算符 逻辑表达式 描述 实例
and x and y 布尔"与" - 如果 x 为 False,x and y 返回 False,否则它返回 y 的计算值。 (a and b) 返回 20。
or x or y 布尔"或" - 如果 x 是非 0,它返回 x 的值,否则它返回 y 的计算值。 (a or b) 返回 10。
not not x 布尔"非" - 如果 x 为 True,返回 False 。如果 x 为 False,它返回 True。 not(a and b) 返回 False

对布尔类型进行操作,返回的结果也是布尔类

但是逻辑运算符不一定返回的是布尔值,如上

成员运算符

除了以上的一些运算符之外,Python还支持成员运算符,测试实例中包含了一系列的成员,包括字符串,列表或元组。

运算符 描述 实例
in 如果在指定的序列中找到值返回 True,否则返回 False。 x 在 y 序列中 , 如果 x 在 y 序列中返回 True。
not in 如果在指定的序列中没有找到值返回 True,否则返回 False。 x 不在 y 序列中 , 如果 x 不在 y 序列中返回 True。

身份运算符

身份运算符用于比较两个对象的存储单元

运算符 描述 实例
is is 是判断两个标识符是不是引用自一个对象 x is y, 类似 id(x) == id(y) , 如果引用的是同一个对象则返回 True,否则返回 False
is not is not 是判断两个标识符是不是引用自不同对象 x is not y , 类似 id(a) != id(b)。如果引用的不是同一个对象则返回结果 True,否则返回 False。

6 如何判断变量的值,身份和类型

is和==的区别

is判断的是值内存地址是否相等

==判断的是值是否相等

示例

# 分别判断两个集合,两个元组之间的身份运算结果
a = {1, 2, 3}
b = {2, 1, 3}
c = (1, 2, 3)
d = (2, 1, 3)
print(a == b)
print(a is b)
print(c == d)
print(c is d)

# 因为集合是无序的,所以a,b值相等
# 又因为a,b,c,d的内存地址不同,所以is都是False
"""运行结果
True
True
False
False
False
"""

当我们想要知道一个对象的类型的时候,通常是使用type(object)来实现

但是我们要判断一个对象是不是某个类型的时候,通常是使用isinstance

name = 'andy'
isinstance(name,str)
isinstance(name,(str,int))  # 判断某个对象是不是某一组类型中的一个

7 什么是表达式

定义:

表达式(Expression)是运算符(operator)和操作数(operand)所构成的序列

8 表达式的优先级

运算符说明 Python运算符 优先级 结合性 优先级顺序
小括号 ( ) 19
索引运算符 x[i] 或 x[i1: i2 [:i3]] 18
属性访问 x.attribute 17
乘方 ** 16
按位取反 ~ 15
符号运算符 +(正号)、-(负号) 14
乘除 *、/、//、% 13
加减 +、- 12
位移 >>、<< 11
按位与 & 10
按位异或 ^ 9
按位或 | 8
比较运算符 ==、!=、>、>=、<、<= 7
is 运算符 is、is not 6
in 运算符 in、not in 5
逻辑非 not 4
逻辑与 and 3
逻辑或 or 2
逗号运算符 exp1, exp2 1

练习

a = 1
b = 2
c = 3
print(not a or b+2 == c)  # False  优先级:"+" > "==" > "not" > 'or' 
print(not a or ((b+2) == c)) # False  优先级:小括号的优先级最高

四:分支,循环,条件

IDE :Integrated Development Environment(集成开发环境)

1 使用vscode

pass  # 空语句,占位语句

2流程控制语句

if condition:
    pass
else:
    pass


a = int(input('please input number'))
if a == 1:
    print('eat apple')
elif a == 2:
    print('eat orange')
else:
    print('eat banana')

注:

在python中使用的input,不管接受到的字符是什么,都是str类型的

比如我们想要输出 a,b两个中为Trued的值,除了使用if else ,还可以使用

a or b  # 会返回出True的值

3 循环

while

counter = 1
while counter <= 10 :
    counter += 1
    print(counter)
else:  # 想不到把,while也有else
    print('EOF') 

在使用while循环的过程中,while后面的条件不应该是一个常量,而且在循环体内部应该有影响循环条件的代码

在递归中通常使用while,在其他循环中建议使用for循环

for

# for 主要用来遍历/循环 序列或者集合、字典
a = ['apple','orange','banana','grape']
b = 
for i in a:
    print(i)
s

break 跳出本层循环

continue 结束本次循环,开始下一次循环

range

for x in range(0,10):
    print(x)
# 打印从0到9
# 实现一组序列的递增,而且步长为2
for x in range(0,10,2): 
	print(x,end=' | ')
    
    
# 实现一组序列的递减    
for x in range(10,0,-2): 
    print(x,end=' | ')
    
# 打印出列表中奇数的元素
a = [1,2,3,4,5,6,7,8,9,10]
b = a[0:len(a):2]  # 不用使用循环,直接使用列表的切片来实现
    
# 使用range来实现上述的例子
a = [1,2,3,4,5,6,7,8,9,10]
for x in range(0,len(a),2):
    print(a[x],end='| ')
    
    

五:包,模块,函数与变量作用域

1 Python工程的组织结构:包、模块儿、类

定义

包--》模块--》类--》函数、变量

包:项目文件夹
模块:一个.py文件

python包与模块的名字

# 我们取包里面模块的名字,比如view包下面有一个user.py的模块
view.user
# 上面的表达就是我们说的命名空间

# 子包:包下面可以有子包

包和文件夹的区别

# 包里面有一个特殊的文件,__ini__.py文件
# __init__.py文件的名字就是包名

# python导包

import t.c7
print(t.c7.a)

2 import 导入模块

# 使用import书写规范
# from module import a,xxx
from t.c7 import a
print(a)  # 1


# 导入一个模块里面的所有的变量和方法
from t.c7 import *

"""
__all__:模块的内置属性
当我们是使用‘*’获取模块中所有的变量和方法的时候,为了避免冲突,可以在需要导入的模块中使用‘__all__’
__all__是一个序列,中的元素就是别的模块使用*导入的变量和方法
使用的时候,不在__all__中的变量和方法便会显示not defined
"""

# 导入的时候可以使用如下方法导入模块中的多个变量和方法
from c1 import a, b, c

#当导入的方法过多,查过80个字符的时候,可以通过换行实现
from m import (a,b
               c)


3 _init_.py 的用法

# 在t1包中定义__init__.py文件
a = 'this is __init__.py file'
print(a)

# 当我们在其他文件中导入t1的时候
import t1

# 就会运行__init__.py中的代码

# 当我们在__init__.py中使用__all__方法的时候,只有在__all__中定义的方法才可以被导入


# 当我们有很多的模块都要使用相同的库,就可以将这些库在__init__.py中导入即可

#比如我们在包t中的__init__.py文件中
import sys
# 在其他包中导入该包
import t
print(t.sys.path)  # 即可运行成功

4 包与模块的几个常见错误

  1. 包和模块是不会被重复导入的
  2. 避免循环导入
  3. 单纯的导入一个模块,就会执行模块里面的代码

5 模块内置变量

#t.c14.py
a = 2
c = 3
infos = dir()        #打印当前模块内所有变量
print(infos)
"""
运行结果:['__annotations__', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__','a',']
"""
 #t.c9.py
    '''
        This is a c9 doc                          #注释
    '''
    print('name:' + __name__)                    # + 把他们连接在一起,
    print('package:' + __package__)
    print('doc:' + __doc__)                      #doc指的是模块的注释
    print('file:' + __file__)

#c15.py
import t.c9
"""
c15.py运行结果:
name:t.c9                             #c9模块的完整命名
package:t                             #c9模块的包
doc:
This is a c9 doc                      #c9模块的注释
file:D:\install\python\t\c9.py        #c9模块在系统中的物理路径
"""

6 入口文件和普通模块内置变量的区别

#c15.py
import t.c9
print('package:' + __package__ )
print('name:' + __name__)
print('doc:' + __doc__)
print('file:' + __file__)

运行结果:
name:t.c9
package:t
doc:
    This is a c9 doc
file:D:\install\python\t\c9.py
c9运行成功,c15运行失败,因为c15不属于任何包

修改后:

#c15.py
import t.c9
print('package:' + (__package__ or '当前模块不属于任何包'))        #因为+的优先级高于or,所以加()
print('name:' + __name__)
print('doc:' + __doc__)
print('file:' + __file__)
运行结果:
name:t.c9
package:t
doc:
    This is a c9 doc
file:D:\install\python\t\c9.py
package:当前模块不属于任何包
name:__main__                          #入口文件中__name__会被强制修改为__main__ 

再次修改:

#c15.py
import t.c9
print('~~~~~~~~~~~~c15~~~~~~~~~~~~~)
print('package:' + (__package__ or '当前模块不属于任何包'))  
print('name:' + __name__)
print('doc:' +( __doc__or ‘当前模块没有文档注释'))
print('file:' + __file__)
运行结果:
name:t.c9
package:t
doc:
    This is a c9 doc
file:D:\install\python\t\c9.py
~~~~~~~~~~~~c15~~~~~~~~~~~~~
package:当前模块不属于任何包
name:__main__       
doc:当前模块没有文档注释
file:c15.py                   #入口文件中路径不同 ,和执行python命令所在目录是有关系的

差异: 导入的模块:有package name是模块名字 file是完整的系统路径 入口文件:没有package name是__main__ file是py文件的名字

7 __name__的经典应用

dir()若不传参数可以打印当前模块所有可见的变量,传参显示特定的变量

#c16.py

import sys
infos = dir(sys)
print(infos)

运行结果是打印出很多变量

#c17.py

if __name__ == '__main__':               #内置变量
    print('This is app')

print('This is a module')
运行结果是:This is app
		  This is a module 

#c18.py

import c17
运行结果是:This is a module 

8 相对导入和绝对导入

有一个主入口文件。
顶级包和可执行文件在同一级。
绝对导入:从顶级包开始往下导入
相对导入:. 同级目录 …上级目录 …上上级目录
在相对路径中应使用from import 不能使用 import
不能在入口文件中使用相对路径
相对导入不能超过顶级包。
入口不能使用相对路径导入,相对路径根据__name__定位,由于入口文件被强制改成了__main__所以不能使用。
在入口文件中可以使用绝对路径导入。
若想在入口文件使用相对导入,可以把入口文件当做一个模块来使用,回到PYTHON的上一级,即

用python -m PYTHON.main来执行。

六:Python函数

1 认识函数

# round  传一个参数就是保留整数,传两个参数保留小数点后几位,且四舍五入
a = 3.1415926
print(round(a,2))  

# 查看Python之禅
import this




函数的特性

  1. 功能性
  2. 隐藏细节
  3. 避免编写重复的代码
  4. 组织代码,自定义函数

2 函数的定义及运行特点

def funcname(parameter_list):
    pass

1 参数列表可以没有
2 要有返回值,没有return将会返回None
3 函数必须先定义再调用

# 更改python最大递归深度
import sys
sys.setrecursionlimit(1000)  # 改这个就可以了

# 函数定义的时候不要使用Python内置的变量或函数名称
def print(code):
    print(code)
    
 

传不传参数的区别

def add(x,y):
    result = x+y
    return result

def print_code(code):
    print(code)
a = add(1,2)
b = print_code('Python')
print(a,b)

"""
运行结果
Python
3 None
"""


python返回值的特点

从上面可以看出来,函数定义之后执行是从上带下执行的,没有返回值的时候返回None 使用print方法的时候,会把传的值在同一行进行打印 函数内部的代码碰到return之后,后续的代码是不会执行的了

3 如何让函数返回多个结果

def demage(skill1,skill2):
    demage1 = skill1+2*2
    demage2 = skill2*2+2
    return demage1,demage2
# 序列解包
skill1_demage,skill2_demage = demage(1, 2)
print(skill1_demage,skill2_demage)

# 注:当一个函数中返回多个值的时候,接受的时候最好使用序列解包的方式

4 序列解包与链式赋值

链式赋值

# python的链式赋值
a,b,c = 1,2,3

什么是序列解包呢?

a = 1,2,3
print(type(a)) # <class 'tuple'>元组

a1,a2,a3 = a
print(a1,a2,a3)  # 1 2 3
# 序列解包就是将链式赋值反过来

序列解包就是将链式赋值反过来

5 函数的参数

1 必须参数 --形参和实参

​ 形参是定义时候函数的参数

​ 实参是调用时函数的参数

2 关键字参数

调用的时候明确所传的实参是给那个形参使用的

def add(x,y):
	result = x + y
    return result
c = add(x=12,y=13) # 关键字参数

关键字参数与形式参数的区别在于函数的调用上

3 默认参数

当我们一个函数有很多的参数的时候,调用的时候为了避免过多的传入参水,在函数调用的时候建议使用默认参数

eg:

def add(x,y=None):  # 这个y=None就是传入了默认参数
	result = x + y
    return result
c = add(x=12,y=13) # 关键字参数

默认参数的一个例子

def message(name,gender='男',age=18,college='人民路小学'):
    return (
    f"""
    我的名字是{name},
    我的性别是{gender},
    今年{age}岁,
    我现在在{college}上学
    """
    )
# 想改变一个形参的默认值就在调用的时候传过去就可以了
msg = message(name='andy')  # 这样我们在调用函数的时候就灵活很多了
print(msg)

注:在函数的定义和调用的时候,我们必须将位置参数放在关键字参数的前面

6 变量的作用域

在函数外面定义了变量c,不在函数的作用范围

虽然函数内的c和外部变量名称一样,但是两者没有关系

c = 12
def add(x,y): 
    c = 10
	result = x + y
    return result

add(1,2)
print(c) #打印出来是12,因为这个c是函数外部的c

函数外部定义的变量是全局变量

函数内部定义的变量为局部变量

函数内部可以引用外部变量

函数外部不可以引用函数内部变量

print('~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~')
a = 10
def demo():
	print(a)
demo()

print('~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~')
def demo1():
    c = 50
    for i in range(0,9):
        a = 'a'
        c += 1
    print(c)
    print(a) #可以在for循环外部引用for循环变量
demo()
demo1()

7 作用域链

c = 1
def func1():
    pass
c = 2
def func2():
    pass
c = 3
print(c)
func2()
func1()
# 打印的结果为3

8 global关键字

c = 1
def demo():
    global c
    c = 2
demo()
print(c)
# 用global将局部变量变成全局变量
# 全局变量适用于整个应用程序,不仅仅是自己的模块

七:高级部分--面向对象

1 类的定义

  • 类(Class): 用来描述具有相同的属性和方法的对象的集合。它定义了该集合中每个对象所共有的属性和方法。对象是类的实例。

  • **类变量:**类变量在整个实例化的对象中是公用的。类变量定义在类中且在函数体之外。类变量通常不作为实例变量使用。

  • **数据成员:**类变量或者实例变量, 用于处理类及其实例对象的相关的数据。

  • **方法重写:**如果从父类继承的方法不能满足子类的需求,可以对其进行改写,这个过程叫方法的覆盖(override),也称为方法的重写。

  • **局部变量:**定义在方法中的变量,只作用于当前实例的类。

  • **实例变量:**在类的声明中,属性是用变量来表示的。这种变量就称为实例变量,是在类声明的内部但是在类的其他成员方法之外声明的。

  • **继承:**即一个派生类(derived class)继承基类(base class)的字段和方法。继承也允许把一个派生类的对象作为一个基类对象对待。例如,有这样一个设计:一个Dog类型的对象派生自Animal类,这是模拟"是一个(is-a)"关系(例图,Dog是一个Animal)。

  • **实例化:**创建一个类的实例,类的具体对象。

  • **方法:**类中定义的函数。

  • **对象:**通过类定义的数据结构实例。对象包括两个数据成员(类变量和实例变量)和方法。

类最基本的作用就是封装代码

# c1.py
class Student():
    name = ''
    age = 0
    
    def print_file(self):
        print("name": + self.name)
        print('age: ' + str(self.name))
        
# 我们在使用类的时候,最好在一个模块中值定义类,调用的时候,最好在另一个模块中调用
from c1 import Student
student = Student()  # 类的实例化
student.print_file()  # 调用类里面的方法



2 方法和函数的区别

方法: 设计层面上的,面向对象

函数:程序运行,过程的一种称谓

3 类与对象

类就像一个模板一样,可以产生很多的对象

类:类是现实世界或思维世界中的实体在计算机中的反映,

​ 他将数据以及这些数据上的操作封装到一起

行为对应到类中的方法

属性对应到类中的属性
class Student():
    name = ''
    age = 0
    def do_homework(self):
        print('homework')
        

4 构造函数

构造函数的作用是让模板生成不同的对象

就是初始化类的特征的

在python的类中,构造函数使用下面的方式表示
def __init__(self):
    self.name = name
    
但是要注意的是构造函数最好不要取调用,并不是说不能调用
构造函数不能有返回值,一旦返回一个除了None之外的类型的数据,就会报错

类实例化赋值给一个对象之后,都可以在这个对象后面通过‘.’的方式访问类里面的属性和方法

5 类变量和实例变量

模块中局部变量不会覆盖全局变量

类变量

和类相关联的变量

示例变量

在构造函数中定义的

和对象相关联的变量

class Student:
    # 这是类变量
    sum = 0
    
    def __init__(self,name,age):
        # 下面的是实例变量
        self.name = name
        self.age = age

    def return_name_age(self):
        return f'{self.name}{str(self.age)}'

student1 = Student('鸡小萌',18)
print(student1.name)  # 打印出来的是实例变量
print(Student.name)  # 打印出来的是类变量

在类中定义类变量没有什么实际的意义,因为咱们的类是一个模板,根据实例化的不同而出现不同的对象

但是类变量是应该定义出总体的表示

6 类与对象的变量查找顺序

在构造函数中,只有在变量前加上self才是示例变量,我们使用__dict__查看

Python在找实例变量的时候,如果不存在,就回去类变量中取寻找

7 self与实例方法

  1. 如果我们在类中定义一个示例方法的话,我们必须在该方法的第一个参数放一个self

  2. 我们在调用示例方法的时候,不需要对self传参

  3. sellf代表的是示例,而不是类,就是类实例化后的对象

  4. 示例方法是和对象实例关联的

8 在实例方法中访问实例变量与类变量

方法代表的是类的行为

变量刻画类的特征

方法要操作变量,那在方法中如何操作变量

# 在方法中操作类变量
Student.sum
self.__class__.sum

# 在方法中操作实例变量
self.name

9 类方法

定义:操作类变量的方法,第一个参数是类本身

class Student:
    sum = 0
    def __init__(self,name,age):
        # 下面的是实例变量
        self.name = name
        self.age = age
        self.__class__.sum += 1
        print(f'当前班级的学生总数{self.__class__.sum}')

    def return_name_age(self):
        return f'{self.name}{str(self.age)}'

student1 = Student('鸡小萌',18)
student2 = Student('鸡中萌',18)
student3 = Student('鸡大萌',18)

# 运行结果
"""
当前班级的学生总数1
当前班级的学生总数2
当前班级的学生总数3
"""

示例方法是专门操作实例的,类方法是专门来操作类的

使用@classmethod

class Student:
    sum = 0
    def __init__(self,name,age):
        # 下面的是实例变量
        self.name = name
        self.age = age
        self.__class__.sum += 1
        print(f'当前班级的学生总数{self.__class__.sum}')

    def return_name_age(self):
        return f'{self.name}{str(self.age)}'

    @classmethod
    def plus_sum(cls):
        cls.sum += 1
        # print(f'当前班级的学生总数{cls.sum}')
        print(cls.sum)
        


student1 = Student('鸡小萌',18)
Student.plus_sum()
student2 = Student('鸡中萌',18)
Student.plus_sum()
student3 = Student('鸡大萌',18)
Student.plus_sum()

类和示例中都可以操作类示例,那为什么要有类方法呢,还是上面说的,示例方法只用来操作示例

其实对象也可以来操作类方法

sudent1.plus_sum()

10 静态方法

    @staticmethod
    def add(x,y):
        print('this is staticmethod')

不管是静态方法还是类方法都不可以访问示例变量

其实能用静态方法的地方都是可以用类方法来替代的

同时静态方法和类对象的关联非常的弱

当觉得静态方法和类没有什么联系的时候可以使用

11 成员可见性:公开和私有

对于示例变量的修改,要使用示例方法,从而保证数据的安全

我们给方法或者示例添加双下划线就会变成私有的

# 变成内部私有,外部不可调用
def __mark(self):
        print('mark')

12 没有什么是不能访问

class Student:
    sum = 0
    def __init__(self,name,age):
        # 下面的是实例变量
        self.name = name
        self.age = age
        self.__a = 100  # 定义一个私有变量


	# 实例方法中定义一个私有的变量
    def mark(self,score):
        self.__score = score

        
student1 = Student('鸡小萌',18)
student1.mark(10)  # 这个时候生成了一个_Student__score的示例变量
student1.__score = 1  # 这个时候生成了一个__score的示例变量
print(student1.__score)  # 1
print(student1.__dict__)  # {'name': '鸡小萌', 'age': 18, '_Student__score': 10, '__score': 1}

# 我可以用这种方式来读取私有变量
print(student1._Student__a)  # 100

其实是私有的外部就是不能访问的,但是在定义私有变量的时候,python会将变量在前面加上_类名

13 继承

先定义一个父类Human

# c1.py
class Human():
    sum = 0
    def __init__(self,name,age):
        self.name = name
        self.age = age

    def get_name(self):
        return self.name

然后定义一个字类Student

from c1 import Human

class Student(Human):
    def __init__(self,school,name,age):
        self.school = school
        Human.__init__(self,name,age)  # 实例化父类
        
student1 = Student('andy',1,'任命路小学')
print(Student.sum)
print(student1.name)
print(student1.age)
print(student1.get_name())

这样就实现了类的继承

在子类中重写父类的方法,会覆盖掉父类的方法

14 子类方法调用父类方法:super关键字

只需要在字类的构造函数中

super(Student,self).__init__(name,age)  # 第一个参数是字类名,第二个参数是self

八:正则表达式

1 初识正则表达式

正则表达式是一个特殊的字符序列,一个字符串是否与我们所设定的这样的字符序列相匹配

快速检索文本,实现一些替换文本的操作

1 检查一串数字是否是电话号码

2 检测一个字符串是否符合email

3 把一个文本里指定的单词替换为另外一个单词

import re
a = 'C|C++|Java|C#|Python|Javascript'
r = re.findall('Python',a)  # 查看字符串里面包含Python
print(r)  # ['Python']

2 字符集

import re

a = 'abc, acc, adc, aec, afc, ahc'
# []表示一组字符,就是字符集
r = re.findall('a[cf]c',a)  # 查询第二个字符是f或者c的单词
r = re.findall('a[^cfd]c',a)  # 取反
r = re.findall('a[a-z]c',a)  # 表示范围


print(r)

3 概括字符集

\d 数字

\D 非数字

\w 数字,字母,下划线

\W 非单词字符

\s 空白字符(换行符,制表符,空白字符)

\S 非空白字符

4 数量词

import re
a = 'python231php13213  java'
r = re.findall('[a-z]{3,6}?',a)  # 使用字符集的时候,{}中的数是表示字符重复多少次
print(r)  # ['python', 'php', 'java']

5 贪婪和非贪婪

默认形况下,python使用贪婪模式

# 非贪婪就是在数量级后面加上?
r = re.findall('[a-z]{3,6}?',a) 

6 匹配0次1次或者无限多次

# *匹配0次或多次
# +匹配1次或多次
# ?匹配0或1次

针对于该字符作用的字符,而不是字符串

import re
a = 'pythodadasdpythonsdadpythonnn'
r = re.findall('python*',a)
print(r)
r = re.findall('python+',a)
print(r)
r = re.findall('python?',a)
print(r)

7 边界匹配符

^ 匹配的字符串以作用的字符串开头(匹配字符串的开头)
$ 匹配的字符串以作用的字符串结尾(匹配字符串的结尾)

import re
a = '1000001'
r = re.findall('00$',a)  # 判断字符的结尾是00
print(r)  # []

8 组

就是在匹配字符里面加括号

# []表示或关系
# ()表示且关系
import re
a = 'PythonPythonPythonPythonPythonPythonPython'
r = re.findall('(Python){3}',a)
print(r)  # ['Python', 'Python']

9 匹配模式参数

import re
lanuage = 'PythonC#\nJavaPhp'
r = re.findall('c#',lanuage,re.I)  # re.I就是忽略大小写
print(r)  # ['C#']

r = re.findall('c#.{1}',lanuage,re.I|re.S)  # re.S就是让.除换行符匹配任意字符
print(r) #['C#\n']

10 re.sub正则替换

import re
lanuage = 'PythonC#Phpjava'
r = re.sub('C#','Go',lanuage)  # 实现字符串的替换
print(r)  # PythonGoPhpjava


lanuage = 'pythonC#C#C#C#C#C#Php'
# 第四个参数不写表示替换所有,传几就表示替换几个
r = re.sub('C#','Go',lanuage,1)  # 表示只将第一个C#替换掉
print(r)



# python的内置函数replace也可以实现字符串的替换
lanuage = 'pythonC#C#C#C#C#C#Php'
lanuage = lanuage.replace('python','javascript')
print(lanuage)

sub的第二个参数还可以传入一个函数

import re
lanuage = 'PythonC#PhpC#java'

def convert(value):
    matched = value.group()
    return '!!'+matched+'!!'


r = re.sub('C#',convert,lanuage)  # 实现字符串的替换
print(r)  # Python!!C#!!Php!!C#!!java

12 把函数作为参数传递

示例1:将字符串中的数字大一等于6的替换成9,小于6的替换成0

import re
s = 'A8c3123134Sfdsf63453897456409gh0'

def convert(value):
    matched = value.group()
    if int(matched)>=6:
        return '9'
    else:
        return '0'



# 每找到一个数字,便会调用convert函数
r = re.sub('\d',convert,s)  # 实现字符串的替换
print(r)  # A9c0000000Sfdsf90000999009009gh0



示例2:一个字符串中的两位数,大于等于50的替换成AA,小于50的替换成aa

import re
s = '123456789swwwhh0234146'

def convert(value):
    matched = value.group()
    print(matched)
    if int(matched)>=50:
        return 'AA'
    else:
        return 'aa'

# 每找到一个数字,便会调用convert函数
r = re.sub('\d{2}',convert,s)  # 实现字符串的替换
print(r)  #aaaaAAAA9swwwhhaaaaaa6



13 search与match函数

match:尝试从字符串首字母开始匹配,匹配不到返回None

search:尝试搜索整个字符串,知道找到第一个满足正则表达式的结果,把结果返回

这两个方法匹配到结果之后就立即返回了,不想findall以值匹配到末尾

import re
s = '8B3C4D6E7F2G9'
r1 = re.search('\d',s)
print(r1.group())  # group返回匹配结果
print(r1.span())  # 返回匹配结果在字符串中的位置
r2 = re.match('\d',s)
print(r2.group())
print(r2.span())

r3 = re.findall('\d',s)
print(r3)
"""
运行结果
8
(0, 1)
8
(0, 1)
['8', '3', '4', '6', '7', '2', '9']
"""

14 group分组

s = 'life is short,i use python'
r = re.search('life(.*)python',s)  # .*表示匹配所有的字符
print(r.group(1))  # 在匹配的字符串中加(),表示分组,group()中传1
r = re.findall('life(.*)python',s)  # 其实search完全可以使用findall来代替
print(r)

group和groups

r = re.search('life(.*)python(.*)python',s)
print(r.group(0,1,2))  # 返回一个元组
print(r.groups())  # 除了group(0)的结果都返回出去
"""
('life is short,i use python,i love python', ' is short,i use ', ',i love ')
(' is short,i use ', ',i love ')
"""

勇哥博客园正则表达式详解

九:JSON

一种轻量级的数据交换格式

1理解JSON

JavaScript object Notation

javascript 对象标记

字符串是JSON的表现形式

什么是JSON字符串?

符合JSON格式的字符串叫做JSON字符串

JSON VS XML

之前互联网上面都用的是XML
JSON的优势
	易于阅读
	易于解析
	网络传输效率高
	适合跨语言交换数据
	
	

xml格式的数据

<?xml version="1.0" encoding="UTF-8"?>
<note>
    <to>Tove</to>
    <form>Jani</form>
    <heading>Reminder</heading>
    <body>Dont't forget me this weekend</body>
</note>

    

json

{"name":"andy"}  
是跟pytohn字典类格式类似的数据格式,但是json的内容都是使用双引号的

2 反序列化

把json格式的数据转化成python格式的数据

import json
# json_str = '{"name":"andy","age":18}'
json_str = '[{"name":"andy","age":18,"flag":false},{"name":"andy","age":18}]'
# json.loads将json格式字符串解析成字典
student = json.loads(json_str)  
print(student)

# json格式的数组也可以转换成python格式的
# 由字符串到python的某个格式就做反序列化

json转换成python数据类型

json		python
object		dict
array		list
string		str
number		int
number		float
true		True
false		False
null		None

3 序列化

将python格式的数据转化成json格式的数据

import json
student = [
            {'name': 'andy', 'age': 18, 'flag': False},
            {'name': 'andy', 'age': 18}
            ]

# 序列化
json_str = json.dumps(student)
print(json_str)

NOSQL数据库,MongDB适合存储对象

4 小谈JSON、JSON对象与JSON字符串

JSON对象

JSON

轻量级数据交换格式

JSON字符串

十:Python的高级语法与用法

1 枚举

1-1 枚举其实是一个类

from enum import Enum
class VIP(Enum):
    YELLOW = 1
    GREEN  = 2
    BLACK = 3
    RED = 4

print(VIP.YELLOW)  # VIP.YELLOW

1-2 枚举和普通类相比有什么优势

我们在划分类型的时候会想到普通类和字典

但是上面两种都是可变的

在枚举下面定义的确实不能轻易修改的

from enum import Enum
class VIP(Enum):
    YELLOW = 1
    GREEN  = 2
    BLACK = 3
    RED = 4

print(VIP.YELLOW)
VIP.YELLOW.value = 10
print(VIP.YELLOW.value)  #枚举下面的变量却不能修改

1-3 枚举类型、枚举名称与枚举值

# 如何获取枚举下面标签的数值--通过.value
VIP.YELLOW.value  # 1
# 获取标签的名字
VIP.GREEN.name  # GREEN

print(VIP.GREEN.name)  # 枚举的名字
print(VIP.GREEN.value)  # 枚举的值
print(VIP.GREEN)  # 枚举类型
print(VIP['GREEN'])  # 枚举类型


for i in VIP:
    print(i)  # 通过遍历,可以打印出所有的枚举类型
    

1-4 枚举的比较运算

result = VIP.RED is VIP.RED  # 枚举可以进行身份的比较  
result = VIP.RED == VIP.RED  # 可以进行等值比较

枚举不可以进行大小比较,可以进行身份比较和等值比较

1-5 枚举注意事项

对枚举类型来说,可以让多个类型的值相等,但是在这中情况下第二个值得名字是第一个值名字的别名,遍历的时候也不存在

枚举的类型不能相同

需要将别名打印出来呢

for i in VIP.__members__.items():
    print(i)
# 但是的出来的是元组
"""
('YELLOW', <VIP.YELLOW: 1>)
('GREEN', <VIP.YELLOW: 1>)
('BLACK', <VIP.BLACK: 3>)
('RED', <VIP.RED: 4>)
"""

# 要是想得出枚举的值的话
for i in VIP.__members__:
    print(i)
"""
YELLOW
GREEN
BLACK
RED
"""
    
    

1-6 枚举转换

from enum import Enum
class VIP(Enum):
    YELLOW = 1
    GREEN  = 2
    BLACK = 3
    RED = 4

a = 1
# 类型转换
print(VIP(a))  # VIP.YELLOW  

1-7 枚举小结

我们上面的代码都是枚举值都是数字,那么我们把枚举值定义成字符串使用IntEnum

from enum import IntEnum,unique
class VIP(IntEnum):
    YELLOW = '1'  # 这样就可以定义字符串了
    GREEN  = 2
    BLACK = 3
    RED = 4
    
当我们想让枚举的值不能相同的时候,就在枚举类上加一个@unique这个装饰器
@unique
class VIP(IntEnum):
    YELLOW = '1'  # 这样就可以定义字符串了
    GREEN  = 2
    BLACK = 2
    RED = 4
    
# 运行结果
# ValueError: duplicate values found in <enum 'VIP'>: GREEN -> YELLOW

2 一切皆对象

函数:只是一段可执行的代码,并不是对象

一切皆对象:

另外一个函数的参数,传递到另外的函数

把一个函数当作另外一个函数的返回结果

3 闭包

3-1什么是闭包

闭包=函数+环境变量(函数定义的时候)

内层函数有对外层函数变量的引用

外层函数由对内存函数的调用

def curve_pre():
    a = 25
    def curve(x):
        return a*x*x
    return curve
f = curve_pre()
print(f.__closure__[0].cell_contents)  # 对象环境变量中的参数

print(f(2))
#25
#100

3-2 一个事例看看闭包

闭包返回的是内存函数的现场

def f1():
    a = 10
    def f2():
        a = 20  # 此时的a将会被python认为是局部的变量
        print(a)

    print(a)  # 10
    f2()  # 20
    print(a)  # 10

f1()

3-3 闭包的经典误区

内层函数要有对外层函数变量的引用

3-4 用闭包解决问题

# 非闭包解决问题
origin = 0
def go(step):
    global origin
    origin += step
    return origin
print(go(2))
print(go(4))
print(go(6))



# 闭包函数解决问题
# 函数式编程

origin = 0
def factory(pos):
    def go(step):
        nonlocal pos  # python声明pos不是局部变量
        new_pos = pos + step
        pos = new_pos
        return new_pos
    return go

tourist = factory(origin)
print(tourist(2))
print(tourist(3))
print(tourist(5))

# 闭包记住上一次现场的应用
# 并没有改变全局变量

十一:函数式编程: 匿名函数、高阶函数、装饰器

1 lambda表达式

# 匿名函数
f= lambda x,y: x+y
print(f(1,2))

2 三元表达式

条件为真时返回的结果 if 条件判断 else 条件为假时的返回结果

x = 1
y = 2
r = x if x>y else y
print(r)  # 2

3 map

map第一参数传递一个函数,第二个参数传一个序列,序列的元素依次作用于前面的函数

# 把列表的每一个数都平方,然后返回一个列表
list_x = [1,2,3,4,5,6,7,8]
r = map(lambda x: x**2,list_x)
print(list(r))  # [1, 4, 9, 16, 25, 36, 49, 64]

# map后面可以传入多个参数
list_x = [1,2,3,4,5,6,7,8]
list_y = [1,2,3,4,5,6]
r = map(lambda x,y: x**2,list_x,list_y)
print(list(r))  # 后面传两个参数,将取短
# [1, 4, 9, 16, 25, 36]

并不能提升代码的运行效率,只能使代码更加简洁

5 reduce

# reduce连续调用lambda表达式,将本次结果作为下一次作用的初始值
from functools import reduce
list_x = [1,2,3,4,5,6,7,8]
r = reduce(lambda x,y:x+y,list_x,10)  # 这个10作为一个初始值
print(r)  # 46

# python内置求和函数sum

6 filter

# filter实现过滤,后面的序列依次作用于前面的函数,函数返回True则保留该元素,False则过滤
list_x = [1,3,2,1,21,0,1,2,0,1,0]
r = filter(lambda x:True if x == 1 else False,list_x)
print(list(r))  # [1, 1, 1, 1]

python字符大小写转换

s = 'OUyangAndy'
# upper()将字符转换成大写
# lower()将字符转换成小写
s.upper()  # 'OUYANGANDY'
s.lower()  # 'ouyangandy'

7 装饰器

7-1不带参数的装饰器

import time

def decorator(func):
    def wrapper():
        print(time.time())
        func()
    return wrapper

@decorator
def f1():
    print('this is a function1')

@decorator
def f2():
    print('this is a function2')


f1()
f2()
# 没有改变对象的调用方式
# 遵循python的开放封闭原则,对扩展开放,对修改封闭
# 使用装饰器语法糖@,体现AOP的编程思想

7-2 有参数的装饰器

被装饰对象可以传任意参数

import time

def decorator(func):
    def wrapper(*args,**kwargs):
        print(time.time())
        func(*args,**kwargs)
    return wrapper

@decorator
def f1(name):
    print(f'this is a function1 {name}')

@decorator
def f2(name):
    print(f'this is a function2 {name}')

@decorator
def f3(name,**kwargs):
    print(f'this is a function3 {name}')
    print(kwargs)

f1('andy')
f2('xiaohui')
f3('张三',gender='andy',age=10)

计算一段时间内的星期

def get_week_nums(start_date, end_date):
    """
    计算一段时间内的星期
    返回元素类型是str的列表
    """

    date_index = pd.date_range(start_date, end_date)
    week_s = [str(i.weekday()+1) for i in date_index]
    return week_s

十二:爬取yy直播数据

# 爬取yy直播名字和观看人数
from urllib import request
import requests
import re
import time

class Spider():
    url = 'http://www.yy.com/chicken/cjzc'
    root_pattern = '<a[\s]*?class="box"([\s\S]*?)</a>'
    name_pattern = '<span class="intro">([\s\S]*?)</span>'
    number_pattern = '<span class="usr">([\s\S]*?)</span>'

    # 获取前端代码并且转码
    def __fetch_content(self):
        r = request.urlopen(Spider.url)
        htmls = r.read()
        htmls = str(htmls,encoding='utf-8')

        return htmls
        
    # 分析代码
    def __analysis(self,htmls):
        anchors = []
        root_html = re.findall(Spider.root_pattern,htmls)
        for html in root_html:
            name = re.findall(Spider.name_pattern,html)
            number = re.findall(Spider.number_pattern,html)
            anchor = {'name':name,'number':number}
            anchors.append(anchor) 
        return anchors

    # 完善分析
    def __refine(self,anchors):
        l = lambda anchor:{
            'name':anchor['name'][0].strip(),
            'number':anchor['number'][0]
            }
        return map(l,anchors)

    # 排序
    def __sort(self,anchors):
        anchors = sorted(anchors,key=self.__sort_seed,reverse=True)
        return anchors

    # 排序种子
    def __sort_seed(self,anchor):
        r = re.findall('\d*',anchor['number'])
        anchor = float(r[0])*10000 if '万' in anchor['number'] else float(r[0])
        return anchor

    # 展示代码
    def __show(self,anchors):
        for rank,anchor in enumerate(anchors):
            print('排名:'+str(rank+1)+'  '+anchor['name']+ '-----'+anchor['number'])

    def go(self):
        htmls = self.__fetch_content()
        anchors = self.__analysis(htmls)
        anchors = (list(self.__refine(anchors)))
        anchors = self.__sort(anchors)
        self.__show(anchors)
        print(anchors)


spider = Spider()
spider.go()



    

十三:pythonic

1 异常处理

# 使用字典实现switch
day = 1
switcher={
    0:'Sunday',
    1:'Monday',
    2:'Tuesday'
}
day_name = switcher[day]  # 字典的普通访问方式
day_name = switcher.get(day,'Unkown')  # 使用get访问的时候,即使访问不到也不会报错,会返回一个默认值
print(day_name)


# 字典的value还可以使用函数
day = 0

def get_sunday():
    return 'Sunday'

def get_monday():
    return 'Monday'

def get_tuesday():
    return 'Thuesday'
def get_default():
    return "Unkonw"

switcher={
    0:get_sunday,
    1:get_monday,
    2:get_tuesday
}

day_name = switcher.get(day,get_default)()
print(day_name)


2 列表推导式

a = [1,2,3,4,5,6]
b = [i**2 for i in a]
b = [i**2 for i in a if i >=3 ]
# 元组,集合,字典都可以被推导

# 字典的列表推导式

students = {
    'andy':12,
    'xiaohui':14,
    'zhangsan':16
}
b = [key for key,value in students.items()]  # 新组成的列表里面就都是key了
b = (key for key,value in students.items())  # 使用元组的话会变成生成器

# 生成器取值
for i in b:
    print(i)  

3 None

无论是从类型还是值上面说,None都不等同于'',[],False.....

在我们编程过程中,需要判空的话尽量使用

a = ''
if not a:
    pass

if a:
    pass

None:表示不存在的概念

False:表示假

4 对象存在不一定是True

class Test():
    def __len__(self):
        return 0
    
test = Test()
if test:
    print('S')
else:
    print('F')
    
    

调用布尔判断

class Test():
    def __len__(self):
        return 0
    
test = Test()
print(bool(None))  # False
print(bool([]))  # False
print(bool(test))  # False

5 __len__和__bool__内置方法

__len__表示长度,只可以返回整形或者布尔类型

class Test():

	def __len__(self):
        return 9
print(bool(Test()))