Python 学习笔记

一、基础知识

1、输出函数print()

  1. print() 可以输出数字、字符串、表达式;
  2. 换行/不换行输出;
  3. 将数据输出到文件中;
  4. 转义字符。
# 输出字符串
print('hello world')
# 输出数字
print(520)
print(98.5)
# 输出表达式
print(3+1)
# 将数据输出到文件中
fp = open('D:/text.txt','a+') # a+:如果文件不存在就创建,存在就在文件内容后面继续追加
print("hello world",file = fp)
fp.close()
#不换行输出
print('hello','world','Python')
# 转义字符
print('hello\nworld')
print('hello\tworld')
print('helloooo\tworld')
# \b:退格
print('hello\bworld')
# world将hello覆盖了
print('hello\rworld')

print('http:\\\\www.baidu.com')
print('老师说:\'大家好\'')
# r/R 是原字符,不希望字符串中的转义字符起作用,就用原字符。最后一个字符不能是反斜杠
print(r'hello\nworld')

2、字符编码

  1. 对于单个字符的编码,Python提供了以下两个函数:
    1) chr(i):用来返回整数i所对应的Unicode字符。
    2) ord():用来返回对应字符的ascii码。
# ASCII
print(chr(20056))
print(ord('乘'))
  1. 如果要在网络上传输,或者保存到磁盘上,就需要把str变为以字节为单位的bytes。
    1) bytes类型的数据用带b前缀的单引号或双引号表示,如 x=b’ABC’。
    2) 以Unicode表示的str通过encode()方法可以编码为指定的bytes。
    (1) 纯英文的str可以用ASCII编码为bytes,内容是一样的。
    (2) 含有中文的str可以用utf-8编码为bytes。
    (3) 含有中文的str无法用ASCII编码,因为中文编码的范围超过了ASCII编码的范围。
print('ABC'.encode('ascii'))
print('中国'.encode('utf-8'))
# print('中国'.encode('ascii')) # 报错UnicodeEncodeError
  1. 如果我们从网络或磁盘上读取了字节流,那么读到的数据就是bytes。要把bytes变为str,就需要用decode()方法。如果bytes中只有一小部分无效字节,可以传入errors='ignore’忽略错误的字节。
print(b'ABC'.decode('ascii'))
print(b'\xe4\xb8\xad\xe6\x96\x87'.decode('utf-8',errors='ignore'))

3、保留字和标识符

  1. 保留字
    python import keyword print(keyword.kwlist)
  2. 标识符
    ① 变量。函数、类、模块和其他对象起的名字就叫标识符
    ② 区分大小写

4、变量

  1. 变量由标识、类型、值三部分组成。
    标识:表示对象所存储的内存地址,使用id(obj)来获取
    类型:表示的是对象的数据类型,使用type(obj)来获取
    值:表示对象存储的具体数据,使用print(obj)直接打印输出

5、数据类型

  1. 整数
  2. 浮点数
    ① 使用浮点数进行计算时,可能会出现小数位数不确定的情况。
    ② 导入decimal模块。
from decimal import Decimal
print(Decimal('1.1')+Decimal('2.2'))
  1. 布尔类型
    ① True为真,False为假
    ② 布尔值可以转化为整数
# 布尔类型
f1 = True
f2 = False
print(f1,type(f1))
print(f2,type(f2))

# 布尔值可以转成整数计算
print(f1+1)
print(f2+2)
  1. 字符串类型
    ① 不可变的字符序列
    ② 可以使用单引号’'、双引号"“、三引号”“”“”"来定义
    ③ 单引号和双引号定义的字符串必须在一行,三引号定义的字符串可以分布在连续的多行
    ④ 要计算str包含多少个字符,可以用len()函数。如果换成bytes,len()函数计算的是字节数。
    ⑤ 字符串是数组,可以使用str[i]来获取字符。
    ⑥ Python中的内置方法:
    1. strip()方法删除开头和结尾的空白字符。
    2. lower()返回小写的字符串。
    3. upper()方法返回大写的字符串。
    4. replace()用另一段字符串来替换字符串。
    5. split()方法在找到分隔符的实例时将字符串拆分为子字符串。
    6. 字符串串联使用+连接。
    7. 可以使用format()方法对结果进行格式化。使用{}充当占位符。
    1)可以在花括号内添加参数以指定如何转换值;
    2)如需使用更多值,只需向 format() 方法添加更多值;
    3)可以使用索引号(花括号 {0} 内的数字)来确保将值放在正确的占位符中;
    4)还可以通过在花括号 {carname} 中输入名称来使用命名索引,但是在传递参数值 txt.format(carname = “Ford”) 时,必须使用名称。
    8. join()方法使用哈希字符作为分隔符,将元组中的所有项目连接到字符串中。
    9. find()和index()方法在字符串中搜索指定的值并返回它被找到的位置。如果找不到指定值,find()返回-1,index()报错。
    10. 所有的字符串方法都返回新值,不会改变原始字符串。
# 字符串类型
str1 = '人生苦短,我用Python'
str2 = "人生苦短,我用Python"
str3 = """人生苦短,
我用Python
"""
print(str1)
print(str2)
print(str3)
print(len(str1)) # 计算字符串长度
print(str1[1])
print(str1[2:5])

# 字符串方法
print('----------strip()删除开头和结尾的空白字符----------------')
a = ' Hello,world! '
print(a.strip())
print('----------lower()----------------')
print(a.lower())
print('----------upper()----------------')
print(a.upper())
print('----------replace()----------------')
print(a.replace('world','Python'))
print('----------split()----------------')
print(a.split(','))
print('----------检查字符串 in , not in----------------')
print('Hello' in a)
print('----------字符串串联使用+连接----------------')
b1 = 'Good '
b2 = 'Morning'
b = b1 + b2
print(b)
print('----------format()----------------')
age = 20
gender = 'boy'
txt = 'My name is Bill, I am {} years old,and I am a {}.'
print(txt.format(age,gender))
quantity = 3
itemno = 567
price = 52
myorder = "I want {0} pieces of item number {1} for {2:.2f} dollars."
print(myorder.format(quantity, itemno, price))
myorder = "I have a {carname}, it is a {model}."
print(myorder.format(carname = "Porsche", model = "911"))
print('----------join()----------------')
new_str = '*'.join(str1)
print(new_str)
print('----------find()------------')
print(txt.find('name'))
print('----------index()------------')
print(txt.index('name'))
  1. 格式化
    1) 通过使用 % 运算符来格式化字符串。
    2) 在字符串内部,%s 表示用字符串替换, %d 表示用整数替换, %f 表示用浮点数替换,有几个 %? 占位符,后面就跟几个变量或者值,括号可以省略。格式化整数和浮点数还可以指定是否补0和整数与小数的位数。
    3) 使用format()方法格式化字符串,他会用传入的参数依次替换字符串内的占位符{0}、{1}等。
    4) f-string:是一种用以f开头的字符串格式化字符串的方法,字符串中如果包含{xxx},就会以对应的变量替换。
# 格式化
print('Hello,%s' % 'world')
print('Hi,%s,you have $%d.' % ('Michael',1000000))
print('%2d-%03d' % (3,1))
print('%.2f' % 3.1415926)
print('Hello,{0},数学考了{1:.1f}'.format('小明',98))
r = 2.5
s = 3.14 * r ** 2
print(f'The area of a circle with radius {r} is {s:.2f}')

6、数据类型转换

  1. str()将其他类型转换成str类型
  2. int()将其他类型转换成int类型
    注意:① 文字类和小数字符串不可转;② 浮点数转化成整数,抹零取整
  3. float()将其他类型转换成float类型
    注意:① 文字类无法转换;② 整数转成浮点数,末尾为.0
print('-------------------str()将其他类型转换成str类型')
a = 10
b=198.7
c=False
print(str(a),str(b),str(c),type(str(a)),type(str(b)),type(str(c)))

print('--------------------int()将其他类型转换成int类型')
s1='128'
s2=98.7
s3='hello'
s4=True
print(int(s1),type(int(s1))) # 将str转换成int类型,字符串只能是整数串
print(int(s2),type(int(s2)))
# print(int(s3),type(int(s3)))
print(int(s4),type(int(s4)))

print('--------------------float()将其他类型转换成float类型')
s1='128.98'
s2=98
print(float(s1),type(float(s1)))
print(float(s2),type(float(s2)))
print(float(s4),type(float(s4)))
# print(float(s3),type(float(s3)))

7、Python注释

  1. 单行注释:以#开头
  2. 多行注释:将一对三引号之间的代码称为多行注释
  3. 中文编码声明注释:
    在文件开头写# -- coding:utf-8 --,标识的是该文件的编码方式为utf8。

8、输入函数input()

  1. 基本使用:input()函数的结果是str类型
#输入函数input()
present=input('输入提示')
print(present,type(present))
a = int(input('请输入一个数:'))
b = int(input('请输入另一个数:'))
print(a+b)

9、运算符

  1. 算术运算符
