美文网首页
Python入门与进阶

Python入门与进阶

作者: Amok校长 | 来源:发表于2019-08-02 12:15 被阅读0次

导语

Python是一个动态语言.(属于解释型语言,类似的有JavaScript)

Python是一个面向对象的语言. 既有动态脚本的特性, 又有面向对象的特性.

Python相对于编译型语言(c、c++)、Java运行效率慢

第3章 理解什么时写代码与Python的基本类型

什么是写代码?

代码是现实世界事物在计算机世界中的映射.

什么是写代码?

写代码是将现实世界中的事物用计算机语言来描述.

3-1 、Python的基本数据类型

1、Number: 数字

整数: int  
浮点数: float

比如: print(type(2/2)) 打印结果: <class 'float'>
print(type(2//2)) 打印结果: <class 'int'>

/是除法,结果会自动转成浮点数;
//是整除,结果会自动转换成整数.

10进制: 1,2,3,4,5,6,7,8,9,10...
2进制: 0,1,10,11...
8进制: 0,1,2,3,4,5,6,7,10...
16进制:0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F

在Python里表示不同的进制:
0b10 二进制10 =2
0o10 八进制10 =8
0x10 十六进制10 =16

各进制之间的转换:
bin() 把其他进制转换为2进制;比如: bin(0o7)
oct() 把其他进制转换为8进制;
int() 把其他进制转换为10进制;
hex() 把其他进制转换为16进制;

bool 布尔类型:
    非0为真 True
    0和空值和none为假 False

complex 复数

2、str字符串

'双单引号'
"双引号"
'''三引号'''
"""三引号""" 三引号可显示长字符及换行字符,除了print时转义字符有效,其他情况下转义字符无效.

\ 转义字符:(三种)
    特殊的字符
  无法"看见"的字符 比如:\n换行;\t横向制表符;\r回车
  与语言本身语法有冲突的字符

r显示原始字符串:
  print(r'c:\northwind\northwest')
  打印结果:c:\northwind\northwest

字符串的运算:
  用+拼接字符串,比如: "hello"+"world"
    用*重复字符串,比如: "hello"*3
  截取字符串中第几个字符,比如: 
    "hello"[3] 输出:l
    "hello"[-1] 输出:o
    "hello"[0:2] 输出:he (:是切片操作)
    "hello"[0:-1] 输出:hell (从0到倒数第一个字符之间的字符)
    "hello"[-2:] 输出:lo (从倒数第二个到末尾)
    "hello"[:-3] 输出:he (从开头到倒数第三个之间的字符)

3、序列与集合

列表- list []
  列表运算 跟 字符串运算 操作一致;
    嵌套列表.
  
元祖- tuple ()
    元祖运算 跟 字符串运算 操作一致;
  注意:元祖()跟数学运算()的区分,比如定义只有一个元素的元祖,(1,),也就是加个逗号
    定义一个空元祖:()
       
str list tuple 都是序列.
//序列共有操作:
  除去相同的运算操作外,以下也是,以序列中list为例,
  3 in [1,2,3,4]  3是否在list中,
  3 not in [1,2,3,5]  3是否不在list中,
  len([1,2,3,4,5])  列表的元素个数,
  max([1,2,3,4,5]) 列表中最大值,通过ASSIC码来比较的,输出ASSIC码的值用ord(),比如: ord('d')
  min([1,2,3,4,5]) 列表中最小值
  
  
集合- set {} 
  无序的,没有索引,不属于序列,无法进行序列运算操作
  里面元素不重复
  支持长度判断,比如:len({1,2,3})
  支持包含判断,比如:1 not in {1,2,3}
  求两个集合差集,比如:{1,2,3,4,5,6} - {3,4} 
  找出两个集合中共有元素,比如: {1,2,3,4,5,6} & {3,4}  
  两个集合合并成一个,并且无重复元素,(并集)比如: {1,2,3,4,5,6} | {3,4,7}
  如何定义一个空集合: set()
      
字典- dict {key:value}
    并不是序列类型,是集合类型
  字典中不能有相同的key,key必须是不可变类型.
  定义一个空的字典: {}

第5章 变量与运算符

5-1、变量

= 赋值符号
变量名规范: 
    首字符不能是数字,
    变量名只能是字母、数字、下划线,
    系统关键字(保留关键字)不能用在变量名中
变量没有类型限制,不需要声明变量类型

int str tuple 是值类型(不可改变), list set dict(可变) 是引用类型,比如:
    a = 1
    b = a
    a = 3
    print(b) 此时输出1
    a = [1,2,3]
    b = a
    a[0] = '1'
    print(b) 此时输出['1',2,3]
    print(id(b)) 输出b的内存地址

总结:
    值类型: 不可改变值,只能让指针指向新值来实现改变;
    引用类型: 可改变值,直接在旧值的基础上添加或删除数据,指针不变,依然指向旧址.

5-2、运算符

算法运算符:(对数字运算)
  +  加
  -  减
  [1]*3 = [1,1,1] 乘
  /  除
  3//2 = 1 整除
  5%2 = 1 余数
  2**5 = 32 二的5次方

赋值运算符:(先做运算再赋值)
  =
  -=
  +=
  *=
  /=
  %=
  **=
  //=
  
比较(关系)运算符:(返回布尔结果)
  ==
  !=
  >
  <    
  >=
  <=
  总结: ord('a')//比较的是对应的ASCII值,输出a的ASCII码值

逻辑运算符:(返回布尔值)
  and 并且 比如:1 and 3 //输出3
  or  或者 比如: 1 or 2 //输出1
  not 非
  总结: int float中,0被认为是False,非0表示Ture; 对于字符串类型,空字符串被认为是False,否则为True.
    运算优先级: not>and>or.比如:1 or 2 and 3 //输出1
  
成员运算符:(一个元素是否在另一组运算符里)
  in
  not in
  总结: 这里特别注意,判断某个字符是否在字典中存在,判断的是key是否和这个字符相同.
  
身份运算符:(判断两个变量是否相等)
  is
  is not
  总结: 关系运算符比较的两个变量的值是否相等; 身份运算符比较的是两个变量身份(内存地址)是否相等.
  
位运算符:(把数字当做二进制数进行运算)
    & 按位与 比如: a=2 b=3 a&b输出:2. 解析:a转化二进制为1 0 ,b转化二进制为1 1,当同位对应的数为都为1时为1,同位上一个为1一个为0时为0,所以结果是1 0
  | 按位或  解析: 只要两个数转二进制后,同位上有一个为1,那么就为1
  ^ 按位异或
  ~ 按位取反
  << 左移动
  >> 右移动
  
对象三个特性: 值(id)、身份(value)、类型(type)
//判断变量类型方法一:
type('hello') == int 输出:False
//判断变量类型方法二(推荐):
isinstance('hello',str)  输出:True
isinstance('hello',(int,str,float))  输出:True (是否是元祖中任意类型是任意一种)

第6章 分支、循环、条件与枚举

6-1 表达式

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

6-2 vscode开发工具—Python插件

1. Python
2. Terminal 想在另一个IDE里运行代码,比如小程序开发
3. view in Browser
4. Vim
5. vscode Icon

6-3 流程控制语句---(解决选择性问题)

1. 条件控制--- if else 可以判断变量和表达式,比如下面例子:
  mood = True
  if mood:
      print('go to left')
  else :
        print('go to right')

2. 循环控制--- for while

3. 分支--- switch (Python里面没有switch)

6-4 注释

# 单行注释 

'''
多行注释
'''

6-5 Python代码特点

# 语句结束时;不是必须的, 一般情况下省略
# 通过缩进(四个空格)来做代码包裹
# Python建议用_来组合两个单词的命名
# Python里面并不存在真正意义上的常量, (假装)常量命名规范是单词大写,比如: ACCOUNT - 'qiyue'
# 比较运算符的两侧各加一个空格
# pass 空语句/占位语句
# Python规定一行里面的字符个数不能超过80个, 换行的方法一:末尾加\ ,这样就可以下一行继续编写代码. 方法二:用() 比如下面的例子:
    from c9 import a,b,\
    c
    from c9 import (a,b,
    c) 
#

第7章 包、模块、函数与变量作用域**

7-1 循环

# while循环
counter = 1
while counter <= 10 :
    counter += 1 # while代码块内必须有影响条件判断的语句,否则出现死循环
    print(counter)
else:
    print('所有元素都遍历完,打印这里')
    
# for循环 主要是用来遍历/循环 序列或者集合、字典 
a = ['apple','orange']
for x in a:
    print(x,end='') # 默认情况下,print打印出来的数据,呈现列的排布print(x,end='\n');想让每个元素都在一行打印出来 print(x,end='')
else:
    print('所有元素都遍历完,打印这里')
    
# for循环---区间   
for x in range(10,20,2):# 创建一个递增序列,从10开始循环到19,步长为2
    print(x,end='|') # 打印: 10|12|14|16|18
for x in range(20,10,-2):# 创建一个递减数列,从20开始循环到11,步长为-2 
    print(x,end='|') # 打印: 20|18|16|14|12
 
### break 和 continue 区别:
b = [1,2,3]
for x in b:
    if x ==2:
        break # 终止循环操作, 并且不会执行else语句; 如果是嵌套循环,break不会影响外部的循环继续
    print(x) # 打印: 1
    
c = [1,2,3]
for x in c:
    if x ==2:
        continue # 跳过本次循环, 还会打印else语句
    print(x) # 打印: 1 3
    
### 思维拓展: 取出数组d,等差数列,步长为2
    d = [1,2,3,4,5,6,7,8]
方法一:
  for i in range(0,len(d),2)
        print(d[i],end='')
方法二:
  b = d[0:len(d):2]
  print(b)

7-2 Python项目的组织结构

包 (文件夹) #想让一个普通的文件夹变成包,在文件夹下创建一个__init__.py文件,__init__.py的模块名就是包名

模块 (.py文件)

类

函数和变量

7-3 模块的导入

# 在同一个包中, c8.py中导入使用c7.py里的变量和函数
在c7.py中:
  a = 2
  
在c8.py中:
  import c7
  print(c7.a) //使用c7模块的变量
  
# 在不同包中, c8.py中导入使用t包下的c7.py里的变量和函数
在t包下的c7.py中:
  __all__ = ['a','c']//sp1
  a = 2
  b = 3
  c = 4

在c8.py中:
  方法一:(导入具体模块)
  import t.c7 as m
  #print(t.c7.a) 此时命名空间过长,用as简化
  print(m.a)
  方法二:(导入具体变量/模块/函数)
  from t.c7 import a,b,c
  print(a)
  方法三: (*默认导入所有变量,如果不想导入所有变量,需配合sp1导入部分变量)
  from t.c7 import * //sp2
  print(a) 
  print(c)
  print(b)//无法打印,因为sp1没有导入b

7-4 vscode中设置---隐藏不想显示的文件/文件夹

让文件目录中隐藏 __pycache__缓存文件夹
#匹配文件路径所依据的 glob模式,设置为true或false可启用或禁用该模式
用户设置>>搜索files.exclu>>进行下面的操作👇:
  // 配置 glob 模式已排除文件和文件夹.
  "files.exclude":{
    "**/.git":true,
    "**/.svn":true,
    "**/.hg":true,
    "**/CVS":true,
    "**/.DS_Store":true,
    "**/__pycache__":true //添加这行
  }

7-5 包下init文件的使用场景

#包和模块是不会被重复导入的
#避免循环导入,比如: p1.py导入p2.py,同时p2.py也导入p1.py,就会出现循环的导入
#导入.py文件,会执行一次所导入.py文件里的代码.(并且不管导入多少次,也只执行这一次)

当一个包被导入的时候,会先执行__init__.py文件
通常会在包的__init__.py文件做一些初始化的工作

# 应用一:不同包情况下,c11.py中导入t包

在t包下的__init__.py文件中:
  __all__ = ['c7'] # 这里只定义了c7
  
在t包下的c7.py文件中:
  __all__ = ['a','c']
  a = 2
  c = 3
  d = 4
  
在t包下的c8.py文件中:
  e = 2
  f = 3
  g = 4
 
在c11.py中
    from t import *
  print(c7.a) # 打印:2
  print(c8.e) # 无法打印,因为没有导入c8
  
  
# 应用二: 批量导入库
  在t包下的__init__.py文件中:
    import sys
    import datetime #引入多个包
    import io
  
  其他包的c13.py文件中t
        import t
    print(t.sys.path) #导入t就可以使用t导入的sys包了

小技巧:
终端清屏: clear

第8章 Python函数

8-1 函数

a = 1.12386
print(round(a,2)) #round函数给a保留两位小数(四舍五入),输出: 1.12

# python默认最大递归数是995次,可以设置最大递归数如下:
import sys
sys.setrecursionlimit(996)#数可以任意设置

#定义一个函数(一个返回值)
def add(x,y):  //x和y是形参
    result = x + y
    return result
b = add(1,2) //1和2是实参
print(b)

#定义一个函数(多个返回值)
def damage(skill1, skill2):
    damage1 = skill1 * 3
    damage2 = skill2 *2 + 10
    return damage1, damage2
damages = demage(3,6)
print(type(damages)) #输出: <class 'tuple'>
skill1_damage, skill2_damage = damage(3,6) #序列解包接收结果
print(skill1_damage, skill2_damage)

#序列解包
a = 1
b = 2
c = 3
可简写成: a,b,c = 1,2,3
  
a,b,c = 1,1,1
可简写成: a=b=c=1 #链式赋值
  
d = 1,2,3
print(type(d)) #输出:<class 'tuple'>
a,b,c = d #序列解包,这里要使接收变量和返回值个数相同
  

8-2 参数

1.必须参数 #按顺序传参

2.关键字参数#可以不按顺序传参
    def add(x,y):
        result = x + y
      return result
    c = add(y=3, x=2) 
  
3.默认参数 #默认按形参顺序传, 可以用关键字参数方式传
    def add(name,age,x=10,y=13): #必须将必须参数和关键字参数分开调用,不要混合调用
        result = x + y
      return result

第9章 高级部分: 面向对象

9-1定义类

# 在c1.py中:
class Student():
    name = 'shiyue' #类变量
    age = 0
    sum1 = 0
    
    #定义构造函数,只能返回None
    def __init__(self,name,age): 
        self.name = name# 定义实例变量
        self.age = age
            print(Student.sum1)# 打印类变量,方法一
            print(self.__class__.sum1)# 打印类变量,方法二
        self.__class__.sum1 += 1
        print('当前班级学生总数为:' + str(self.__class__.sum1))
        
    #定义实例方法
    def print_file(self):
        print('name:' + self.name) # 调用本类的属性,必须加self
        print('age:' + str(self.age))
        
    #定义类方法
    @classmethod
    def plus_sum(cls):
        cls.sum1 += 1
        print(cls.sum1)# 调用本类的属性,必须加cls
    
    #定义静态方法:(不推荐使用,完全可以被类方法取代)
    @staticmethod
    def add(x,y):
        print('This is a static method')
        print(Student.sum1)#调用类的属性
        
student = Student('石敢当',18)#实例化时,自动调用__init__函数
student.print_file()#方法 和 函数的区别:方法是设计层面; 函数:程序运行,过程式的一种称谓
print(student.__dict__) #打印实例student里面所有的变量
print(Student.__dict__) #打印类Student里面所有的变量

# 从另外一个模块中引用类:
from c1 import Student
student = Student()
student.print_file()#调用实例方法
Student.plus_sum()#调用类方法
student.add(1,2)
Student.add(1,2)#类和实例变量都可以调用静态方法


##### Python寻找相关变量的机制:
如果我们尝试去访问一个实例变量,Python首先会尝试在实例变量里面查找有没有这个变量; 如果没有,Python不会立即返回None,它会在类变量里面寻找有没同名的变量; 如果有,把这个类变量的值返回出来.

9-2 可见性

class Student():
  
  def __init__(self, name, age):
        self.name = name
      self.age = age
      self.__score = 0#严格意义上讲,Python是没有私有变量的,它只是把私有变量变成了: _类名__私有变量名 这样一个变量
  
  def marking(self, score):
      if score < 0:
          return '不能够给别人打负分'
      self.__score = score
      print(self.name + '同学本次考试分数为:' + str(self.__score))
      
  def __siyou(self, name):
            print('从外部强制访问此私有方法会报错')
      
student1 = Student('石敢当', 18)
result = student1.marking(-1)
print(result)
student.score = -1
# 总结: 
# 不要直接在外部给变量赋值,会使数据不可限制,不安全; 建议通过方法给变量赋值,进行操控,可以保护变量.
# 一旦只在方法或变量前面加了双下划线(__),Python就会认为你这个方法或变量是私有的.
# 前后都加双下划线(__)是Python内置函数和变量的风格,非私有.

9-3 面向对象三大特性

# 继承性 -- 实例变量、类变量都是可以继承的. 支持多继承.
    在c6.py中
    class Human():#最好一个模块文件定义一个类
        sum = 0
        def __init__(self, name, age):
            self.name = name
          self.age = age
          
      def get_name(self)
            print(self.name)
  在其他.py中
    from c6 import Human
  class Student(Human):# 让Student类继承Human类
            def __init__(self, school, name, age):
            self.school = school
          #在子类里调用父类的构造函数,方法一:(不推荐下面这样调用)
          Human.__init__(self, name, age) #为什么这里要传self?这里只是类调用一个普通方法,所以要传self,用实例调用的话就不用传self
          #在子类里调用父类的构造函数,同样调用父类的普通实例方法也是这样写,方法二:(推荐)
          super(Sutdent, self).__init__(name, age)
          
student1 = Student('人民路小学','石敢当', 18)
print(student1.sum) # 输出: 0
print(Student1.sum) # 输出: 0
print(student1.name) # 输出: 石敢当
print(student1.age) # 输出: 18
student1.get_name() # 输出: 石敢当

# 封装性
# 多态性

第10章 正则表达式与JSON

快读检测文本、实现一些替换文本的操作

10-1 正则表达式— 查找re.findall()

import re

# 查找字符串中的'Python'字符(普通字符)
a = 'c|c++|Java|c#|Python|Javascript'
r = re.findall('Python',a)#'Python'字符为一组进行查询
print(r) #返回一个列表: ['Python']

# 查找字符串中的所有'数字'字符(元字符)
a = 'c0c++7Java8c#9Python6Javascript'
r = re.findall('\d',a)
print(r) #输出: ['0','7','8','9','6']

# 查找字符串里,单词中间是'c'或是'f'的单词
s = 'abc, acc, adc, aec, afc, ahc'
r = re.findall('a[cf]c',s)# 在[]内字符是"或"关系
r = re.findall('a[^cfd]c',s)# 在[]内字符是"或"关系,^是取反操作
r = re.findall('a[c-f]c',s)# 在[]内字符是"或"关系,-这里是c到f的意思
print(r) 

# 概括字符集,都可以用字符集表示出来
\d  数字
\D  非数字
\w  单词字符 A-Za-z0-9_
\W  非单词字符 空格、\t、&、\n、\r
\s  空白字符 
\S  非空白字符
.   匹配除换行符\n之外其他所有字符

# 数量词
a = 'python 1111java678php'
r = re.findall('[a-z]{3}',a) #从字符串中匹配3个a-z的字符,3个字母为一组
r = re.findall('[a-z]{3,6}',a) #贪婪匹配,匹配3到6个a-z的字符
##数量词-贪婪和非贪婪
默认情况下,Python正则匹配倾向贪婪模式.
'''
* 匹配0次或无限多次
+ 匹配1次或无限多次
? 匹配0次或者1次.  (在?前有范围时,用做贪婪非贪婪转换; ?前是固定字符时,用作匹配0次或1次.)
'''
r = re.findall('[a-z]{3,6}?',a) #非贪婪匹配, 通过?转换为非贪婪模式
a = 'pytho0python1pythonn2'
r = re.findall('python*',a) # *前面的这个字符匹配0次或无限次
r = re.findall('python+',a) # +前面的这个字符匹配1次或无限次
r = re.findall('python?',a) # ?前面的这个字符匹配0次或1次 输出:['pytho','python','python'],能打印出来第二个'python'是因为,'pythonn2'中'n2'前的'python'是符合匹配的. 因此可以用?做去重的操作.

# 边界匹配---^$
# ^表示以某字符为开头开始匹配,$表示以某字符为末尾开始匹配
qq = '10000001'
r = re.findall('^\d{4,8}$',qq) #qq号是否满足4-8位

# 组----()
a = 'PythonPythonPythonPythonPythonPython'
r = re.findall('(Python){3}',a) # 'Python'为一组,重复3次,进行匹配

# 匹配模式参数--- re.I(忽略大小写), re.S(改变.的匹配行为,使得.能够匹配到换行符\n)
lanuage = 'PythonC#\nJavaPHP'
r = re.findall('c#',lanuage,re.I) # 第三个参数(匹配模式)设置为re.I,使的匹配忽略字母大小写
r = re.findall('c#.{1}',lanuage,re.I | re.S) #这里的|是且关系, 输出: ['C#\n']

10-2 正则表达式--字符替换re.sub()

'''
re.sub(pattern, repl, string, count=0, flags=0)
参数一: pattern表示: 正则表达式
参数二: repl表示: 匹配成功之后,需要替换成功的字符串
参数三: string表示: 要搜索的原字符串
参数四: count表示: 能匹配的最大次数,默认0(表示将无限制的匹配下去)
参数五: flags表示: 匹配模式参数
'''
import re
lanuage = 'PythonC#\nJavaC#PHPC#'
r = re.sub('C#', 'GO', lanuage,1)#将lanuage里的'C#'字符替换为'GO'字符
lanuage = lanuage.replace('C#','GO')# 是sub的简化版替换

# 第二个参数可以传入一个函数: 可以实现根据不同的匹配结果实现不同的替换
def convert(value):
    print(value) #打印出来是个对象,携带的额外信息中:span表示匹配所在位置,match表示匹配内容
    matched = value.group()#value对象的分组信息,获取到'match'信息里的字符
    retun '!!' + matched + '!!'
r = re.sub('C#', convert, lanuage,1)#当正则匹配到一个结果后,它会把结果传递到函数里面去,函数的返回结果将作为替换字符串

##例子: 把函数作为参数传递
s = 'ABC3721D86'
def conver(value):#替换字符串中的数字字符,>5的替换为9,不大于5的替换为0
    matched = value.group()
    if int(matched) >= 6:
        return '9'
    else:
        return '0'
r = re.sub('C#', convert, lanuage,1) 

10-3 re.match和re.search

# 这两个函数跟findall功能跟用法几乎一样,但没有findall好用,一般用findall.
import re
s = 'ABC3721D8E67'
r = re.match('\d',s) #打印出来是:None
print(r.span())#打印匹配到的位置
r = re.search('\d',s) #打印出来是一个匹配对象
print(r.group())#打印匹配到的值

re.match和re.search总结: 
  不同点:
  match的特点是: 从字符串的首字母开始匹配,如果match没有找到相应的匹配结果,那么它将返回一个None. 上面例子中因为开头不是数字所以没有匹配到结果;
  search的特点: 搜索这个字符串,直到找到第一个满足正则表达式的结果.然后将这个匹配结果返回回来.
  
  共同点:
  它们匹配到之后都会返回一个对象,例如返回值:<_sre.SRE_Match object; span=(0, 1),match='8'>;
    匹配到一个结果后,立即停止搜索.(findall会一直搜索)
  
# 分组: 
s = 'life is short,i use python'#正则找出'lift'和'python'之间的内容
r = re.search('life(.*)python',s)
print(r.group(1))#group(0), 默认参数是0,参数表示组号,方便选择第几组的内容.
## 总结: 正则表达式用()来进行分组, 访问分组的话用.group(); group函数默认参数是0,永远代表正则所有内容.()分组的话必须从1开始访问. 特别说明:findall不存在这种问题.
r = re.findall('life(.*)python',s)
print(r)#打印结果同上

# 多个分组
s = 'life is short,i use python, i love python'
r = re.search('life(.*)python(.*)python',s)
print(r.group(0))
print(r.group(1))
print(r.group(2))
print(r.group(0,1,2))#简写上面三个打印, 输出一个元祖
print(r.groups())#输出一个元祖,对比上面打印:只会打印()分组部分,没有完整匹配.

10-4 理解JSON

JavaScript Object Notation 翻译过来: JavaScript对象标记

JSON 是一种轻量级的数据交换格式.
字符串是JSON的表现形式(载体).
JSON同样遵循EMSSCRIPT,是跟js平行的一种语言.

JSON、JSON字符串 区别:
    符合JSON格式的字符串叫做 JSON字符串; 
  JSON 是一种轻量级的数据交换格式

优点: 易于阅读, 易于解析, 网络传输效率高, 跨语言交换数据

import json

# 反序列化
josn_str = '{"name":"qiyue", "age":18}'
student = json.loads(json_str)#json转Python数据类型
print(type(student))#打印出来: <class 'dict'>

# json对应python的转换类型
json            python
object      dict
array           list
string      str
number      int
number      float
true            True
false           False
null            None

# 序列化
student = [
            {'name': 'qiyue', 'age': 18, 'flag':False},
            {'name': 'qiyue', 'age': 18}
          ]
json_str = json.dumps(student) #python数据类型转换成json字符串
print(type(json_str)) # <class 'str'>

如果一定要存储对象到数据库,建议用NOSQL数据库,否则效率太低,强烈反对对象序列化!

第11章 Python的高级语法与用法

11-1 枚举--Enum

# 定义枚举
from enum import Enum # 枚举值可以是任意类型
class VIP(Enum):
        YELLOW = 1
        GREEN    = 2
        BLACK = 3
        RED = 'str'
print(VIP.YELLOW)#获取枚举的类型(<class 'str'>),打印: VIP.YELLOW  
print(VIP.YELLOW.name)# 获取标签的名字(<enum 'VIP'>),打印: YELLOW
print(VIP.YELLOW.value)# 获取枚举值

'''
和普通类相比,枚举的特点:
不可变
防止相同值的功能(类似常量,所以建议大写)
'''

# 遍历枚举
for v in VIP:
    print(v)

# 枚举的比较运算
枚举类型只能与枚举类型进行等值(==)比较, 不支持枚举间进行大小(><)比较;
枚举间可以进行身份(is)比较.

# 枚举转换--- 把数字转换成枚举类型
a = 1
print(VIP(a)) #打印: VIP.YELLOW

# Enum 和 IntEnum区别
from enum import IntEnum #枚举值只能是数字
class VIP(IntEnum):
        YELLOW = 1
        GREEN    = 1
        BLACK = 3
        RED = 4
    
# 限制枚举里有相同的值
from enum import IntEnum,unique #unique不允许有相同的枚举值
@unique
class VIP(IntEnum):
        YELLOW = 1
        GREEN    = 2
        BLACK = 3
        RED = 4
    
枚举是一种单利模式,不用初始化.

11-2 函数式编程—闭包

# 函数式编程
# 闭包
# 在python里面函数是一个对象
# python里一切皆对象

# 闭包 = 函数+环境变量(函数定义时的外部变量)
def f1():
    a = 10
    def f2():
        # a被python认为是一个局部变量
            c = 20 * a
    return f2
f = f1()
print(f)


# 修改全局变量的值,来记录上次的状态---非闭包的方式解决旅行者行走多少步的问题
origin = 0
def go(step:)
        global origin # 声明为全局变量
    new_pos = origin + step
    origin = new_pos
    return new_pos
print(go(2))
print(go(3))
print(go(1))

# 使用闭包来记录上次的状态---闭包的方式解决旅行者行走多少步的问题
origin = 0
def factory(pos):
    def go(step):
        nonlocal pos # 闭包的环境变量,有保存现场的功能,可以记忆上一次调用的状态
        new_pos = pos + step #这种写法让pos成为了一个环境变量, 具有保存状态的能力(记忆上一次调用的状态)
        pos = new_pos
        return new_pos
    return go
tourist = factory(origin)#这里设置初始值factory(0)
print(tourist(3))# 这里类似调用go(3)
print(tourist(3))
print(tourist(2))
# 总结: 代码规范大全中, 函数中尽量少的使用全局变量, 所以推荐闭包
#在函数的外部间接调用函数内部的值
#闭包因为环境变量有保存状态的能力,所以要小心内存泄漏的问题

第12章 函数式编程: 匿名函数、高阶函数、装饰器**

12-1 匿名函数

# 用lambda声明一个匿名函数的定义
lambda parameter_list: expression #parameter_list对应参数部分, expression对应表达式(函数定义部分,不能是代码块),比如下面匿名函数👇
f = lambda x,y: x+y
print(f(1,2))
相当于下面的普通函数:
def add(x,y):
    return x+y
print(add(1,2))

lambda用三元表达式比较多.
# python版本的三元表达式:
条件为真时返回的结果 if 条件判断 else 条件为假时的判断结果
  比如:如果x和y, 如果x>y, 就返回x, 否则返回y.
    r =  x if x > y else y
    print(r)

# map函数用法---映射
list_x = [1,2,3,4,5,6,7,8]
def square(x):
    return x * x
r = map(square,list_x)#遍历list的每一项,并且每一项都作为参数,去执行一个函数.
print(r)#打印出一个map对象
print(list(r))#将打印出来的map对象转化为一个列表

# map(映射)与lambda结合使用
## 传入一个参数
list_x = [1,2,3,4,5,6,7,8]
r = map(lambda x: x*x, list_x) # 用lambda表达式代替上面的例子
print(list(r))
## 传入两个或多个参数---结果集合个数,取几个参数中较少元素的集合的个数.
list_x = [1,2,3,4,5,6,7,8,9,10]
list_y = [1,2,3,4,5,6,7,8]
r = map(lambda x, y: x*x + y, list_x, list_y) 
print(list(r))# 得到的集合个数是8个

# 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) #连续计算, 连续调用lambda: 上一次的计算结果,作为这一次的参数进行计算
print(r)#相等于:(((((((1+2)+3)+4)+5)+6)+7)+8)
##reduce第三个参数
list_x = ['1','2','3','4','5','6','7','8']
r = reduce(lambda x,y:x+y, list_x, 'aaa')
print(r)#输出:aaa12345678

# filter(过滤)与lambda结合使用
list_x = [1,0,1,0,0,1]
filter(lambda x: True if x==1 else False, list_x)#过滤掉list中的0 , 返回False会被剔除掉
print(list(r))#输出:[1,1,1]

12-2 函数式编程VS命令式编程

命令式编程,比如:
def 
if else
for

函数式编程,比如:
map reduce filter
lambda(算子)

12-3 装饰器

# 原则: 对修改是封闭的, 对扩展是开放的
#      我们可以接受定义时候的复杂, 不接受调用时候的复杂.
import time
def f1():
    print('This is a function')
def f2():
    print('This is a function')
# 让所有的函数都添加一个方法, 比如:给f1和f2前,添加一个打印时间戳的功能
## 方案一:
def print_current_time(func):
    print(time.time())#unix 时间戳--定义为从格林或治时间1970年01月01日00时00分
    func()
print_current_time(f1)
print_current_time(f2)#这方案的弊端:添加的打印时间方法,并不是f1和f2本身的
## 方案二: 装饰器
def decorator(func):
    def wrapper():
        print(time.time())
        func()
    return wrapper
f = decorator(f1)
f()#同样没有解决方案一的弊端
## 方案三: 装饰器的语法糖✅
def decorator(func):
    def wrapper():
        print(time.time())
        func()
    return wrapper
@decorator
def f1():
    print('This is a function')
f1() #妙在没有改变原来调用的逻辑. 

# 装饰器支持函数带参数的情况
def decorator(func):
    def wrapper(func_name):
        print(time.time())
        func(func_name)
    return wrapper
@decorator
def f1(func_name):
    print('This is a function' + func_name)
f1('test func') 

# 装饰器支持带多个参数的情况
def decorator(func):
    def wrapper(*args):
        print(time.time())
        func(*args)
    return wrapper
@decorator
def f1(func_name):
    print('This is a function' + func_name)   
@decorator
def f2(func_name1,func_name2):
    print('This is a function' + func_name1)
    print('This is a function' + func_name2)
f1('test func') 
f2('test func1','test func2')

# 装饰器的完整形态,可以传入任意值
def decorator(func):
    def wrapper(*args, **kw):
        print(time.time())
        func(*args, **kw)
    return wrapper
@decorator
def f1(func_name):
    print('This is a function' + func_name)   
@decorator
def f2(func_name1,func_name2):
    print('This is a function' + func_name1)
    print('This is a function' + func_name2)
@decorator
def f3(func_name1, func_name2, **kw):#**关键字参数
    print('This is a function' + func_name1)
    print('This is a function' + func_name2)
    print(kw)
f1('test func') 
f2('test func1','test func2')
f3('test func1','test func2', a=1, b=2, c='1,2,3')

#总结: 装饰器最基本的思想:如果我们想对某一个封装的单元(比如函数),做出一个代码上的修改的话,可以不去改动具体实现,而是通过装饰器这样一种形式来改变函数的行为.
也就是说如果想改变函数的功能, 又不想改变它的内部代码实现.那么装饰器是很好的解决方案.

第13章 实战:原生爬虫**

13-1 爬虫步骤

爬虫前奏:
  明确目的
  找到数据对应的网页
  分析网页的结构找到数据所在的标签位置
模拟HTTP请求, 向服务器发送这个请求, 获取到服务器返回给我们的HTML
用正则表达式提取我们要的数据(名字, 人气)

爬虫框架: BeautifulSoup , Scrapy

13-2 爬取主播姓名和在线观看人数

from urllib import request #python自带的网络请求框架
class Spoder():
    url = 'https://www.panda.tv/cate/lol'
    root_pattern = '<div class="video-info">([\s\S]*?)</div>'
    name_pattern = '</i>([\s\S]*?)</span>'
    number_pattern = '<span class="video-number">([\s\S]*?)</span>'
    
    def __fetch_content(self):#sp1.创建一个私有函数,获取全部数据
        r = rquest.urlopen(Spider.url)
        htmls = r.read()#获取到请求后的内容
        htmls = str(htmls, encoding='utf-8')#获取到的bytes数据转字符串
        return htmls
        
    def __analysis(self, htmls):#sp2.创建私有函数,正则匹配出想要的数据
        root_html = re.findall(Spider.root_pattern, htmls)
        anchors = [] #定义一个列表
        for html in root_html:
            name = re.findall(Spider.root_pattern, html)
            number = re.findall(Spider.number_pattern, html)
            anchor = {'name':name, 'number':number}
            anchors.append(anchor)
        return anchors
      
    def _refine(self, anchors):#sp3.创建私有函数,数据精炼,变成我们想要的结构
        l = lambda anchor:{'name':anchor['name'][0].strip(),
                            'number':anchor['number'][0]
                          } #去除文本里面的换行符和空格
        return map(l, anchors)
    
    def __sort(self, anchors):#sp4.创建私有函数,数据排序
            #filter
        anchors = sorted(anchors,key=self.__sort_seed,reverse==True)#根据key来进行大小排序,reverse反序排序
        return anchors
    
    def __sort_seed(self,author): #sp4-2.创建一个私有函数,为sp4提供可比较大小的key       
                r = re.findall('\d*',anchor['number']) #提取这一个文本中的数字
        number = float(r[0])#转换为float
        if '万' in anchor['number']
                number *= 10000
        return anchor['number']
                         
    def __show(self, anchors):#sp5.创建私有函数,展示数据
      # for anchor in anchors:
      #     print(anchor['name'] + '-------' + anchor['number'])
        for rank in range(0, len(anchors)):
            print('rank' + str(rank + 1)
                  + ':' + anchors[rank]['name']
                  + '  ' + anchors[rank]['number'])
        
    def go(self):#作为调用私有方法的入口方法
        htmls = self.__fetch_content()
        anchors = self.__analysis(htmls)
        two_anchors = list(self.__refine(anchors))
        three_anchors = self.__sort(two_anchors)
        self.__show(three_anchors)
        
spider = Spider()
spider.go()


''' 断点调试的几个快捷键:
启动应用程序F5,
单步执行F10,
一个断点跳到下一个断点F5,
进入某一个函数或对象的内部F11
'''

关于注释:
方法注释、类注释和模板注释用''' ''', 其中方法注释写在方法里面, 而不是方法上面;
单行注释推荐写在代码上面# ;
函数行数最好控制在10-20行之内

第14章 Pythonic与Python杂记

14-1 用字典映射代替switch case语句

day = 6

def get_sunday():
    return 'Sunday'

def get_monday():
    return 'Monday'
  
def get_tuesday():
    return 'Tuesday'
  
def get_default():
    return 'Unkown'
  
switcher = {
    0 : get_sunday,
    1 : get_monday,
    2 : get_tuesday
}

# day_name = switcher[day] #用下标的方式来访问,如果没有对应项会报错
day_name = switcher.get(day,get_default)() #如果找不到值的情况下返回 'Unknown'
print(day_name)

14-2 列表推导式

#列表推导式
#集合推导式
# 使用map filter也可以实现列表推导式,不过稍微复杂.
# set 也可以被推导
# dict 也可以被推导
根据一个已经存在的列表, 来推导一个新的列表, 就用到列表推导式.(set集合和dict也可以被推导)

a = [1,2,3,4,5,6,7,8]
# 用列表推导式,使a的每一个元素平方, 生成一个新的列表. 
b = [i**2 for i in a]
print(b)#输出:[1,4,9,16,25,36,49,64] 

# 在列表推导式里做筛选,a里面元素>=5的才平方,生成一个新列表
b = [i**2 for i in a if i>=5]
print(b)#输出: [25,36,49,64]

# 集合使用列表推导式
a = {1,2,3,4,5,6,7,8}
b = [i**2 for i in a if i>=5]#外面用[]包裹则生成列表
print(b)#输出: [25,36,49,64]
b = {i**2 for i in a if i>=5}#外面用{}包裹则生成set集合
print(b)#输出: {25,36,49,64}

# 字典的列表推导式
students = {
    '喜小乐': 18,
    '石敢当': 20,
    '横小五': 15
}
b = [key for key,value in students.items()]
print(b)#输出: ['喜小乐', '石敢当', '横小五']
b = {value:key for key,value in students.items()}#让原字典key和value做颠倒,生成新字典
元祖是不可变的,不建议转元祖

14-3 None

None 类型和值都不等于 空字符串、空列表、0、False.
print(type(None))#输出 <class 'NoneType'>

所以做判空操作, 用if a: 或 if not a: ,别用 if a is None.
    
# 对象存在不一定是True
class Test():
    def __len__(self):
        return 0
test = Test()
if test:
    print('s')
else:
    print('F')

相关文章

网友评论

      本文标题:Python入门与进阶

      本文链接:https://www.haomeiwen.com/subject/idfldctx.html