# 算术运算符
print(1+1)
print(3-1)
print(2*4)
print(11/2)
print(11//2) # 整除运算
print(-9//-2)
print(9//-2) # 一正一负向下取整
print(-9//2)
print(11%2) # 取余运算:余数=被除数-除数*商
print(9%-2) # 9-(-2)*(-5)=-1
print(-9%2) #-9-2*(-5)=1
print(2**3) # 幂运算
  1. 赋值运算符
    ① 执行顺序:右→左
    ② 链式赋值:a=b=c=20
    ③ 支持参数赋值:+=、-=、*=、/=、//=、%=
    ④ 支持系列解包赋值:左右变量的个数与值的个数对应
print('------------赋值运算符--------')
a=b=c=20 # 链式赋值
print(a,id(a))
print(b,id(b))
print(c,id(c))

print('--------支持参数赋值----------')
a=20
a+=30
print(a)
a-=10
print(a)
a*=2
print(a)
a/=3
print(a,type(a))
a//=2
print(a,type(a))
a%=2
print(a,type(a))

print('--------支持系列解包赋值-----------')
a,b,c=20,30,40
print(a,b,c)

print('-----交换两个变量的值-----')
a,b=10,20
print('交换前:',a,b)
a,b=b,a
print('交换后:',a,b)
  1. 比较运算符:结果为True或False
# 比较运算符
a,b=10,10
print('a>b吗?',a>b)
print('a,a<b)
print('a>=b吗?',a>=b)
print('a<=b吗?',a<=b)
print('a==b吗?',a==b) # ==比较的是值 is 比较的是地址(标识)
print('a is b?',a is b)
print('a is not b?',a is not b)
print('a!=b吗?',a!=b)
lst1=[11,22,33,44]
lst2=[11,22,33,44]
print('lst1 == lst2?',lst1 == lst2)
print('lst1 is lst2?',lst1 is lst2)
  1. 布尔运算符:and、or、not、in、not in
# 布尔运算符
a,b = 1,2
print(a==1 and b==2) # and 且
print(a==2 or b==2) # or 或
print(not a==1) # not 非
print('---------in 与 not in----------')
s = 'hello world'
print('w' in s)
print('k' in s)
print('w' not in s)
  1. 位运算符:
    ① 按位与 &:同为1结果为1,其余为0
    ② 按位或 |:同为0时结果为0,其余为1
    ③ 左移位:向左移动一位相当于乘以2(高位溢出低位补0)
    ④ 右移位:向右移动相当于除以2(高位补0低位溢出)
# 位运算符
print(4&8) # 按位与:同为1时结果为1,其余为0
print(4|8) # 按位或:同为0时结果为0,其余为1
print(4<<1) # 左移位:向左移动一位
print(4<<2) # 向左移动两位
print(4>>1) # 右移位:向右移动一位
print(4>>2) # 向右移动两位
  1. 运算符的优先级
    算术运算(**、*,/,//,%、+,-)>位运算(<<,>>、&、|)>比较运算>布尔运算(and、or)>赋值运算(=)

二、程序的组织结构

1、顺序结构

  1. 从上到下顺序执行代码,中间没有任何判断和跳转,直到程序结束。
  2. 对象的布尔值:Python一切皆对象,所有对象都有一个布尔值。
    使用内置函数bool()获取对象的布尔值
  3. 以下对象的布尔值全为False:False、数值0、None、空字符串、空列表、空元组、空字典、空集合。
# 对象的布尔值
print(bool(False))
print(bool(0))
print(bool(0.0))
print(bool(None))
print(bool(''))
print(bool([])) # 空列表
print(bool(list())) # 空列表
print(bool(())) # 空元组
print(bool(tuple())) # 空元组
print(bool({})) # 空字典
print(bool(dict())) # 空字典
print(bool(set())) # 空集合

2、选择结构

  1. 单分支结构
  2. 双分支结构
  3. 多分支结构
  4. 嵌套if
# 单分支结构
money=1000
s=int(input('请输入取款金额:'))
# 判断余额是否充足
if money>=s:
    money-=s
    print('取款成功,余额为:',money)

# 双分支结构
'''从键盘录入一个整数,判断是奇数还是偶数'''
num=int(input('请输入一个整数:'))
if num%2==0:
    print(num,"是偶数")
else:
    print(num,"是奇数")

# 多分支结构
'''从键盘录入一个整数成绩,判断成绩的范围'''
score=int(input('请输入一个整数成绩:'))
if score>=90 and score <=100:#也可写成 90<=score<=100
    print('A')
elif score>=80 and score<90:
    print('B')
elif score>=70 and score<80:
    print('C')
elif score>=60 and score<70:
    print('D')
elif score>=0 and score<60:
    print('E')
else:
    print('成绩无效')

# 嵌套if
'''会员:购物金额≥200打8折,≥100打9折,否则不打折
    非会员:购物金额≥200打9.5折,否则不打折
'''
answer=input('您是会员吗?y/n')
money=int(input('请输入您的购物金额:'))
if answer=='y':
    if money>=200:
        print('打8折,付款金额为:',money * 0.8)
    elif money>=100 and money<200:
        print('打9折,付款金额为:',money * 0.9)
    else:
        print('不打折,付款金额为:',money)
else:
    if money>=200:
        print('打9.5折,付款金额为:', money * 0.95)
    else:
        print('不打折,付款金额为:', money)
  1. 条件表达式:是if-else的简写
# 条件表达式
num_a=int(input('请输入第一个整数:'))
num_b=int(input('请输入第二个整数:'))
print((num_a,'大于等于',num_b) if num_a >= num_b else (num_a,'小于',num_b))
  1. pass语句:语句什么都不做,只是一个占位符,用在语法上需要语句的地方。
# pass语句
answer=input('您是会员吗?y/n')
if answer=='y':
    pass
else:
    pass

3、循环结构

  1. 内置函数range():用于生成一个整数序列
    1. range()的三种创建方式
      (1) range(stop):创建一个[0,stop)之间的整数序列,步长为1
      (2) range(start,stop):创建一个[start,stop]之间的整数序列,步长为1
      (3) range(start,stop,step):创建一个[start,stop]之间的整数序列,步长为step
    2. 返回值是一个迭代器对象
    3. 不管range对象表示的整数序列有多长,所有range对象占用的内存空间都是相同的,只需存储start,stop和step。
    4. in 与 not in 判断整数序列中是否存在(不存在)指定整数
#range()的三种常见方式
'''1. range(stop)'''
r=range(10)
print(r)
print(list(r)) # 用于查看range对象中的整数序列 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
'''2. range(start,stop)'''
r=range(1,10)
print(list(r)) # [1, 2, 3, 4, 5, 6, 7, 8, 9]
'''3. range(start,stop,step)'''
r=range(1,10,2)
print(list(r)) # [1, 3, 5, 7, 9]

'''判断指定整数是否在序列中 in 或 not in'''
print(10 not in r)
print(9 in r)
  1. while循环:判断n+1次,条件为True执行n次。
# while循环
'''1到100之间的偶数和'''
a=1
sum=0
while(a<=100):
    if a%2==0:# not bool(a%2)
        sum+=a
    a+=1
print('1-100之间的偶数和为',sum)
  1. for-in循环
    1. in 表示从(字符串、序列等)中依次取值,又称为遍历
    2. 遍历的对象必须是可迭代对象(字符串、序列等)。
    3. 如果在循环体中不需要使用自定义变量,可将自定义变量写为’_‘。
'''输出100-999之间的水仙花数
    水仙花数:153=3^3+5^3+1^3
'''
for item in range(100,1000):
    ge=item%10 # 个位
    shi=item//10%10 # 十位
    bai=item//100 # 百位
    # print(bai,shi,ge)
    if (ge**3 + shi**3 + bai**3) == item:
        print(item)
  1. 流程控制语句
    1) break
    (1) 用于结束循环结构。
    (2) 直接跳出当前循环。
    2) continue:结束当前循环,进入下一次循环。
    3) else:可以与if、while、for配合使用。
# break语句
for _ in range(1,4):
    pwd = input('请输入密码:')
    if pwd=='8888':
        print('密码正确')
        break
    else:
        print('密码错误')
# continue 语句
for item in range(0,51):
    if item%5!=0:
        continue
    print(item)
# else语句
# for _ in range(3):
#     pwd = input('请输入密码:')
#     if pwd=='8888':
#         print('密码正确')
#         break
#     else:
#         print('密码错误')
# else:
#     print('三次密码输入错误')

a=0
while a<3:
    pwd = input('请输入密码:')
    if pwd=='8888':
        print('密码正确')
        break
    else:
        print('密码错误')
    a+=1
else:
    print('三次密码输入错误')
  1. 嵌套循环:外层循环执行一次,内层循环执行完整的一轮。
# 嵌套循环
'''产生一个三行四列的矩形'''
for _ in range(1,4):
    for _ in range(1,5):
        print('*',end='\t') # 不换行输出
    print()

'''打印出99乘法表'''
print()
for i in range(1,10):
    for j in range(1,i+1):
        print(i,'*',j,'=',i*j,end='\t')
    print()
  1. break和continue在二重循环用于控制本层循环
# break和continue在二重循环的使用
print('---------break在二重循环的使用--------')
for i in range(1,5):
    for j in range(1,10):
        if j%2==0:
            break
        print(j)
print('---------continue在二重循环的使用--------')
for i in range(1,5):
    for j in range(1,10):
        if j%2==0:
            continue
        print(j)

三、列表

1、列表的创建

  1. 通过[]进行创建
  2. 使用内置函数list()创建
  3. len()函数可以获取列表中元素的个数
# 列表
lst1 = ['hello','world',98] # 使用方括号创建
lst2 = list(['hello','world',98]) # 使用内置函数list()创建
print('lst1:',lst1)
print('lst2:',lst2)
print(len(lst1))

2、列表的特点

  1. 列表元素按顺序有序排序
  2. 索引映射唯一一个数据
  3. 列表可以存储重复数据
  4. 任意数据类型混存
  5. 根据需要动态分配和回收内存

3、列表的查询操作

  1. 获取指定元素的索引:index(‘item’)
    1) 如果列表中存在N个相同元素,只返回相同元素中第一个元素的索引
    2) 如果查询的元素在列表中不存在,则会抛出ValueError
    3) 还可以在指定的start和stop之间进行查找[start,stop)
# 列表的查询操作
lst1 = ['hello','world',98,'hello']
print(lst1.index('hello'))
# print(lst1.index('python'))
print(lst1.index('hello',1,4))
  1. 获取列表中的单个元素
    1) 正向索引从0到N-1,如:lst[0]
    2) 逆向索引从-N到-1,如:lst[-N]
    3) 指定索引不存在,抛出IndexError
# 获取列表中的单个元素
lst1 = ['hello','world',98,'hello',234]
print(lst1[2]) # 正向索引
print(lst1[-3]) # 逆向索引
# print(lst1[5]) # IndexError: list index out of range
  1. 获取列表中的多个元素
    1) 语法格式:列表名[start:stop:step]
    2) 切片操作
    (1) 切片的结果:原列表片段的拷贝
    (2) 切片的范围:[start,stop)
    (3) step默认为1:简写为[start,stop)
    (4) step为正数:从start开始往后计算切片
    ① [:stop:step] : 切片的第一个元素默认是列表的第一个元素
    ② [start::step]:切片的最后一个元素默认是列表的最后一个元素
    (5) step为负数:从start开始往前计算切片
    ① [:stop:step]:切片的第一个元素默认是列表的最后一个元素
    ② [start::step]:切片的最后一个元素默认是列表的第一个元素
# 获取列表中的多个元素
lst=[10,20,30,40,50,60,70,80]
lst2=lst[1:4:1]
print(lst2)
print('原列表地址:',id(lst))
print('切片地址:',id(lst2))
print(lst[1:6]) # step默认为1
print(lst[1:6:]) # step默认为1
print(lst[:6:2]) # start默认为0
print(lst[1::2]) # stop采用默认
print('------------step步长为负数的情况-------------')
print(lst[::-1]) # 列表逆序
print(lst[7::-1]) # stop省略
print(lst[6:0:-2])
  1. 列表元素的查询操作
    1) 判断指定元素在列表中是否存在
    (1) 元素 in 列表名
    (2) 元素 not in 列表名
    2) 列表元素的遍历
    for 迭代变量 in 列表名:
    操作
# 列表元素的判断及遍历
lst=['hello','world',98,'python']
print(98 in lst) # True
print(98 not in lst) # False
print('good' in lst) # False
print('good' not in lst) # True
print('----------列表元素的遍历-----------')
for item in lst:
    print(item)
  1. 列表元素的增删改操作
    1) 增加元素
    (1) append():在列表的末尾添加一个元素(如果添加的是列表,则把这个列表看作一个元素)。
    (2) extend():在列表的末尾一次性添加多个元素(如果添加的是列表,则将该列表中的元素依次添加)。
    (3) insert():在列表的任意位置添加一个元素。
    (4) 切片:在列表的任意位置添加至少一个元素。
'''增加元素'''
lst=[10,20,30]
print('添加元素之前',lst,id(lst))
lst.append(40) # 在列表的末尾添加一个元素
print('添加元素之后',lst,id(lst))
lst2=['hello','world']
# lst.append(lst2) # 如果添加的是列表,则把这个列表看作一个元素
# print(lst)
lst.extend(lst2) # 在列表的末尾一次性添加多个元素
print(lst)

# 在任意位置上添加一个元素
lst.insert(1,90)
print(lst)

# 使用切片在任意位置上添加n多个元素
lst3=[True,False,'hello']
lst[1:]=lst3
print(lst)
	2) 删除元素
			(1) remove():从列表中移除一个元素,如果有重复元素,则只删第一个元素,元素不存在抛出ValueError。
			(2) pop():根据索引移除元素,如果不指定索引,将删除列表中的最后一个元素,指定索引不存在抛出IndexError。
			(3) 切片:切片操作删除至少一个元素,将产生一个新的列表对象。
			(4) clear():清空列表
			(5) del:删除列表对象
'''删除元素'''
lst=[10,20,30,40,50,60,30]
lst.remove(30) # 从列表中移除一个元素,如果有重复元素,则只删第一个元素
print(lst)

lst.pop(1) # 根据索引移除元素
print(lst)
lst.pop() # 如果不指定索引,将删除列表中的最后一个元素
print(lst)

print('-------切片操作删除至少一个元素,将产生一个新的列表对象------')
new_lst=lst[1:3]
print('原列表',lst)
print('切片后的列表',new_lst)

'''不产生新的列表对象,删除原列表中的内容'''
lst[1:3]=[]
print(lst)

'''clear()清除列表中的所有元素'''
lst.clear()
print(lst)

'''del语句将列表对象删除'''
del lst
# print(lst) # 报错,列表对象已被删除
	3) 修改元素
		(1) 为指定索引的元素赋予一个新值。
		(2) 为指定的切片赋予一个新值。
'''修改元素'''
lst=[10,20,30,40]
# 一次修改一个值
lst[2]=100
print(lst)
# 一次修改多个值
lst[1:3]=[300,400,500,600]
print(lst)

4、 列表元素的排序操作

  1. 调用sort()方法:升序排序,在括号中指定reverse=True,进行降序排序,在原列表的基础上排序。
  2. 调用内置函数sorted():升序排序,在括号中指定reverse=True,进行降序排序,原列表不发生变化。
	# 列表元素的排序操作
	lst=[20,40,10,98,54]
	print('----调用sort()方法排序-------')
	print('排序前的列表',lst,id(lst))
	lst.sort() # 升序排序 省略了reverse=False
	print('升序排序后的列表',lst,id(lst))
	lst.sort(reverse=True) # 降序排序
	print('降序排序后的列表',lst,id(lst))
	print('----调用内置函数sorted()排序,将产生一个新的列表对象-------')
	lst=[20,40,10,98,54]
	print('排序前的列表',lst)
	new_lst=sorted(lst) # 升序排序
	print('升序排序后的列表',new_lst)
	desc_lst=sorted(lst,reverse=True) # 降序排序
	print('降序排序后的列表',desc_lst)

5、 列表生成式

  1. 语法格式:[i*i for i in range(1,10)]
  2. 注意:表示列表元素的表达式(如i*i)中通常包含自定义变量。
  3. for循环后面还可以加上if判断。如果把if写在for前面,必须加上else。
  4. 还可以使用两层循环。
# 列表生成式
lst=[i*i for i in range(1,10)]
print(lst)
lst2 = [i * i for i in range(1,10) if i % 2 == 0]
print(lst2)
lst3 = [i  if i % 2 == 0 else -i for i in range(1,10)]
print(lst3)
'''使用两层循环生成全排列'''
lst4 = [m + n for m in 'ABC' for n in 'XYZ']
print(lst4)

6、生成器

  1. 在Python中,一边循环一边计算的机制,称为生成器:generator。
  2. 创建生成器:把列表生成式的[]改为()
  3. 可以通过next()函数获得generator的下一个返回值,直到最后抛出StopIteration错误表示无法继续返回下一个值。
  4. 可以使用for循环遍历生成器中的元素。
g = (i*i for i in range(1,10))
# print(next(g))
for x in g:
    print(x)
  1. 如果一个函数定义中包含yield关键字,那么这个函数就不再是一个普通函数,而是一个generator函数,调用一次generator函数将返回一个generator对象。
    generator函数在每次调用next()时执行,遇到yield语句返回,再次执行时从上次返回的yield语句处继续执行。
# 斐波那契数列
def fib(max):
    n,a,b = 0,0,1
    while n < max:
        yield b
        a,b = b, a + b
        n = n + 1
    return 'done'
'''使用for循环调用generator时,拿不到generator的return语句的返回值。'''
for n in fib(6):
    print(n)

四、元组

1、基本概念

1、元组是有序且不可变的序列。
2、语法格式:thistuple = (‘张三’,‘李四’,‘王五’)
3、更改元组值:将元组转换为列表,再将列表转换为元组。
4、只有一个元素的tuple定义时,必须加一个逗号,来消除歧义。
5、如果元组中有可变序列,那么元组看起来也是“可变”的。
6、确定元组长度,用len()方法。
7、count()方法返回元组中指定值出现的次数
8、index() 方法在元组中搜索指定的值并返回它被找到的位置,如果有多个相同值,则返回第一个值的位置。

# 元组
'''创建元组'''
thisTuple = ('张三','李四','王五','apple','banana','lemon')
'''通过构造函数tuple()创建元组'''
thisTuple2 = tuple(('apple','banana','lemon'))
'''创建空元组'''
t = ()
print(thisTuple)
print(thisTuple2)
print(t)
print(thisTuple[1]) # 元组中第二个元素
print(thisTuple[-1]) # 元组中最后一个元素
print(thisTuple[2:5]) # 切片返回多个元素

'''只有一个元素的元组'''
t1 = (1,)
print(t1)

'''无法删除元组中的元素,只能删除整个元组'''
tuple1 = ['a','b','c','d']
del tuple1
# print(tuple1) # NameError: name 'tuple1' is not defined

# 更改元组值
fruit = ('apple','banana','cherry','lemon')
y = list(fruit)
y[1] = 'watermelon'
fruit = tuple(y)
print(fruit)

# "可变"元组
t2 = ('a','b',['A','B'])
t2[2][0] = 'X'
t2[2][1] = 'Y'
print(t2)
# 确定元组长度
print(len(t2))

# 合并元组
tuple1 = ('a','b','c','a')
tuple2 = (1,2,3)
tuple3 = tuple1 + tuple2
print(tuple3)

# count()方法
print('a的个数:',tuple1.count('a'))
#index()方法
print('a的位置:',tuple1.index('a'))

五、字典

  1. 字典与列表一样,是一个可变序列。
  2. 以键值对的方式存储数据,字典是一个无序序列。
  3. 语法格式:thisDict = {‘name’:‘张三’,‘age’:18}
  4. 通过字典名[‘键名’]或字典名.get(‘键名’)来访问字典的元素。
  5. 可以通过引用其键名来更改特定项的值,也可以使用update()方法向字典中添加。
  6. 使用values()函数返回字典的值。
  7. 通过使用items()函数遍历键和值。
  8. 确定字典有多少键值对,使用len()方法。
  9. 嵌套字典:字典中包含字典。
  10. fromkeys() 方法返回具有指定键和值的字典,语法:dict.fromkeys(keys, value)。
  11. setdefault() 方法使用指定的键返回项目的值。如果键不存在,则插入这个具有指定值的键。
# 字典
'''创建字典'''
thisDict = {
    'name':'张三',
    'age':18,
    'gender':'男'
}
print(thisDict)
'''使用dict()构造函数创建字典'''
thisDict2 = dict(brand='Porsche',model='911',year=1963)
print(thisDict2)
'''通过方括号内引用其键名来访问字典的元素'''
name = thisDict['name']
print(name)
'''通过get()访问字典的元素'''
age = thisDict.get('age')
print(age)

'''更改元组内元素的值'''
thisDict['gender'] = '女'
print(thisDict)

# 遍历字典的键
for item in thisDict:
    print(item)

# 使用values()函数返回字典的值
print(thisDict.values())

# 通过使用items()函数遍历键和值
for key,value in thisDict.items():
    print(key,value)

# 确定字典中是否存在指定的键,使用 in 关键字
if 'name' in thisDict:
    print(True)

# 确定字典有多少键值对,使用len()方法
print(len(thisDict))

# 向字典中添加键值对
thisDict['school'] = 'QUT'
print(thisDict)
thisDict.update({'class':'Software'})
print(thisDict)

# 删除键值对
'''pop()方法删除具有指定键名的项'''
thisDict.pop('age')
print(thisDict)

'''popitem()删除最后一个键值对'''
thisDict.popitem()
print(thisDict)

'''del 关键字删除具有指定键名的键值对'''
del thisDict['name']
print(thisDict)

'''clear()清空字典'''
thisDict.clear()
print(thisDict)

'''del 删除字典对象'''
del thisDict
# print(thisDict)

# 复制字典
'''使用copy()方法来复制字典'''
dict1 = {
    'name':'Mike',
    'age':20,
    'gender':'男'
}
mydict = dict1.copy()
print('mydict:',mydict)

'''使用dict()方法创建字典的副本'''
dict2 = dict(dict1)
print('dict2:',dict1)

# 嵌套字典
myfamily1 = {
    'child1':{
        'name':'Phoebe Adele',
        'year':2002
    },
    'child2':{
        'name':'Mike',
        'year':2001
    },
    'child3':{
        'name':'Rory John',
        'year':1999
    }
}
print('myfamily1:',myfamily1)

'''创建三个字典,然后创建一个包含其他三个字典的字典'''
child1 = {
    'name':'Phoebe Adele',
    'year':2002
}
child2 = {
    'name':'Mike',
    'year':2001
}
child3 = {
    'name':'Rory John',
    'year':1999
}
myfamily2 = {
    'child1':child1,
    'child2':child2,
    'child3':child3
}
print('myfamily2:',myfamily2)

# fromkeys()
x = ('name','age','gender')
y = 0
dict3 = dict.fromkeys(x,0)
print('dict3:',dict3)

# setdefault()方法
car = {
  "brand": "Porsche",
  "model": "911",
  "year": 1963
}
year = car.setdefault("year")
print('year:',year)
color = car.setdefault("color", "white")
print('color:',color)

六、集合

  1. 集合是无序和无索引的集合。
  2. 语法表示:thisSet={‘apple’,‘banana’,‘lemon’}
  3. 可以使用for循环遍历set,或者使用in关键字查询集合中是否存在指定值。
  4. 集合一旦创建,就无法更改其中的元素。
  5. 可以使用add()和update()方法添加元素。
  6. 使用len()方法获取 set的长度。
  7. 使用remove() 或 discard()方法删除元素。如果删除的元素不存在,remove()会报错,而discard()不会。
  8. pop()方法删除的是集合中的最后一个元素,因为集合是无序的,所以不知道删除的是哪个元素。
  9. clear()方法清空集合,del 删除集合对象。
  10. 合并两个集合:union()方法返回包含两个集合中所有项目的新集合,update()将一个集合插入另一个集合。两个方法都排除重复项。
  11. difference()返回差集。
  12. intersection()返回交集。
# 集合
'''创建集合'''
thisSet = {'apple','banana','lemon'}
print('thisSet:',thisSet)
'''通过使用set()构造函数来创建集合'''
thisSet2 = set(('apple','banana','lemon'))
print('thisSet2:',thisSet2)

'''遍历set'''
for item in thisSet:
    print(item)

'''检查set中是否存在指定值'''
print('apple' in thisSet)

'''添加元素'''
thisSet.add('orange')
print('thisSet:',thisSet)
thisSet.update(['mango','grapes'])
print('thisSet:',thisSet)

# 获取 set 的长度
print(len(thisSet))

# 删除元素
print('--------remove()--------')
thisSet.remove('banana')
print('--------discard()--------')
thisSet.discard('mango')
print('thisSet:',thisSet)
# thisSet.remove('watermelon')
thisSet.discard('watermelon')
print('thisSet:',thisSet)
print('--------pop()--------')
thisSet.pop()
print('thisSet:',thisSet)
print('--------clear()--------')
thisSet.clear()
print('thisSet:',thisSet)
print('--------del--------')
del thisSet

# 合并两个集合
print('--------union()--------')
set1 = {'a','b','c'}
set2 = {'a',1,2,3}
set3 = set1.union(set2)
print('set3:',set3)
print('--------difference()--------')
set4 = set1.difference(set2) # 返回差集
print('set4:',set4)
print('--------intersection()--------')
set5 = set1.intersection(set2)
print('set5:',set5)
print('--------update()--------')
set1.update(set2)
print('set1:',set1)

七、函数

1、概念

  1. 函数是一种仅在调用时运行的代码块。
  2. 函数中可以传参。
  3. 函数可以把数据作为结果返回。
  4. 函数名就是指向一个函数对象的引用,完全可以把函数名赋给一个变量,相当于给这个函数起了一个别名。

2、创建及调用函数

  1. 使用 def 关键字定义函数。
  2. 使用函数名()来调用函数。
# 函数
'''创建函数'''
def my_function():
    print('Hello, Function')

'''调用函数'''
my_function()

3、参数

  1. 在函数名后的括号内指定,用逗号分隔多个参数。
  2. 默认参数值:def my_function(country=‘China’): …,注意:必选参数在前,默认参数在后。默认参数必须指向不变对象。
  3. 关键字参数:可以使用key = value 语法发送参数,参数的顺序无关紧要。这些关键字参数在函数内部自动组装成一个dict。
  4. 命名关键字参数:必须传入参数名。命名关键字参数需要一个特殊分隔符 * , * 后面的参数被视为命名关键字参数。如果函数定义中已有一个可变参数,后面跟着的命名关键字参数就不需要特殊分隔符 * 了。
  5. 可变参数:如果不知道传几个参数,在定义的参数名称前添加 *,这样函数将接收一个参数元组,并可以相应的访问各项。
# 参数
def function_1(fname):
    print(fname+' Gates')

function_1('Bill')
function_1('Steve')
function_1('Elon')

'''默认参数值'''
def function_2(country = 'China'):
    print('I am from ' + country)
function_2('India')
function_2()

'''以List传参'''
def function_3(food):
    for x in food:
        print(x)
fruits = ['apple','banana','cherry']
function_3(fruits)

'''关键字参数'''
def function_4(child3,child2,child1):
    print('The youngest child is ' + child3)

function_4(child1 = 'Bill', child2 = 'Mike', child3 = 'Steve')
def function4(name,age,**kw):
    print('name:',name,'age:',age,'other:',kw)

function4('张三',18,city='北京')
extra = {'gender':'男','city':'北京'}
function4('张三',18,**extra) # **extra表示把rxtra中的所有键值对用关键字参数传到函数的**kw中。
'''命名关键字参数'''
def person(name,age,*,city,job):
    print(name,age,city,job)

person('Mike',20,city='Beijing',job='Doctor')

def person(name,age,*args,city,job):
    print(name,age,args,city,job)

person('Mike',20,'Boy',city='Beijing',job='Doctor')
'''可变参数'''
def function_5(*kids):
    print('The youngest child is ' + kids[2])

function_5('Bill','Mike','Steve')

4、返回值

  1. 如果需要使函数返回值,使用return语句。
  2. 函数也可以返回多个值,实际上是返回一个元组。
# 返回值
def function_6(x):
    return x * x, x * 2
print(function_6(3))

5、递归

  1. 尾递归可以解决递归调用栈溢出。
  2. 尾递归是指在函数返回的时候,调用自身本身,并且 return 语句不能包含表达式。这样,编译器或者解释器就可以把尾递归做优化,使递归本身无论调用多少次,都只占用一个栈桢,不会出现栈溢出的情况。
  3. Python标准的解释器没有针对尾递归做优化,任何递归函数都存在栈溢出的问题。
# 递归
'''实现阶乘'''
def fact(k):
    if k==1:
        return 1
    return k * fact(k-1)
print(fact(5))

# 汉诺塔问题
def move(a,c):
    print(a,'-->',c)
def hanoi(n,a,b,c):
    if n == 1:
        move(a,c)
    else:
        hanoi(n-1,a,c,b)
        move(a,c)
        hanoi(n-1,b,a,c)
hanoi(3,'A','B','C')

八、数组

Python没有内置对数组的支持,可以使用Python列表代替。

九、函数式编程

1、高阶函数

  1. 将函数作为参数传入的函数称为高阶函数。
  2. map()函数接收两个参数,一个是函数,另一个是Iterable,map 将传入的函数依次作用到序列的每个元素,并把结果作为新的Iterator返回。
'''map()'''
def f(x):
    return x * x
r = map(f,[1,2,3,4,5,6,7,8,9])
print(list(r))
print(list(map(str,[1,2,3,4,5,6])))
  1. reduce()函数把一个函数作用在一个序列上,这个函数必须接收两个参数,reduce把结果继续和序列的下一个元素做累积计算。
'''reduce()'''
from functools import reduce
def fn(x,y):
    return x * 10 + y
def char2num(s):
    digits = {'0':0,'1':1,'2':2,'3':3,'4':4,'5':5,'6':6,'7':7,'8':8,'9':9}
    return digits[s]
print(reduce(fn,map(char2num,'13579')))
  1. filter()函数用于过滤序列。filter()函数接收一个函数和一个序列,filter()把传入的函数依次作用于每个元素,然后根据返回值是True还是False决定保留还是丢弃该元素。
'''filter()'''
'''在一个list中,删除偶数,只保留奇数'''
def not_odd(x):
    return x % 2 == 1
print(list(filter(not_odd,[1,2,3,4,5,6,7,8,9])))
  1. sorted()函数可以对list进行排序,还可以接受一个key函数来实现自定义排序,要进行反向排序,传入第三个参数reverse = True即可。
'''sorted()'''
print(sorted([5,7,1,4,-3]))
print(sorted(['bob','about','Zoo','Credit'],key=str.lower))
print(sorted(['bob','about','Zoo','Credit'],key=str.lower,reverse=True))

2、返回函数

  1. 高阶函数还可以把函数作为结果值返回。
  2. 闭包函数是能够读取其他函数内部变量的函数。
  3. 返回一个函数时,该函数并未执行,返回函数中不要引用任何可能会变化的变量。
def count():
    def f(j):
        def g():
            return j * j
        return g
    fs = []
    for i in range(1,4):
        fs.append(f(i))
    return fs
f1,f2,f3 = count()
print(f1())
print(f2())
print(f3())

3、匿名函数Lambda

  1. Lambda函数是一种小的匿名函数,冒号前面的变量表示函数参数。
  2. Lambda函数可接受任意数量的参数,但只能有一个表达式。
  3. 语法表示:lambda arguments : expression
  4. 如果在短时间内需要匿名函数,使用lambda函数。
# Lambda
x = lambda a,b : a * b
print(x(5,6))
y = lambda a,b,c : a + b+ c
print(y(1,2,3))
'''把lambda作为返回值返回'''
def myfunc(n):
    return lambda a : a * n
mydoubler = myfunc(2)
print(mydoubler(11))

4、装饰器

  1. 在代码运行期间动态增加功能的方式,称为装饰器。
  2. 函数对象有一个__name__属性,可以拿到函数的名字。
import functools
def log(func):
    @ functools.wraps(func)
    def wrapper(*args,**kw):
        print('call %s():' % func.__name__)
        return func(*args,**kw)
    return wrapper

# 把decorator置于函数的定义处,相当于执行了 now = log(now)
@log
def now():
    print('2022-10-15')
now()
print(now.__name__)

5、偏函数

  1. 通过functools.partial来创建偏函数。
  2. functools.partial的作用就是把一个函数的某些参数固定住(即设置默认值),返回一个新的函数,调用这个新函数会更简单。
  3. 创建偏函数时,实际上可以接收函数对象、*args、**kw三个参数。
# 偏函数
import functools
'''相当于 
    kw = {'base': 2} 
    int('100000',**kw)
'''
int2 = functools.partial(int,base=2)
print(int2('100000'))
'''相当于 
    args = (10,5,7,12) 
    max(*args)
'''
max2 = functools.partial(max,10)
print(max2(5,7,12))

十、模块

1、 基本概念

  1. 模块是包含一组函数的文件,希望在应用程序中引用。
  2. 在Python中,一个.py文件就是一个模块。
  3. 使用模块的好处: 1) 大大提高了代码的可维护性。 2) 可以避免函数名和变量名冲突。
  4. 为了避免模块名冲突,可以通过包来组织模块。

2、 使用模块

  1. 如需创建模块,只需将所需代码保存在文件扩展名为.py的文件中。
  2. 通过import 语句来导入模块。
  3. 如果使用模块中的函数,语法为:module_name.function_name。
  4. 模块可以包含已经描述的函数,但也可以包含各种类型的变量(数组、字典、对象等)。
  5. 重命名模块:使用as关键字创建别名。如: import mymodule as mx。
  6. Python中有几个内建模块,可以随时导入,如:platform。
  7. 使用dir()函数可以列出模块中的所有函数名(或变量名)。
  8. 可以使用from关键字选择仅从模块中导入部件。此时引用模块中的元素时不需要使用模块名称了。
# -*- coding: utf-8 -*-

' a test module '  # 表示模块的文档注释,任何模块代码的第一个字符串都被视为模块的文档注释

__author__ = 'CuiYuqing'  # 作者姓名

import sys

def test():
    '''sys.argv即 "argument value" 是一个列表对象,
    其中存储的是在命令行调用python脚本时提供的“命令行参数”.
     sys.argv[0]是被调用的脚本文件名或全路径。
     sys.argv[1:]之后的元素就是从程序外部输入的,而非代码本身的,
     想要看到它的效果,就要将程序保存,从外部(即命令行)运行程序并给参数。
     '''
    args = sys.argv
    if  len(args) == 1:
        print('Hello, World!')
    elif len(args) == 2:
        print('Hello, %s!' % args[1])
    else:
        print('Too Many Arguments!')

if __name__ == '__main__':  # 相当于python模拟的程序入口
    ''' 如果if __name__ == '__main__' 所在模块是被直接运行的,则该语句下代码块被运行,如果所在模块是被导入到其他的python脚本中运行的,则该语句下代码块不被运行。'''
    test()
import platform
import mymodule as mx # 重命名模块
from mymodule import person2 # 使用 from 关键字选择仅从模块导入部件
x = dir(platform) # dir()可以列出模块中的所有函数名(或变量名)。
print(x)

age = mx.person1["age"] # 访问模块中的变量
print('age:',age)

print('person2["name"]:',person2['name'])

3、作用域

  1. 正常的函数和变量名是公开的(public),可以直接被引用。
  2. 类似“ xxx ”这样的变量是特殊变量,可以被直接引用,但是有特殊用途。如:author
  3. 类似 “_xxx”和“__xxx”这样的函数或变量就是非公开的(private),不应该被直接引用。
'''在模块里公开greeting()函数,而把内部逻辑用private函数隐藏起来,
这样,调用greeting函数不用关心内部private函数的细节'''
'''这是一种非常有用的代码封装和抽象的方法:即:
外部不需要引用的函数全部定义为private,只有外部需要引用的函数才定义为public
'''
def _private_1(name):
    return 'Hello, %s' % name
def __private_2(name):
    return 'Hi, %s' % name
def greeting(name):
    if len(name)==3:
        return _private_1(name)
    else:
        return __private_2(name)

print(greeting('李明'))

4、安装第三方模块

  1. 安装语法:pip install 模块名
  2. Anaconda是一个基于Python的数据处理和科学计算平台。
  3. 下载后直接安装,Anaconda会把系统Path中的python指向自带的Python,并且,Anaconda安装的第三方模块会安装在Anaconda自己路径下,不影响系统已安装的Python目录。

面向对象编程(OOP)

1、基本概念

  1. OOP把对象作为程序的基本单元,一个对象包含了数据和操作数据的函数。
  2. 面向过程的程序设计就是把计算机程序视为一系列的命令集合,即一组函数的顺序执行。面向过程把函数切分成子函数,来降低系统的复杂度。
  3. 面向对象的程序设计把计算机程序视为一组对象的集合,每个对象都可以接收其他对象发过来的消息,并处理这些消息。
  4. 在Python中,所有数据类型都可以视为对象,自定义的对象数据类型就是面向对象中的类的概念。

2、类和实例

  1. 类是抽象的模板。
  2. 实例是根据类创建出来的一个个具体的“对象”。每个对象都拥有相同的方法,但各自的数据可能不同。
  3. 类是通过class关键字定义的,class后面紧接着是类名,类名通常是大写开头的单词,紧接着是(object),表示该类是从哪个类继承下来的。
  4. object类是所有类的父类。
  5. 创建实例是通过类名()实现的。
  6. init()函数。 1) 所有类都有一个名为 init() 的函数,他始终在启动类时执行。 2) 使用__init__()函数将值赋值给对象属性,或者在创建对象时需要执行的其他操作。 3)
    每次使用类创建新对象时,都会自动调用__init__()函数。 4)
    init()函数的第一个参数永远是self,表示创建的实例本身,是对类的当前实例的引用,用于访问属于该类的变量。因此,在__init__()方法内部,就可以把各种属性绑定到self。
    5) 有了__init__()方法,在创建实例时,必须传入与__init__方法匹配的参数,但是self不需要传。
  7. 数据封装 1) 可以直接在类的内部定义访问类中数据的函数,这就把数据封装起来了。 2) 这些封装数据的函数称为类的方法。 3) 定义方法时,方法的第一个参数也必须是self,其他和普通函数一样。 4) 调用方法时,使用对象.方法名()直接调用。
  8. 修改对象属性 使用 对象.属性名 = 要修改的属性值 来修改对象属性。
  9. 删除对象属性 使用del关键字删除对象属性。del 对象.属性名
  10. 删除对象 使用 del 对象 来删除对象。
class Student(object):
    # 初始化方法,self表示创建的实例本身
    def __init__(self,name,score):
        self.name = name
        self.score = score

    def print_score(self):
        print('The score of %s is: %s' % (self.name,self.score))

# 创建实例(对象)
stu1 = Student('Mike',90)
stu1.print_score()

stu2 = Student('Bill',100)
stu2.print_score()

# 修改对象的属性
stu2.score = 88
stu2.print_score()

# 删除对象属性
del stu2.score
# stu2.print_score() # AttributeError: 'Student' object has no attribute 'score'

# 删除对象
del stu2

3、访问限制

  1. 如果想让内部属性不被外部访问,可以将属性变成私有属性(private),这样就确保了外部代码不能随意修改对象内部的状态。
  2. 如果外部代码要获取内部属性,可以给类增加get_属性名()方法。
  3. 如果外部代码要修改内部属性,可以给类增加set_属性名()方法。在set方法中,可以对参数做检查,避免传入无效的参数。
class Student(object):
    # 初始化方法,self表示创建的实例本身
    def __init__(self,name,score):
        self.__name = name
        self.__score = score

    def print_score(self):
        print('The score of %s is: %s' % (self.__name,self.__score))
    def get_name(self):
        return self.__name
    def get_score(self):
        return self.__score
    def set_name(self,name):
        self.__name = name
    def set_score(self,score):
        if 0<=score<=100:
            self.__score = score
        else:
            raise ValueError('error score')

# 创建实例(对象)

stu2 = Student('Bill',100)
stu2.print_score()

# 修改对象的属性
# print(stu2.__score) # AttributeError: 'Student' object has no attribute '__score'
print(stu2.get_name())
stu2.set_score(99)
stu2.print_score()

4、继承和多态

  1. 继承允许我们定义继承另一个类的所有方法和属性的类。
  2. 父类是被继承的类,也称为基类、超类。
  3. 子类也称为派生类。
  4. 继承的好处 1) 子类获得了父类的全部功能。 2) 子类可以新增自己特有的方法,也可以重写父类的方法。
  5. 当子类和父类存在相同的方法时,子类会覆盖父类的方法。
  6. 判断一个变量是否是某个类型,可以用 isinstance()判断。
  7. 多态:不同的子类对象调用相同的父类方法产生不同的执行结果。
  8. 对于静态语言来说,如果需要传入一个Animal类型,则传入的对象必须是Animal类型或者其子类,否则,无法调用run()方法。
  9. 对于Python这样的动态语言,则不一定需要传入Animal类型,只需保证传入的对象有一个run()方法就可以了。这就是动态语言的“鸭子类型”。
  10. super()函数,会使子类自动从其父继承所有方法和属性。
  11. 添加属性 使用self.属性名 = 属性值来添加。
# 继承和多态
class Animal(object):
    def run(self):
        print("Animal is running...")

class Dog(Animal):
    pass

dog = Dog()
dog.run()

class Cat(Animal):
    def run(self): # 多态:子类重写了父类的方法
        print("Cat is running...")

    def eat(self):
        print('Eat fish...')

cat = Cat()
cat.run()
cat.eat()

# 判断一个变量是否是某个类型
print(isinstance(cat,Animal))

def run_twice(animal):
    animal.run()

run_twice(Animal())
run_twice(Cat())

class Tortoise(object):
    def run(self):
        print("Tortoise is running...")

run_twice(Tortoise())

class Person(object):
    def __init__(self,name,age):
        self.name = name
        self.age = age

class Student(Person):
    def __init__(self,name,age,year):
        super().__init__(name,age)
        self.graduationyear = year

    def show(self):
        print('%s 今年 %s 岁,在 %s 年毕业' % (self.name,self.age,self.graduationyear))

x = Student('Mike',20,2023)
x.show()

5、获取对象信息

  1. 使用type()判断对象类型。
  2. 使用isinstance()判断对象类型。能用type()判断的基本类型也可以用isinstance()判断。
  3. 还可以使用isinstance()判断一个变量是否是某些类型中的一种。
  4. 使用dir()可以获得一个对象的所有属性和方法。
  5. getattr(obj, attr[, default]) 用来获取属性,如果属性不存在,就返回传入的默认值。
  6. setattr(obj, attr, 属性值) 用来为obj对象设置属性值。
  7. hasattr(obj, attr) 判断obj对象是否有属性attr。
  8. 只有在不知道对象信息时,才会去获取对象信息。
  9. 如果可以直接写 sum = obj.x + obj.y,就不要写 sum = getattr(obj,‘x’) + getattr(obj,‘y’) 。
# 获取对象信息

# type()
print(type(123))
print(type(123) == type(456))

# 判断一个对象是否是函数
import types
def fn():
    pass

print(type(fn) == types.FunctionType)

# isinstance()

print(isinstance(123,int))
# 判断一个变量是否是某些类型中的一种
print(isinstance([1,2,3],(list,tuple)))

print('--------------------')
class MyObject(object):
    def __init__(self):
        self.x = 9
    def power(self):
        return self.x * self.x

obj = MyObject()
print(dir(obj)) # 获得该对象的所有属性和方法
print(hasattr(obj,'x'))
print(getattr(obj,'x'))
print(getattr(obj,'y',100))
setattr(obj,'z',2)
print(getattr(obj,'z'))

6、实例属性和类属性

  1. 实例属性属于各个实例所有,互不干扰;
  2. 类属性属于类所有,所有实例共享一个属性‘
  3. 不要对实例属性和类属性使用相同的名字,否则将产生难以发现的错误。
# 实例属性和类属性
class Student(object):
    name = 'Student' # 类属性
    # def __init__(self,name):
    #     self.name = name # 实例属性

s = Student()
print(s.name) # 实例没有name属性,所以会继续查找cass的name属性
print(Student.name)
s.name = 'Mike'
print(s.name) # 实例属性的优先级比类属性高,所以实例属性会覆盖类属性

面向对象高级编程

1、使用__slots__

  1. 在类中定义一个__slots__变量来限制该类的实例能添加的属性。
  2. __slots__定义的属性只对当前类实例起作用,对继承的子类不起作用。
  3. 如果在子类中也定义__slots__,子类实例就允许定义的属性就是自身的__slot__加上父类的__slots__。
class Student(object):
    __slots__ = ('name','age')

s = Student()
s.name = 'Mike'
s.age = 20
# s.score = 90  # AttributeError: 'Student' object has no attribute 'score'

# __slots__定义的属性只对当前类实例起作用,对继承的子类不起作用
class S(Student):
    pass
a = S()
a.score = 99

#  如果在子类中也定义__slots__,子类实例就允许定义的属性就是自身的__slot__加上父类的__slots__
class Stu(Student):
    __slots__ = ('name', 'age')

b = Stu()
# b.score = 80

2、使用@property

  1. @property装饰器就是负责把一个方法变成属性调用。
  2. 属性名和方法名一定要区分开,不然会进入死循环。
  3. 实例化的对象使用属性时,不是调用属性,而是用的方法名。
  4. @property实现的是getter功能,@xxx.setter实现的是setter功能;@xxx.deleter实现的是删除功能。
  5. 定义方法时@property必须在@xxx.setter之前,且二者修饰的方法名相同。
  6. 如果只实现了@property,那么该属性为只读属性。
# @property用法
class Student(object):
    def __init__(self,name,age):
        self._name = name
        self._age = age

    @property # 实现一个age相关的getter方法
    def age(self):
        return self._age

    @age.setter # 实现一个age相关的setter方法
    def age(self,value):
        if isinstance(value,int):
            self._age = value
        else:
            raise ValueError("'int' type need")

stu = Student('Xiaohong',18)
stu.age = 19
print(stu.age)

3、多重继承

  1. 通过多重继承,一个子类就可以同时获得多个父类的所有功能。
  2. 在设计类的继承关系时,通常主线都是单一继承下来的。如果需要“混入”额外的功能,通过多重继承可以实现,这种设计称为MixIn。
  3. MixIn的目的就是给一个类增加多个功能。
# 多重继承

class Animal(object):
    pass

# 大类:
class Mammal(Animal):
    pass

class Bird(Animal):
    pass

# 会飞
class FlyableMixIn(object):
    def fly(self):
        print("Flying...")

# 会跑
class RunnableMixIn(object):
    def run(self):
        print("Runnable...")

# 各种动物:多重继承
class Dog(Mammal,RunnableMixIn):
    pass

class Parrot(Bird,RunnableMixIn):
    pass

4、使用枚举类

  1. Python在使用枚举类时需要导入enum模块,枚举定义用class关键字,继承Enum类。
  2. 定义枚举时,成员名称不允许重复,成员名称相同时就会报错。
  3. 默认情况下,不同的成员值允许相同。但是两个相同值的成员,第二个成员的名称被视作第一个成员的别名。
  4. 可以使用装饰器@unique【要导入unique模块】,可以帮助我们检查保证没有重复值。
  5. 既可以用成员名称引用枚举常量,又可以直接根据value的值获得枚举常量。
  6. 如果枚举有值重复的成员,循环遍历枚举时只获取值重复成员的第一个成员。如果想把值重复的成员也遍历出来,要用枚举的一个特殊属性__members__。
  7. 枚举成员可进行同一性比较,使用is和not等,枚举成员可进等值比较,使用==,枚举成员不能进行大小比较。
# 枚举类

from enum import Enum,unique

Month = Enum('Month',('Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'))

for name,member in Month.__members__.items():
    print(name,'=>',member,',',member.value)


@unique # 保证没有重复值
class Weekday(Enum):
    Sun = 0
    Mon = 1
    Tue = 2
    Wed = 3
    Thu = 4
    Fri = 5
    Sat = 6

print(Weekday.Mon)
print(Weekday['Tue'])
print(Weekday.Wed.value)
print(Weekday(1))

5、定制类

  1. 使用__str__()方法可以返回一个自定义的字符串。
  2. repr()方法:当直接打印类的实例化对象时,系统将会自动调用该方法,输出对象的自我描述信息,用来告诉外界对象具有的状态信息。repr()方法返回程序开发者看到的字符串。
  3. 如果一个类像被用于for…in循环,就实现一个__iter__()方法,该方法返回一个迭代对象。
  4. getitem(self,key):这个方法返回与指定键相关联的值。 对序列来说(通常是列表),键应该是0~n-1的整数,其中n为序列的长度。对映射来说(通常是字典),键可以是任何类型。
  5. getattr()方法可以动态返回一个属性。只有当调用不存在的属性时,Python解释器会试图调用__getattr__(self,‘score’)来尝试获得属性。
  6. 在类中定义一个__call__()方法,可以直接对实例进行调用。call()还可以定义参数。
# 定制类

class Student(object):
    def __init__(self,name):
        self.name = name
    # 使用__str__()方法可以返回一个自定义的字符串
    def __str__(self):
        return 'Student object (name: %s)' % self.name
    # __repr__()方法返回程序开发者看到的字符串。
    __repr__ = __str__

    #  __getattr__()方法可以动态返回一个属性.只有当调用不存在的属性时,Python解释器会试图调用__getattr__(self,'score')来尝试获得属性。
    def __getattr__(self,attr):
        if attr == 'score':
            return 99

    #  __call__()可以直接对实例进行调用。
    def __call__(self):
        print('My name is %s.' % self.name)
s = Student('Mike')
print(s)

print('score:',s.score)
s()
# iter()方法
class Fib(object):
    def __init__(self):
        self.a, self.b = 0,1
    def __iter__(self):
        return self # 实例本身就是迭代对象
    def __next__(self):
        self.a, self.b = self.b, self.a + self.b # 计算下一个值
        if self.a > 100000:
            raise StopIteration()
        return self.a   # 返回下一个值
    #  __getitem__(self,key):这个方法返回与指定键相关联的值。
    def __getitem__(self,n):
        a,b = 1,1
        for x in range(n):
            a,b = b,a+b
        return a

for n in Fib():
    print(n)

f = Fib()
print(f[0])

错误、调试和测试

1、错误处理

try…except…finally

  1. 当我们认为某些代码可能会出错时,就可以使用try来运行这段代码,如果执行出错,则后续代码不会继续执行,而是直接跳转至错误处理代码,即except语句块,
    执行完except后,如果有finally语句块,则执行finally语句块,至此,执行完毕。
  2. 如果没有错误发生,就不会执行except语句块,但是如果有finally,则一定会被自行。
  3. 如果发生了不同类型的错误,应该有不同的except语句块来捕获不同类型的错误。
  4. 使用try…except捕获错误可以跨越多层调用。不需要在每个可能出错的地方捕获错误,只要在合适的层次去捕获就可以。
  5. Python内置的logging 模块可以容易的记录错误信息,然后让程序继续执行下去。
  6. 可以使用raise语句抛出错误。raise语句如果不带参数,就会把当前错误原样抛出。
try:
    print('try...')
    r = 10 / int('2')
    print('result:',r)
except ValueError as e:
    print('ValueError:',e)
except ZeroDivisionError as e:
    print('ZeroDivisionError:', e)
else:
    print('no error!')
finally:
    print('finally...')
print('END')
import logging

def foo(s):
    return 10 / int(s)
def main():
    try:
        foo('0')
    except Exception as e:
        logging.exception(e)

main()
print('End')
# 捕获错误后,打印ValueError后,又把错误抛出去
def foo(s):
    n = int(s)
    if n==0:
        raise ValueError('invalid value: %s' % s)
    return 10 / n

def bar():
    try:
        foo('0')
    except ValueError as e:
        print('ValueError!')
        raise
bar()

2、单元测试

  1. 单元测试是用来对一个模块、一个函数或者一个类来进行正确性检验的测试工作。
  2. 如果我们对某个函数代码做了修改,只需要再跑一遍单元测试,如果通过,说明我们的修改不会对函数原有的行为造成影响, 否则,说明我们的修改与原有行为不一致,要么修改代码,要么修改测试。
  3. 为了编写单元测试,需要引入Python自带的unittest模块。
  4. 编写单元测试时,我们需要编写一个测试类,从unittest.TestCase继承。以test开头的方法就是测试方法,否则就不是测试方法,测试时不会被执行。
  5. 最常用的断言是assertEqual(),判断函数返回值是否与指定值相等。
  6. 另一个重要的断言是assertRaises(Error),期待抛出指定类型的Error。
  7. 在单元测试中编写setUp()和tearDown()方法,会分别在每调用一个测试方法的前后分别被执行。
import unittest
from mydict import Dict

class TestDict(unittest.TestCase):
    def test_init(self):
        d = Dict(a=1,b='test')
        self.assertEqual(d.a,1)
        self.assertEqual(d.b,'test')
        self.assertTrue(isinstance(d,dict))

    def test_key(self):
        d = Dict()
        d['key'] = 'value'
        self.assertEqual(d.key,'value')
    def setUp(self):
        print('setUp...')
    def tearDown(self):
        print('tearDown...')

if __name__ == '__main__':
    unittest.main()

3、文档测试

  1. Python内置的“文档测试”(doctest)模块可以直接提取注释中的代码并执行测试。
  2. doctest严格按照Python交互式命令行的输入和输出来判断测试结果是否正确。
  3. 当模块正常导入时,doctest不会被执行,只有在命令行直接运行时,才执行doctest。
  4. 如果什么输出也没有,说明编写的doctest运行都是正确的。
class Dict(dict):
    '''
    Simple dict but also support access as x.y style.

    >>> d1 = Dict()
    >>> d1['x'] = 100
    >>> d1.x
    100
    >>> d1.y = 200
    >>> d1.y
    200
    >>> d2 = Dict(a=1,b=2,c='3')
    >>> d2.c
    '3'
    >>> d2['empty']
    Traceback (most recent call last):
        ...
    KeyError: 'empty'
    >>> d2.empty
    Traceback (most recent call last):
        ...
    AttributeError: 'Dict' object has no attribute 'empty'
    '''
    def __init__(self,**kw):
        super().__init__(**kw)

    def __getattr__(self,key):
        try:
            return self[key]
        except KeyError:
            raise AttributeError(r"'Dict' object has no attribute '%s'" % key)

    def __setattr__(self,key,value):
        self[key] = value
if __name__=='__main__':
    import doctest
    doctest.testmod()

Python日期

  1. Python中的日期不是其自身的数据类型,但是我们可以导入名为datetime的模块,把日期视作日期对象进行处理。
  2. 可以使用datetime模块的datetime()类来创建日期。datetime() 类需要三个参数来创建日期:年、月、日,其他参数可选。
  3. datetime 对象拥有把日期对象格式化为可读字符串的方法。该方法称为 strftime(),并使用一个 format 参数来指定返回字符串的格式。
  4. %A:Weekday; %B:月; %d:日; %m:数字的月; %Y:年; %H:小时; %M:分; %S:秒
import datetime

x = datetime.datetime.now()

print(x) # 返回当前日期
print(x.year)   # 返回年份
# strftime()方法可以把日期对象格式化为可读字符串,使用一个format参数来指定返回字符串的格式。
print(x.strftime("%A")) # 返回weekday的名称
print(x.strftime("%B")) # 返回month的名称

# 创建日期对象
y = datetime.datetime(2020,5,20,13,14) # 年月日必须有,其他参数可选
print(y)

Python JSON

  1. JSON是用于存储和交换数据的语法。
  2. JSON是用JavaScript对象表示法编写的文本。
  3. Python中有一个名为json的内置包,可用于处理JSON数据。
  4. JSON转化为Python:若有JSON字符串,则可以使用json.loads()方法对其进行解析,结果将是Python字典。
  5. Python转化为JSON:若有Python对象,可以使用json.dumps()方法转换为JSON字符串。
  6. json.dumps()中的参数 1) 可以使用indent参数定义缩进数。 2) 使用 separators 参数来更改默认分隔符,默认值为(", ", ": "),这意味着使用逗号和空格分隔每个对象,使用冒号和空格将键与值分开。 3) 使用
    sort_keys 参数来指定是否应对结果进行排序.
import json

# JSON字符串
x = '{"name":"Bill","age":63,"city":"USA"}'

# 解析 JSON:JSON转化为Python
y = json.loads(x)

# 结果是Python字典
print(y,type(y))

# Python转化为JSON
'''Python 对象(字典)'''
dict = {
    "name":"Mike",
    "age":30,
    "city":"USA"
}
y = json.dumps(dict) # 把Python对象转换为JSON字符串

print(y,type(y))
print(json.dumps(["apple","banana"])) # 把Python的list转换为JSON的Array
print(json.dumps(("apple","banana"))) # 把Python的tuple转换为JSON的Array
print(json.dumps(42)) # 把Python的int转换为JSON的Number
print(json.dumps(None)) # 把Python的None转换为JSON的null

print(json.dumps(dict,indent=4,separators=(".","="),sort_keys=True))

Python RegEx

  1. RegEx 或正则表达式是形成搜索模式的字符序列。
  2. RegEx可用于检查字符串是否包含指定的搜索模式。
  3. Python 提供名为 re 的内置包,可用于处理正则表达式。
  4. re 模块提供了一组函数,允许我们检索字符串以进行匹配。 1) findall():返回包含所有匹配项的列表。 2) search():如果字符串中的任意位置存在匹配,则返回Match对象。如果有多个匹配,就返回首个匹配项。 3)
    split():返回在每次匹配时拆分字符串的列表。 4) sub():用字符串替换一个或多个匹配项。
  5. 元字符 []:表示一组字符; \:表示特殊序列(如:转义字符); .:除换行符以外的任何字符; ^:起始字符; $:结束字符; *:0次或多次出现; +:一次或多次出现; {}:确切指定出现次数; |:两者任一;
    ():捕获和分组
  6. Match 对象是包含有关搜索和结果信息的对象。 1) 如果没有匹配,则返回值 None,而不是 Match 对象。 2) span() 返回的元组包含了匹配的开始和结束位置。 3) .string 返回传入函数的字符串。 4) group()
    返回匹配的字符串部分。
import re

txt = "China is a great country"
x = re.search("^China.*country$",txt)
x2 = re.findall("a",txt)
x3 = re.split("\s",txt) # \s 返回字符串包含空白字符的匹配项
x4 = re.split("\s",txt,1) # 仅在首次出现时拆分字符串
x5 = re.sub("\s","\t",txt)
print(x.group())
print(x.span())
print(x.string)
print(x2)
print(x3)
print(x4)
print(x5)

Python 文件处理

1. 文件打开、关闭

  1. 在Python中使用文件的关键函数是open()函数。
  2. open()函数有两个参数:文件名和模式。
  3. 打开文件的方法: 1) “r”:读取,默认值,打开文件进行读取,文件不存在则报错。 2) “a”:追加,打开供追加的文件,文件不存在则创建文件。会追加到文件末尾。 3)
    “w”:写入,打开文件进行写入,文件不存在则创建文件。会覆盖已有的全部内容。 4) “x”:创建,创建指定文件,文件存在则报错。
  4. 指定文件处理方式: 1) “t”:默认值,文本模式。 2) “b”:二进制模式。
  5. 关闭文件:f.close()

2. 文件读取

  1. open()函数返回文件对象,使用该对象的read()方法用于读取文件内容。
  2. 默认情况下,read() 方法返回整个文本,也可以指定要返回的字符数。
  3. 使用 readline() 方法返回一行。通过循环遍历文件中的行,可以逐行读取整个文件。
  4. 使用 readlines() 方法读取文件的所有行,自动将文件内容分析成一个行的列表,返回的每一行内容包含换行符。
# 文件打开、读取、关闭
f = open("D:\\text.txt") # 等同于 f = open("D:\test.txt","rt")
# print(f.read()) # 读取整个文本
# print(f.read(5)) # 读取文本中的指定字符数
# print(f.readline()) # 读取文件中的一行
# print(f.readlines()) # 读取文件的所有行,自动将文件内容分析成一个行的列表
# 通过循环遍历文件中的行,您可以逐行读取整个文件
for x in f:
    print(x)
f.close()

3. 文件写入

  1. 如需写入已有文件,必须向open()函数中添加"a"、"w"参数。
  2. 使用write()函数追加内容。
  3. 如需在 Python 中创建新文件,请使用 open() 方法,并使用"a"、“w”、"x"中的一个参数。
f = open("D:\\text.txt","a") # 向文件中追加内容
f.write("Happy New Year!")
f = open("D:\\text.txt","w") # 覆盖文件中的内容
f.write("Happy New Year!")
f = open("D:\\demo.txt","x") # 创建新文件
f.write("Happy New Year!")

4. 删除文件

  1. 删除文件时,需要导入os模块,并使用os.remove()函数。
  2. 为了避免出现错误,在删除文件之前检查文件是否存在。
  3. 如果需要删除空文件夹,使用os.rmdir()方法。
# 删除文件
import os
if os.path.exists("D:\\demo.txt"): # 检查文件是否存在
    os.remove("D:\\demo.txt")
else:
    print("The file does not exist")
os.rmdir("D:\\test") # 只能删除空的文件夹

你可能感兴趣的:(Python学习,python,学习,开发语言)