python_basic

2023-12-24

Python学习笔记

一、基础语法

1、标识符

  • 标识符:变量、模块名、函数名、类名
  • 在 Python 里,标识符由字母、数字、下划线组成
  • 命名规则:
    • 由数字、字母和下划线组成,不能以数字开头
    • 严格区分大小写
    • 不能使用关键字
  • 命名规范:推荐三种常用命名方式
    • 小驼峰命名法:第一个单词的首字母小写,以后每个单词首字母大写 rememberToDoSth
    • 大驼峰命名法:每个单词首字母都大写 RememberToDoSth
    • 使用下划线连接 remember_to_do_sth

注:

1)以下划线开头的标识符是有特殊意义的。以单下划线开头 _foo 的代表不能直接访问的类属性,需通过类提供的接口进行访问,不能用 from xxx import * 而导入。

2)以双下划线开头的 __foo 代表类的私有成员,以双下划线开头和结尾的 __foo__ 代表 Python 里特殊方法专用的标识,如 __init__() 代表类的构造函数。

2、保留字

  • 保留字不能用作标识符名称
  • 所有关键字质保函小写字母
and exec not
assert finally or
break for pass
class from print
continue global raise
def if return
del import try
elif in while
else is with
except lambda yield

3、行和缩进

Python 的代码块不使用大括号 {} 来控制类,函数以及其他逻辑判断。python 用缩进来写模块。

缩进的空白数量是可变的,但是所有代码块语句必须包含相同的缩进空白数量,这个必须严格执行。

建议每个缩进层次使用 单个制表符两个空格四个空格 , 切记不能混用

4、多行语句

  • Python语句中一般以新行作为语句的结束符。但是我们可以使用斜杠( \)将一行的语句分为多行显示
total = item_one + \
        item_two + \
        item_three
  • 语句中包含 [], {} 或 () 括号就不需要使用多行连接符
days = ['Monday', 'Tuesday', 'Wednesday',
        'Thursday', 'Friday']
  • 可以在同一行中使用多条语句,语句之间使用分号(;)分割
print("Hello");print("Python");print("hiahiahia")

5、注释

#表示单行注释

’'’三个单引号开始,三个单引号结束,表示多行注释’’’

”"”三个双引号开始,三个双引号结束,表示多行注释”””

6、内置输入输出函数

6.1、内置 print 函数 进行输出

# print(value, ..., sep=' ', end='\n', file=sys.stdout, flush=False)
print('good','yes','hello',sep='+',end='____')		
# sep 打印时每个元素之间的连接符号,默认是空格;end 打印结束后执行的,默认是换行
print('ajf','world','asdk')

6.2、内置函数 input 进行输入

  • 定义一个变量可以保存用户输入内容
  • 不管用户输入的是什么,变量保存的都是字符串
weiXinHao = input('小姐姐,可不可以把你的微信号给我:')
print(weiXinHao)
print(type(weiXinHao))		# <class 'str'>

二、变量及数据类型

  • Python里的数据分为可变数据和不可变数据:
    • 可变数据:列表、集合、字典
    • 不可变数据:字符串、数字、元组
  • 可变数据:修改值,内存地址不会发生变化
  • 不可变数据:修改值,内存地址会发生变化
  • 使用id()函数可以查看变量地址:
s=0
print("变量s的地址为:{}".format(id(s)))

1、数据类型

1)数字类型:整数型(int)、长整型(long)(Python3中已经没有长整型了)、浮点(小数)型(float)、复数型(complex)

2)字符串类型(Str):表示一段字符,使用单引号或双引号包围起来

str="Python"

3)布尔类型(bool):只有两个TureFalse

a=(1==2)	# a的值为False
b=(1<2)		# b的值为True

4)列表类型(list)

days=["Mon","Tue","Wed","Thu","Fri","Sat","Sun"]

5)字典类型(Dict):

person = {'name':'张三','年龄':'18','身高':'180','体重':'52kg'}

6)元组类型(Tuple):

nums = (1,5,3,9,6)

7)集合类型(set):

x = {1,'good','hello',True}
  • 查看数据类型:使用type()函数进行扁蕾数据类型的查看
a = 3
print(type(a))		# 输出出 a 的数据类型
print(type(3.14))	# 输出出3.14的数据类型

注:在Python中,变量是没有数据类型的,我们所说的变量的数据类型是指变量所对应的值的数据类型

2、数据类型转换

1)使用int()转换为整数型

*注:long() 将其他类型转换为长整型;float() 将其他类型转换为浮点型;complex(real [,imag]) 创建一个复数 *

a = '1'
print(int(a))
b = '3.14'
print(int(b,8))		# 将b作为八进制
c = 'abc'
print(int(c,16))		# 将c最为十六进制
# 当字符串超出进制范围就会报错
 d = 'abcdefghijklmn'
 int(d,16)		# k超出16进制所以会报错

2)使用float()转换为浮点型

a='12.23'
print(float(a))	

# 如果字符串不能转换成为有效的浮点型,就会报错
b = 'hello'
print(float(b))

3)使用str()将其他类型转换为字符串

a = 24
b = str(a)

4)使用bool()将其他类型转换为布尔值

注:在Python里只有空字符串’’/”“,数字0,空列表[],空字典{},空元组(),空集合set()和空数据None转换为False,其他的都会被转换为True

print(bool(0))		# False
print(bool(''))		# False
print(bool({}))		# False
print(bool(()))		# False
print(bool([]))		# False
print(bool(None))	# False
print(bool(set()))	# False

5)使用tuple(), ist(), set()将其他类型转换为可迭代对象

注:可迭代对象有:字符串\列表\字典\元组\集合

t = 'hello'
print(tuple(t))	# ('h', 'e', 'l', 'l', 'o')
print(list(t))	# ['h', 'e', 'l', 'l', 'o']
print(set(t))	# {'h', 'e', 'l', 'l', 'o'}

6)Python里面的数据类型转换相关的函数

函数 描述
int(x [,base]) 将x转换为一个整数
long(x [,base] ) 将x转换为一个长整数
float(x) 将x转换到一个浮点数
complex(real [,imag]) 创建一个复数
str(x) 将对象 x 转换为字符串
repr(x) 将对象 x 转换为表达式字符串
eval(str) 用来计算在字符串中的有效Python表达式,并返回一个对象
tuple(s) 将序列 s 转换为一个元组
list(x) 将序列 s 转换为一个列表
set(s) 转换为可变集合
dict(d) 创建一个字典。d 必须是一个序列 (key,value)元组。
frozense(s) 转换为不可变集合
chr(x) 将一个整数转换为一个字符
unichr(x) 将一个整数转换为Unicode字符
ord(x) 将一个字符转换为它的整数值
hex(x) 将一个整数转换为一个十六进制字符串
oct(x) 将一个整数转换为一个八进制字符串

3、eval() 函数

  • eval() 函数用来执行一个字符串表达式,并返回表达式的值。

  • 语法:

      eval(expression[, globals[, locals]])
    
    • expression – 表达式。
    • globals – 变量作用域,全局命名空间,如果被提供,则必须是一个字典对象。
    • locals – 变量作用域,局部命名空间,如果被提供,可以是任何映射对象。
    • 返回表达式计算的结果
>>>x = 7
>>> eval( '3 * x' )
21
>>> eval('pow(2,2)')
4
>>> eval('2 + 2')
4
>>> n=81
>>> eval("n + 4")
85

三、运算符

Python主要支持以下7中类型的运算符:

  • 算术运算符
  • 关系运算符
  • 赋值运算符
  • 逻辑运算符
  • 位运算符
  • 成员运算符
  • 身份运算符

1、算术运算符

运算符 描述
+ 加 - 两个对象相加
- 减 - 得到负数或是一个数减去另一个数
* 乘 - 两个数相乘或是返回一个被重复若干次的字符串
/ 除 - x除以y
% 取模 - 返回除法的余数
** 幂 - 返回x的y次幂
// 取整除 - 返回商的整数部分(向下取整

注:在Python2里两个整数相除,商为整数,若要得到浮点型,将除数或者被除数改成浮点型即可;在Python3里两个整数相除,商为浮点型

1.1、加+、乘*运算符在字符串中的应用

加法运算符:只能用于多个字符串类型数据,将对个字符串拼接为一个字符串

print('hello' + 'world')		# helloworld

乘法运算符:可以用于字符串和数字之间,将一个字符串重复多次

print('hello' * 2)		# hellohello

1.2、常见算术运算符在可迭代对象中的应用

运算符 Python表达式 结果 描述 支持的数据类型
+ [1,2]+[3,4,5] [1,2,3,4,5] 合并 字符串、列表、元组
- {1,2,3.4} - {3,4} {1,2} 集合求差集 集合
* [‘hello’] * 3 [‘hello’,’hello’,’hello’] 复制 字符串、列表、元组

2、关系运算符

运算符 描述
== 等于 - 比较对象是否相等
!= 不等于 - 比较两个对象是否不相等
<> 不等于 - 比较两个对象是否不相等。python3 已废弃。
> 大于 - 返回x是否大于y
< 小于 - 返回x是否小于y
>= 大于等于 - 返回x是否大于等于y。
<= 小于等于 - 返回x是否小于等于y。

注:所有比较运算符返回1表示真,返回0表示假。这分别与特殊的变量True和False等价。

2.1、字符串之前的关系比较

字符串之间使用比较运算符,会根据各个字符的编码值逐一进行比较

print('a' < 'b')		# True
print('abc' > 'b')		# False

2.2、字符串与数字之间的关系比较

数字和字符串之间,做 == 运算结果是False,做 != 运算结果为True,不支持其它的比较运算

print('a' == 97)	# False
print('a' != 97)	# True
# print('a' > 96)	出错

3、赋值运算符

运算符 描述
= 简单的赋值运算符
+= 加法赋值运算符
-= 减法赋值运算符
*= 乘法赋值运算符
/= 除法赋值运算符
%= 取模赋值运算符
**= 幂赋值运算符
//= 取整除赋值运算符

注:赋值运算符将运算符右边的值赋值给运算符左边,运算符左边一定不能是常量或表达式

3.1、传递赋值

a=b=c="python"		a="python";b="python";c="python"

3.2、拆包

1)赋值

m,n = 3,5		# m = 3		n = 5
#拆包时,变量和数据个数不一致时会报错
# m,n = 1,2,3,4
#m,n,p = 1,2

2)变长度拆包

m,*n,p = 1,2,3,4,5,6		# m=1;n=[2,3,4,5];p=6
*m,n,p = 1,2,3,4,5,6		# m=[1,2,3,4];n=5;p=6

3)值交换

i=1
j=2
i, j = j,  i		# 交换i和j的值

4)元组

x = 'hello','good','yes'	# x = ('hello','good','yes')

4、逻辑运算符

运算符 逻辑表达式 描述
and x and y 布尔”与” - 如果 x 为 False,x and y 返回 False,否则它返回 y 的计算值。
or x or y 布尔”或” - 如果 x 是非 0,它返回 x 的计算值,否则它返回 y 的计算值。
not not x 布尔”非” - 如果 x 为 True,返回 False 。如果 x 为 False,它返回 True。

5、位运算符

运算符 描述
& 按位与运算符:参与运算的两个值,如果两个相应位都为1,则该位的结果为1,否则为0
| 按位或运算符:只要对应的二个二进位有一个为1时,结果位就为1。
^ 按位异或运算符:当两对应的二进位相异时,结果为1
~ 按位取反运算符:对数据的每个二进制位取反,即把1变为0,把0变为1 。~x 类似于 -x-1
« 左移动运算符:运算数的各二进位全部左移若干位,由 « 右边的数字指定了移动的位数,高位丢弃,低位补0。
» 右移动运算符:把”»“左边的运算数的各二进位全部右移若干位,» 右边的数字指定了移动的位数,低位丢弃,高位补0。

注:按位运算符是把数字看作二进制来进行计算的。

5.1、移位运算符的应用

x = 5
print(x << 2)		# a << n  ==>  a * (2的n次方)
print(x >> 2)		# a << n  ==>  a / (2的n次方)

6、成员运算符

  • 用来判断一个内容在可迭代对象里是否存在
运算符 描述
in 如果在指定的序列中找到值返回 True,否则返回 False。
not in 如果在指定的序列中没有找到值返回 True,否则返回 False。

7、身份运算符

  • 身份运算符用于比较两个对象的存储单元
运算符 描述 实例
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。

注:is 用于判断两个变量引用对象是否为同一个(同一块内存空间), == 用于判断引用变量的值是否相等。

8、Python运算符的优先级

运算符说明 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

注:建议实际使用中,使用()来说明运算顺序,提高程序的可读性。

print(True or False and True)		# True
print(True or (False and True))		# True	建议使用这种写法

四、条件语句

  • Python条件语句是通过一条或多条语句的执行结果(True或者False)来决定执行的代码块。
  • Python程序语言指定任何非0和非空(null)值为true,0 或者 null为false。

1、if……else语句

Python 编程中 if 语句用于控制程序的执行:

if 判断条件
    执行语句……
else
    执行语句……
  • “判断条件”成立时(非零),则执行后面的语句,而执行内容可以多行,以缩进来区分表示同一范围。
  • else 为可选语句,当需要在条件不成立时执行内容则可以执行相关语句。
  • if 语句的判断条件可以用>(大于)、<(小于)、==(等于)、>=(大于等于)、<=(小于等于)来表示其关系。

2、if……elif……elf……else语句

由于Python语言中没有switch语句,对于多分枝的条件语句,使用if……elif……elf……else语句来实现,并且根据条件分枝的数量,elif的数量可以增减。

if 判断条件1:
    执行语句1……
elif 判断条件2:
    执行语句2……
elif 判断条件3:
    执行语句3……
else:
    执行语句4……
  • 如果判断需要多个条件需同时判断时,可以使用 or (或),表示两个条件有一个成立时判断条件成功;使用 and (与)时,表示只有两个条件同时成立的情况下,判断条件才成功。
  • if……else语句if……elif……elf……else语句还可以相互嵌套,使用强制缩进表示语句之间的结构
ticket = input('是否买票了Y/N')
if ticket == 'Y' :
    print('买票了,请进')
    safe = input('安检是否通过Y/N')
    if safe == 'Y' :
        print('安检通过进入候车室')
     else :
        print('进站了,安检未通过')
else :
	print('没买票,禁止入内')

3、判断区间

在其他语言,例如C/C++里面,判断区间不可以连写,要表达 $x \in [1,5]$ 这样的区间,一般需要使用逻辑运算符连接,写作:

if(x>=1&&x<=5){
	……
}

在python里可以使用连续的区间判断,,$x \in [1,5]$ 这样的区间,可以直接表达为:

if 1<=x<=5:
	……

4、三元运算符

Python里面没有类似于C/C++里面的三元运算符condition?语句1:语句2这样的运算符,但是有类似功能的三元表达式:

if num1>num2:
    x = num1
else:
    x = num2
    
# 上面的分枝判断语句可以简写为:
x = num1 if num1 > num2 else num2

五、循环语句

  • 循环语句允许我们执行一个语句或语句组多次
  • Python 提供了 for 循环和 while 循环(在 Python 中没有 do..while 循环):
循环类型 描述
while 循环 在给定的判断条件为 true 时执行循环体,否则退出循环体。
for 循环 重复执行语句
嵌套循环 可以在循环体中嵌套循环
  • 循环控制语句可以更改语句执行的顺序。Python支持以下循环控制语句:
控制语句 描述
break 语句 在语句块执行过程中终止循环,并且跳出当前循环
continue 语句 在语句块执行过程中终止当前循环,跳过该次循环,执行下一次循环。
pass 语句 pass是空语句,是为了保持程序结构的完整性。

1、while 循环

Python 语言中 while 语句用于循环执行程序,即在某条件下,循环执行某段程序,以处理需要重复处理的相同任务。其基本形式为:

while 判断条件(condition)
    执行语句(statements)……
  • 执行语句可以是单个语句或语句块。判断条件可以是任何表达式,任何非零、或非空(null)的值均为true。
  • 当判断条件假 false 时,循环结束。
  • while 语句时还有另外两个重要的命令 continue,break 来跳过循环,continue 用于跳过该次循环,break 则是用于退出循环,此外”判断条件”还可以是非零的常值,表示循环必定成立。
  • 如果条件判断语句永远为 true,循环将会无限的执行下去。无限循环可以使用 CTRL+C 来中断循环。
  • 在 python 中,while … else 在循环条件为 false 时执行 else 语句块:
count = 0
while count < 5:
   print("{} is  less than 5".format(count))
   count = count + 1
else:
   print("{} is not less than 5".format(count))

2、for 循环

Python for循环可以遍历任何序列的项目,如一个列表或者一个字符串。for循环的语法格式如下:

for iterating_var in sequence:
   statements(s)

2.1、for 循环使用 else 语句

在 python 中,for … else 表示这样的意思,for 中的语句和普通的没有区别,else 中的语句会在循环正常执行完(即 for 不是通过 break 跳出而中断的)的情况下执行,while … else 也是一样。

2.2、for语句

格式: for ele in iterable

for i in [1,2,3,4]:
	print(i)

3、嵌套循环

Python 语言允许在一个循环体里面嵌入另一个循环。

1)Python for 循环嵌套语法:

for iterating_var in sequence:
   for iterating_var in sequence:
      statements(s)
   statements(s)

2)Python while 循环嵌套语法:

while expression:
   while expression:
      statement(s)
   statement(s)
  • 可以在循环体内嵌入其他的循环体,如在while循环中可以嵌入for循环, 反之,也可以在for循环中嵌入while循环。

4、break语句

  • Python break语句,就像在C语言中,终止当前所在的最内层for或while循环。循环条件没有达到False条件或者序列还没被完全遍历完,也会停止执行循环语句。
  • break语句用在while和for循环中。
  • 如果使用嵌套循环,break语句将停止执行当前所在的最内层的循环。

Python语言 break 语句语法:

break
for letter in 'Python':     
   if letter == 'h':
      break
   print("当前字母 : {}".format(letter))

5、continue语句

  • Python continue 语句跳过本次循环,而break跳出整个循环。
  • continue 语句用来告诉Python跳过当前循环的剩余语句,然后继续进行下一轮循环。
  • continue语句用在while和for循环中。

Python 语言 continue 语句语法格式如下:

continue
for letter in 'Python':     
   if letter == 'h':
      continue
   print("当前字母 : {}".format(letter))

6、pass 语句

  • Python pass 是空语句,是为了保持程序结构的完整性。
  • pass 不做任何事情,一般用做占位语句。

Python 语言 pass 语句语法格式如下:

pass
for letter in 'Python':     
   if letter == 'h':
      pass
    print("这是pass代码块")
   print("当前字母 : {}".format(letter))

在 Python 中有时候会看到一个 def 函数:

def func(paras):
    pass

该处的 pass 便是占据一个位置,因为如果定义一个空函数程序会报错,当你没有想好函数的内容是可以用 pass 填充,使程序可以正常运行。

注:空函数中,在 Python3.x 的时候 pass 可以写或不写,但是Python2.x中必须写。

六、数字(Number)

  • Python 数字数据类型用于存储数值。
  • 数据类型是不允许改变的,这就意味着如果改变数字数据类型的值,将重新分配内存空间。
  • 在变量赋值时 Number 对象将被创建,也可以使用del,语句删除一些数字对象的引用:
var1 = 1
var2 = 10
var3=1
del var1
del var2, var3

1、Python 支持三种不同的数值类型

1)整型(int) :通常被称为是整型或整数,是正、负整数和零,不带小数点。Python3 整型是没有限制大小的,可以当作 Long 类型使用,所以 Python3 没有 Python2 的 Long 类型。布尔(bool)是整型的子类型。

2)浮点型(float) :浮点型由整数部分与小数部分组成,浮点型也可以使用科学计数法表示(2.5e2 = 2.5 x 10^2 = 250)

3)复数( (complex)) :复数由实数部分和虚数部分构成,可以用a + bj,或者complex(a,b)表示, 复数的实部a和虚部b都是浮点型。

还可以使用十六进制和八进制表示整数:

>>> number = 0xA0F # 十六进制
>>> number
2575

>>> number=0o37 # 八进制
>>> number
31

2、Python数字类型转换

数据类型的转换,只需要将数据类型作为函数名即可:

  • int(x) 将x转换为一个整数。
  • float(x) 将x转换到一个浮点数。
  • complex(x) 将x转换到一个复数,实数部分为 x,虚数部分为 0。
  • complex(x, y) 将 x 和 y 转换到一个复数,实数部分为 x,虚数部分为 y。x 和 y 是数字表达式。

3、Python数字运算

Python 数字运算表达式的语法很直白: +, -, *** 和 **/, 和其它语言(如Pascal或C)里一样。

  • 在不同的机器上浮点运算的结果可能会不一样。
  • 在整数除法中,除法 / 总是返回一个浮点数,如果只想得到整数的结果,丢弃可能的分数部分,可以使用运算符 //
  • // 得到的并不一定是整数类型的数,它与分母分子的数据类型有关系。
  • Python 可以使用 ** 操作来进行幂运算:
>>> 5 ** 2  # 5 的平方
25
  • 变量在使用前必须先”定义”(即赋予变量一个值),否则会出现错误
  • 不同类型的数混合运算时会将整数转换为浮点数
  • 在交互模式中,最后被输出的表达式结果被赋值给变量 ** 。 ** 变量应被用视为只读变量:
>>> tax = 12.5 / 100
>>> price = 100.50
>>> price * tax
12.5625
>>> price + _
113.0625
>>> round(_, 2)
113.06

4、数学函数

使用下列函数之前,需要导入数学包:

import math
函数 返回值 ( 描述 )
abs(x) 返回数字的绝对值,如abs(-10) 返回 10
ceil(x) 返回数字的向上取整的结果,如math.ceil(4.1) 返回 5
cmp(x, y) 如果 x < y 返回 -1, 如果 x == y 返回 0, 如果 x > y 返回 1。 Python 3 已废弃,使用 (x>y)-(x<y) 替换
exp(x) 返回e的x次幂(e^x),如math.exp(1) 返回2.718281828459045
fabs(x) 返回浮点数字绝对值,如math.fabs(-10) 返回10.0
floor(x) 返回数字的向下取整的结果,如math.floor(4.9)返回 4
log(x) 对数函数,如math.log(math.e)返回1.0,math.log(100,10)返回2.0
log10(x) 返回以10为底数的x的对数,如math.log10(100)返回 2.0
max(x1, x2,…) 返回给定参数的最大值,参数可以为序列。
min(x1, x2,…) 返回给定参数的最小值,参数可以为序列。
modf(x) 返回x的整数部分与小数部分,两部分的数值符号与x相同,整数部分以浮点型表示。
pow(x, y) 指数函数,返回x**y 运算后的值。
round(x [,n]) 返回浮点数 x 的四舍五入值,n为可选参数,代表舍入到小数点后的位数。
sqrt(x) 返回数字x的平方根。

5、随机数函数

使用下列函数之前,需要导入随机数包:

import random

Python包含以下常用随机数函数:

函数 描述
choice(seq) 从序列的元素中随机挑选一个元素,比如random.choice(range(10)),从0到9中随机挑选一个整数。
randrange ([start,] stop [,step]) 从指定范围内,按指定基数递增的集合中获取一个随机数,基数默认值为 1
random() 随机生成下一个实数,它在[0,1)范围内。
seed([x]) 改变随机数生成器的种子seed。
shuffle(lst) 将序列的所有元素随机排序
uniform(x, y) 随机生成下一个实数,它在[x,y]范围内。

6、三角函数和数学常量

使用下列函数之前,需要导入数学包:

import math
函数 描述
acos(x) 返回x的反余弦弧度值。
asin(x) 返回x的反正弦弧度值。
atan(x) 返回x的反正切弧度值。
atan2(y, x) 返回给定的 X 及 Y 坐标值的反正切值。即arctan(y/x)
cos(x) 返回x的弧度的余弦值。
hypot(x, y) 返回欧几里德范数 sqrt(x^2 + y^2)。
sin(x) 返回的x弧度的正弦值。
tan(x) 返回x弧度的正切值。
degrees(x) 将弧度转换为角度,如degrees(math.pi/2) , 返回90.0
radians(x) 将角度转换为弧度
常量 描述
pi 数学常量 pi(圆周率,一般以π来表示)
e 数学常量 e,e即自然常数(自然常数)。

七、字符串(String)

字符串是 Python 中最常用的数据类型。可以使用引号( )来创建字符串。

var1 = 'Hello World!'
var2="name"

1、访问字符串中的值

  • Python 不支持单字符类型,单字符在 Python 中也是作为一个字符串使用。
  • Python 访问子字符串,可以使用方括号 [] 来截取字符串,字符串的截取的语法格式如下:
变量[下标]		# 字符串中字符的访问
变量[头下标:尾下标]		# 子字符串的访问
  • 索引值以 0 为开始值,-1 为从末尾的开始位置。

img

1.1、字符串切片

切片就是从字符串里复制一段指定内容,生成一段新的字符串

切片语法: 变量名[​start:end:step]

包含start, 不包含end, start 不填写默认从头开始, end不填写默认到最后一个

step 指的是步长, 理解为间隔, 每隔 step-1 个取一个值

step 也可控制取向, 正数从左向右取值; 负数从右向左取值. 默认为1.

n = 'abcdefghijklmnopqrstuvwxyz'		#第一个字符数为0, 从右向左第一个为-1
print(n[2:5])		#cde
print(n[1:9:2])		#bdfh
print(n[::-1])		#倒叙打印
print(n[-5:-2])		#vwx	step默认为1,从左向右输出
print(n[-2:-5:-1])	#yxw

2、字符串更新

1)可以截取字符串的一部分并与其他字段拼接:

>>> var1 = 'Hello World!'
>>> print ("已更新字符串 : ", var1[:6] + 'Runoob!')
已更新字符串 :  Hello Runoob!

3、转义字符

在需要在字符中使用特殊字符时,python 用反斜杠 \ 转义字符:

转义字符 描述
\(在行尾时) 续行符
\\ 反斜杠符号
\' 单引号
\" 双引号
\a 响铃
\b 退格(Backspace)
\000
\n 换行
\v 纵向制表符
\t 横向制表符
\r 回车,将 \r 后面的内容移到字符串开头,并逐一替换开头部分的字符,直至将 \r 后面的内容完全替换完成。
\f 换页
\yyy 八进制数,y 代表 0~7 的字符,例如:\012 代表换行。
\xyy 十六进制数,以 \x 开头,y 代表的字符,例如:\x0a 代表换行

4、字符串运算符

下表实例变量 a 值为字符串 “Hello”,b 变量值为 “Python”:

操作符 描述 实例
+ 字符串连接 a + b 输出结果: HelloPython
* 重复输出字符串 a*2 输出结果:HelloHello
[] 通过索引获取字符串中字符 a[1] 输出结果 e
[ : ] 截取字符串中的一部分,遵循左闭右开原则,str[0:2] 是不包含第 3 个字符的。 a[1:4] 输出结果 ell
in 成员运算符 - 如果字符串中包含给定的字符返回 True ‘H’ in a 输出结果 True
not in 成员运算符 - 如果字符串中不包含给定的字符返回 True ‘M’ not in a 输出结果 True

5、原生字符串

在字符串前面添加r或R,在Python里表示原生字符串

f = '你好\n世界'	# 这样会打印你好后会换行
g = r'你好\n世界'	# 这样打印就不会换行,而是直接全部原样输出'你好\n世界'

6、字符串格式化输出

在 Python 中,字符串格式化输出使用与 C 中 sprintf 函数一样的语法。

>>> print ("我叫 %s 今年 %d 岁!" % ('小明', 10))
我叫 小明 今年 10 !

6.1、python字符串格式化符号:

符 号 描述
%c 格式化字符及其ASCII码
%s 格式化字符串
%d 格式化整数
%u 格式化无符号整型
%o 格式化无符号八进制数
%x 格式化无符号十六进制数
%X 格式化无符号十六进制数(大写)
%f 格式化浮点数字,可指定小数点后的精度
%e 用科学计数法格式化浮点数
%E 作用同%e,用科学计数法格式化浮点数
%g %f和%e的简写
%G %f 和 %E 的简写
%p 用十六进制数格式化变量的地址

6.2、格式化操作符辅助指令:

符号 功能
* 定义宽度或者小数点精度
- 用做左对齐
+ 在正数前面显示加号( + )
在正数前面显示空格
# 在八进制数前面显示零(‘0’),在十六进制前面显示’0x’或者’0X’(取决于用的是’x’还是’X’)
0 显示的数字前面填充’0’而不是默认的空格
% ’%%’输出一个单一的’%’
(var) 映射变量(字典参数)
m.n. m 是显示的最小总宽度,n 是小数点后的位数(如果可用的话)

6.3、字符串的 format() 方法

# 使用空{}占位,顺序填入
print('大家好,我是{},今年{}岁,来自{}'.format('张三', 18, 'Handan'))		# 注意format前面是.点
# 输出为:大家好,我是张三,今年18岁,来自Handan

# 使用{数字}占位,按照数字顺序填入,从0开始
print('大家好,我是{2},今年{0}岁,来自{1}'.format(18, 'Handan', '张三'))
# 输出为:大家好,我是张三,今年18岁,来自Handan

# 使用{变量名}占位
print('大家好,我是{name},今年{age}岁,来自{home}'.format(name='张三',home = '邯郸', age=18))
# 输出为:大家好,我是张三,今年8岁,来自邯郸

#{数字}和{变量名}可以混合使用,要求变量要放在最后
print('大家好,我是{1},今年{age}岁,来自{home},今天挣了{0}元'.format(88,'张三',home='Handan',age=18))
# 输出为大家好,我是张三,今年18岁,来自Handan,今天挣了88元

#空{}和{变量名}可以混合使用,要求变量要放在最后
print('大家好,我是{},今年{age}岁,来自{home},今天挣了{}元'.format('张三',88,home='Handan',age=18))
# 输出为大家好,我是张三,今年18岁,来自Handan,今天挣了88元

#空{}和{数字}不能混合使用

6.4、三引号

python三引号允许一个字符串跨多行,字符串中可以包含换行符、制表符以及其他特殊字符。

para_str = """这是一个多行字符串的实例
多行字符串可以使用制表符
TAB ( \t )。
也可以使用换行符 [ \n ]。
"""
print (para_str)

# 输出结果为:
这是一个多行字符串的实例
多行字符串可以使用制表符
TAB (    )
也可以使用换行符 [ 
 ]

6.5、f-string

f-string 格式化字符串以 f 开头,后面跟着字符串,字符串中的表达式用大括号 {} 包起来,它会将变量或表达式计算后的值替换进去:

>>> name = 'Runoob'
>>> f'Hello {name}'  # 替换变量
'Hello Runoob'
>>> f'{1+2}'         # 使用表达式
'3'

>>> w = {'name': 'Runoob', 'url': 'www.runoob.com'}
>>> f'{w["name"]}: {w["url"]}'
'Runoob: www.runoob.com'
  • 在 Python 3.8 的版本中可以使用 = 符号来拼接运算表达式与结果:
>>> x = 1
>>> print(f'{x+1}')   # Python 3.6
2

>>> x = 1
>>> print(f'{x+1=}')   # Python 3.8
x+1=2

7、Python中字符串常用函数

1)capitalize():将字符串的第一个字符转换为大写

2)count(str, beg= 0,end=len(string)):返回 str 在 string 里面出现的次数,如果 beg 或者 end 指定则返回指定范围内 str 出现的次数

3)endswith(suffix, beg=0, end=len(string)) 检查字符串是否以 suffix 结束,如果beg 或者 end 指定则检查指定的范围内是否以 obj 结束,如果是,返回 True,否则返回 False.

4)expandtabs(tabsize=8):把字符串 string 中的 tab 符号转为空格,tab 符号默认的空格数是 8 。

5)find(str, beg=0, end=len(string)):检测 str 是否包含在字符串中,如果指定范围 beg 和 end ,则检查是否包含在指定范围内,如果包含返回开始的索引值,否则返回-1

6)index(str, beg=0, end=len(string)):跟find()方法一样,只不过如果str不在字符串中会报一个异常。

7)isalnum():如果字符串至少有一个字符并且所有字符都是字母或数字则返 回 True,否则返回 False

8)isalpha():如果字符串至少有一个字符并且所有字符都是字母或中文字则返回 True, 否则返回 False

9)isdigit():如果字符串只包含数字则返回 True 否则返回 False..

10)islower():如果字符串中包含至少一个区分大小写的字符,并且所有这些(区分大小写的)字符都是小写,则返回 True,否则返回 False

11)isnumeric():如果字符串中只包含数字字符,则返回 True,否则返回 False

12)isspace():如果字符串中只包含空白,则返回 True,否则返回 False.

12)isupper():如果字符串中包含至少一个区分大小写的字符,并且所有这些(区分大小写的)字符都是大写,则返回 True,否则返回 False

13)join(seq):以指定字符串作为分隔符,将 seq 中所有的元素(的字符串表示)合并为一个新的字符串

14)len(string):返回字符串长度

15)lower():转换字符串中所有大写字符为小写.

16)max(str):返回字符串 str 中最大的字母。

17)min(str):返回字符串 str 中最小的字母。

18)replace(old, new [, max]):将字符串中的 old 替换成 new,如果 max 指定,则替换不超过 max 次。

19)rfind(str, beg=0,end=len(string)):类似于 find()函数,不过是从右边开始查找.

20)rindex( str, beg=0, end=len(string)):类似于 index(),不过是从右边开始.

21)split(str=””, num=string.count(str)):以 str 为分隔符截取字符串,如果 num 有指定值,则仅截取 num+1 个子字符串

22)startswith(substr, beg=0,end=len(string)):检查字符串是否是以指定子字符串 substr 开头,是则返回 True,否则返回 False。如果beg 和 end 指定值,则在指定范围内检查。

23)swapcase():将字符串中大写转换为小写,小写转换为大写

24)upper():转换字符串中的小写字母为大写

25)isdecimal():检查字符串是否只包含十进制字符,如果是返回 true,否则返回 false。

八、列表(List)

  • 列表是最常用的 Python 数据类型,它可以作为一个方括号内的逗号分隔值出现。
  • 列表的数据项不需要具有相同的类型
  • 创建一个列表,只要把逗号分隔的不同的数据项使用方括号括起来即可。

1、访问列表中的值

  • 与字符串的索引一样,列表索引从 0 开始,第二个索引是 1,依此类推。通过索引列表可以进行截取、组合等操作。
  • 索引也可以从尾部开始,最后一个元素的索引为 -1,往前一位为 -2,以此类推。
  • 使用下标索引来访问列表中的值,同样你也可以使用方括号 [] 的形式截取字符

2、列表添加元素的方法

使用 appendinsertextend 方法

  • append 在列表末尾添加元素
  • insert 指定位置插入元素
  • extend 合并两个列表(可迭代对象)

3、列表删除元素的方法

使用 popremoveclear 的方法

  • pop 默认删除最后一个元素,也可传入index参数,用来删除指定位置的元素
  • remove 删除指定元素
  • clear 清空列表
  • 使用 del 也可以删除数据

4、列表修改元素的方法

使用下标直接修改对应元素

5、 列表查找元素的方法

使用 indexcount 的方法和成员运算符 in

  • index 查找元素并返回元素的下标,如果元素不存在就会报错
  • count 查找元素出现的次数,并返回 int 值
x = ['h','e','l','l','o']
print(x.index('o'))			# 4
# print(x.index('t'))
print(x.count('l'))			# 2
print('h' in x)				# True
print('k' in x)				# False

6、列表的遍历

遍历常用的方法有while和for…in…语句

shooter = ['后羿', '黄忠', '虞姬', '公孙离', '狄仁杰','孙尚香', '李元芳','百里守约', '鲁班七号']
i = 0
while i < len(shooter)
	print(shooter[i])
    i++
shooter = ['后羿', '黄忠', '虞姬', '公孙离', '狄仁杰','孙尚香', '李元芳','百里守约', '鲁班七号']
#for..in..的本质是调用面向对象的next方法
for i in shooter
	print(i) 
# 使用内置函数enumerate()进行带下标的遍历
for i, people in enumerate(shooter): 
    print('第%d个是%s' % (i,people))

7、列表的复制

1)直接赋值(这不是复制)

x = [10,20,30]
y = x	# y 和 x 指向同一个内存地址
x[0] = 1	# 修改 x ,y也会随着改变

2)调用列表的 copy 方法

x = [10,20,30]
z = x.copy()	# y 和 x 指向不同内存地址
x[0] = 1		# 修改 x ,z不会随之改变

3)调用copy模块

import copy
x = [10,20,30]
a=copy.copy(x)	#效果等价于copy方法,都是一个浅拷贝
x[0]=1			# 修改x,y 不会改变

4)使用切片进行拷贝

x = [10,20,30]
y = x[:]		# 切片也是一个浅拷贝
x[0] = 1		# 修改x,y 不会改变

7、列表排序

7.1、使用各种排序算法

冒泡排序、快速排序,归并排序、插入排序、选择排序、堆排序、基数排序、希尔排序等算法

7.2、调用列表的 sort 方法可以直接对列表进行排序

nums = [5,9,3,4,7,0,2,1,6,8]
nums.sort()		#默认为正序
print(nums)
nums.sort(reverse=True)		#添加 reverse=True 参数为逆序
print(nums)

7.3、使用内置函数 sorted ,生成一个新的有序列表,不会改变原来的列表

nums = [5,9,3,4,7,0,2,1,6,8]
x = sorted(nums)
print(nums)
print(x)

8、列表反转

8.1、使用列表的 reverse 方法列表进行反转

names = ['张三','李四','王五']
names.reverse()
print(names)

8.2、使用下标和切片输出

names = ['张三','李四','王五']
print(names[::-1])

9、嵌套列表

嵌套列表即在列表里创建其它列表,类似于C语言的二维数组

10、列表推导式

用一个简单的代码创建一个列表

x = [i for i in range(10)]
pront(x)		# [0,1,2,3,4,5,6,7,8,9]

t = [i for i in range(10) if i % 2 == 0]
print(t)		# [0,2,4,6,8]

# points 是一个列表,里面元素都是元组
points = [(x,y) for x in range(5,10) for y in range(10,20)]		# for语句是嵌套的
print(points)		# 共有 50 个元素

11、Python列表函数&方法

函数 描述
len() 返回列表元素个数
max() 返回列表元素最大值
min() 返回列表元素最小值
list() 将元组转换为列表
方法 描述
append() 在列表末尾添加新的对象
count() 统计某个元素在列表中出现的次数
extend() 在列表末尾一次性追加另一个序列中的多个值(用新列表扩展原来的列表)
index() 从列表中找出某个值第一个匹配项的索引位置
insert() 将对象插入列表
pop() 移除列表中的一个元素(默认最后一个元素),并且返回该元素的值
remove() 移除列表中某个值的第一个匹配项
reverse() 反向列表中元素
sort() 对原列表进行排序
clear() 清空列表
copy() 复制列表

九、元组(Tuple)

  • Python 的元组与列表类似,不同之处在于元组的元素不能修改。
  • 元组使用小括号 ( ),列表使用方括号 [ ]
  • 元组创建很简单,只需要在括号中添加元素,并使用逗号隔开即可。
>>> tup1 = ('Google', 'Runoob', 1997, 2000)
>>> tup2 = (1, 2, 3, 4, 5 )
>>> tup3 = "a", "b", "c", "d"   #  不需要括号也可以
>>> type(tup3)
<class 'tuple'>

# 创建空元组
tup4 = ()
  • 元组中只包含一个元素时,需要在元素后面添加逗号 , ,否则括号会被当作运算符使用:
>>> tup1 = (50)
>>> type(tup1)     # 不加逗号,类型为整型
<class 'int'>

>>> tup1 = (50,)
>>> type(tup1)     # 加上逗号,类型为元组
<class 'tuple'>
  • 元组与类表类似,下标索引从 0 开始,可以进行截取,组合等操作。
  • 元组可以使用下标索引来访问元组中的值。

1、修改元祖

元组中的元素值是不允许修改的,但可以对元组进行连接组合:

tup1 = (12, 34.56)
tup2 = ('abc', 'xyz')
 
# 以下修改元组元素操作是非法的。
# tup1[0] = 100
 
# 创建一个新的元组
tup3 = tup1 + tup2

2、删除元祖

元组中的元素值是不允许删除的,但可以使用del语句来删除整个元组:

# 创建元组
tup = ('Google', 'Runoob', 1997, 2000)

# 删除整个元组
# 此时若对元组进行输出,会报错,提示tup未定义
del tup

3、元组运算符

与字符串一样,元组之间可以使用 + 号和 ***** 号进行运算。这就意味着他们可以组合和复制,运算后会生成一个新的元组。

Python 表达式 结果 描述
len((1, 2, 3)) 3 计算元素个数
(1, 2, 3) + (4, 5, 6) (1, 2, 3, 4, 5, 6) 连接
('Hi!',) * 4 (‘Hi!’, ‘Hi!’, ‘Hi!’, ‘Hi!’) 复制
3 in (1, 2, 3) True 元素是否存在
for x in (1, 2, 3): print (x, end=" ") 1 2 3 迭代

4、元组截取

元组也是一个序列,可以访问元组中的指定位置的元素,也可以截取索引中的一段元素:

tup = ('Google', 'Runoob', 'Taobao', 'Wiki', 'Weibo','Weixin')
tup[1]		# 'Runoob'	读取第二个元素
tup[-2]		# 'Weibo'	反向读取,读取倒数第二个元素
tup[1:]		# ('Runoob', 'Taobao', 'Wiki', 'Weibo', 'Weixin')	截取元素,从第二个开始后的所有元素。
tup[1:4] 	# 	('Runoob', 'Taobao', 'Wiki')	截取元素,从第二个开始到第四个元素(索引为 3)。

5、元组内置函数

函数 描述
len(tuple) 返回元组元素个数。
max(tuple) 返回元组中元素最大值。
min(tuple) 返回元组中元素最小值。
tuple(iterable) 将可迭代序列转换为元组。

6、元组不可变

  • 所谓元组的不可变指的是元组所指向的内存中的内容不可变。
  • 重新赋值的元组,绑定到新的对象了,不是修改了原来的对象。
>>> tup = ('r', 'u', 'n', 'o', 'o', 'b')
>>> tup[0] = 'g'     # 不支持修改元素
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'tuple' object does not support item assignment
    
    
>>> id(tup)     # 查看内存地址
4440687904
>>> tup = (1,2,3)
>>> id(tup)
4441088800    # 内存地址不一样了

十、字典(Dictionary)

  • 字典是另一种可变容器模型,且可存储任意类型对象。
  • 字典的每个键值 key=>value 对用冒号 : 分割,每个对之间用逗号(,)分割,整个字典包括在花括号 {}
  • 字典的值可以是任何的 python 对象,既可以是标准的对象,也可以是用户定义的,但键不行。
  • 不允许同一个键出现两次。创建时如果同一个键被赋值两次,后一个值会被存储
  • 键必须不可变,所以可以用数字,字符串或元组充当,而用列表就不行
  • 字典的格式如下:
d = {key1 : value1, key2 : value2, key3 : value3 }

1、字典创建

  • 键必须是唯一的,但值则不必。
  • 值可以取任何数据类型,但键必须是不可变的,如字符串,数字。

1.1、空字典创建

1)使用大括号 { } 创建空字典:

# 使用大括号 {} 来创建空字典
emptyDict = {}

2)使用内建函数 dict() 创建字典:

# 使用内建函数dict()创建空字典:
emptyDict = dict()

2、访问字典里的值

1)把相应的键放入到方括号中

tinydict = {'Name': 'Runoob', 'Age': 7, 'Class': 'First'}
 
print ("tinydict['Name']: ", tinydict['Name'])

2)如果用字典里没有的键访问数据,会报错:

tinydict = {'Name': 'Runoob', 'Age': 7, 'Class': 'First'}
 
print ("tinydict['Alice']: ", tinydict['Alice'])


# 报错内容
Traceback (most recent call last):
  File "test.py", line 5, in <module>
    print ("tinydict['Alice']: ", tinydict['Alice'])
KeyError: 'Alice'

3)使用字典的 get 方法

person = {'name': 'zhangsan', 'age': 18,'x':'y'}
print(person.get('name'))


# 如果 key 不存在,会默认返回 None,而不报错
print(person.get('whit'))	# None


# 如果 key 不存在,可以返回给定值
print(person.get('geter','falge'))	# falge

3、修改字典

1)向字典添加新内容的方法是增加新的键/值对,通过键添加键值对

tinydict = {'Name': 'Runoob', 'Age': 7, 'Class': 'First'}
 
# 使用key修改对应的value
tinydict['Age'] = 8      

# 添加新的键值对
tinydict['day'] = "Wed"  

2)使用字典的 update 方法合并两个字典

person1 = {'name': 'zhangsan', 'age': 18}
person2 = { 'heighe': 185, 'whit': 65}
person1.update(person2)
print(person1)		

4、字典的删除操作

  • 使用 del() 方法删除单一的元素
  • 使用 clear() 方法清空字典
  • 使用 del() 方法删除整个字典
  • 使用字典的 pop方法,把key对应的键值对删除了,并返回value值
  • 使用字典的popitem()方法,删除一个键值对,并返回一个由该键值对组成元素的元组
tinydict = {'Name': 'Runoob', 'Age': 7, 'Class': 'First'}
 
del tinydict['Name'] # 删除键 'Name'
tinydict.clear()     # 清空字典
del tinydict         # 删除字典


person = {'name': 'zhangsan', 'age': 18, 'heighe': 185, 'whit': 65}
print(person.pop('age'))	# 把key对应的键值对删除了,并返回value值
print(person.popitem())		# 删除一个键值对,并返回一个由该键值对组成元素的元组

5、字典的遍历

person = {'name': 'zhangsan', 'age': 18, 'heighe': 185, 'whit': 65}
# 字典遍历
# 方法一:
for k in person:  # k 获取的是 key
    print(k, ':', person[k])
    
    
# 方法二:
print(person.keys())  # dict_keys(['name', 'age', 'heighe', 'whit'])
for k in person.keys():  # keys() 方法是获取字典的key
    print(k, ':', person[k])
    
    
# 方法三:
print(person.values())  # dict_values(['zhangsan', 18, 185, 65])
for v in person.values():  # 使用 values() 方法获取字典的value
    print(v)  # 只能打印 value
    
    
# 方法四:
print(person.items())	# items() 方法获取的是字典的键值对
# dict_items([('name', 'zhangsan'), ('age', 18), ('heighe', 185), ('whit', 65)])
for k, v in person.items():  # 利用了拆包方法
    print(k, ':', v)
'''常用方法一和方法四'''

6、字典推导式

# 交换key,value
person = {'name': 'zhangsan', 'age': 18, 'heighe': 185, 'whit': 65}

# 方法一:
person1 = {}
for k,v in person.items():
    person1[v] = k
person = person1


# 方法二:推导式
person={v:k for k,v in person.items()}  # 交换key和value
print(person)

7、字典内置函数&方法

函数 描述
len(dict) 计算字典元素个数,即键的总数。
str(dict) 输出字典,可以打印的字符串表示。
type(variable) 返回输入的变量类型,如果变量是字典就返回字典类型。
函数 描述
dict.clear() 删除字典内所有元素
dict.copy() 返回一个字典的浅复制
dict.fromkeys() 创建一个新字典,以序列seq中元素做字典的键,val为字典所有键对应的初始值
dict.get(key,default=None) 返回指定键的值,如果键不在字典中返回 default 设置的默认值
key in dict 如果键在字典dict里返回true,否则返回false
dict.items() 以列表返回键值对的视图对象
dict.keys() 返回键的视图对象
dict.setdefault(key,default=None) 和get()类似, 但如果键不存在于字典中,将会添加键并将值设为default
dict1.update(dict2) 把字典dict2的键/值对合并到dict1里
dict.values() 返回值的视图对象
pop(key[,default]) 删除字典给定键 key 所对应的值,返回值为被删除的值。key值必须给出。 否则,返回default值。
popitem() 返回并删除字典中的最后一对键和值。

十一、集合

  • 集合(set)是一个无序的不重复元素序列。
  • 可以使用大括号 { } 或者 set() 函数创建集合,注意:创建一个空集合必须用 set() 而不是 { },因为 { } 用来创建一个空字典。

1、集合的创建与运算

>>> basket = {'apple', 'orange', 'apple', 'pear', 'orange', 'banana'}
>>> print(basket)                      # 这里演示的是去重功能
{'orange', 'banana', 'pear', 'apple'}


>>> 'orange' in basket                 # 快速判断元素是否在集合内
True
>>> 'crabgrass' in basket
False


>>> # 下面展示两个集合间的运算.
...
>>> a = set('abracadabra')
>>> b = set('alacazam')
>>> a                                  
{'a', 'r', 'b', 'c', 'd'}


>>> a - b                              # 集合a中包含而集合b中不包含的元素
{'r', 'd', 'b'}

>>> a | b                              # 集合a或b中包含的所有元素
{'a', 'c', 'r', 'd', 'b', 'm', 'z', 'l'}

>>> a & b                              # 集合a和b中都包含了的元素
{'a', 'c'}

>>> a ^ b                              # 不同时包含于a和b的元素
{'r', 'd', 'b', 'm', 'z', 'l'}

1.1、集合推导式

>>> a = {x for x in 'abracadabra' if x not in 'abc'}
>>> a
{'r', 'd'}

2、添加元素

2.1、使用 add() 方法

s.add( x )
# 将元素 x 添加到集合 s 中,如果元素已存在,则不进行任何操作。

2.2、使用 update() 方法

# 参数可以是列表,元组,字典等迭代对象
s.update( x )

# x 可以有多个,用逗号分开。
thisset = set(("Google", "Runoob", "Taobao"))
>>> thisset.update({1,3})
>>> print(thisset)
{1, 3, 'Google', 'Taobao', 'Runoob'}
>>> thisset.update([1,4],[5,6])  
>>> print(thisset)
{1, 3, 4, 5, 6, 'Google', 'Taobao', 'Runoob'}
>>>

3、移除元素

3.1、使用 remove() 方法

# 将元素 x 从集合 s 中移除,如果元素不存在,则会发生错误。
s.remove( x )

3.2、使用 discard() 方法

# 如果元素不存在,不会发生错误
s.discard( x )

3.3、使用 pop() 方法

# 随机删除集合中的一个元素
s.pop()
  • set 集合的 pop 方法会对集合进行无序的排列,然后将这个无序排列集合的左面第一个元素进行删除。

3.4、使用 clear() 方法

# 清空集合 s。
s.clear()

4、计算集合元素数量

# 计算集合 s 元素个数。
len(s)

5、判断元素是否在集合中存在

# 判断元素 x 是否在集合 s 中,存在返回 True,不存在返回 False。
x in s

6、集合内置方法

方法 描述
add() 为集合添加元素
clear() 移除集合中的所有元素
copy() 拷贝一个集合
difference() 返回多个集合的差集
difference_update() 移除集合中的元素,该元素在指定的集合也存在。
discard() 删除集合中指定的元素
intersection() 返回集合的交集
intersection_update() 返回集合的交集。
isdisjoint() 判断两个集合是否包含相同的元素,如果没有返回 True,否则返回 False。
issubset() 判断指定集合是否为该方法参数集合的子集。
issuperset() 判断该方法的参数集合是否为指定集合的子集
pop() 随机移除元素
remove() 移除指定元素
symmetric_difference() 返回两个集合中不重复的元素集合。
symmetric_difference_update() 移除当前集合中在另外一个指定集合相同的元素,并将另外一个指定集合中不同的元素插入到当前集合中。
union() 返回两个集合的并集
update() 给集合添加元素

十二、函数

  • 函数是组织好的,可重复使用的,用来实现单一,或相关联功能的代码段。
  • 函数能提高应用的模块性,和代码的重复利用率。

1、函数定义

  • Python 定义函数使用 def 关键字,一般格式如下:
def 函数名参数列表:
    函数体
  • 函数代码块以 def 关键词开头,后接函数标识符名称和圆括号 ()
  • 圆括号之间用于定义参数;
  • 函数内容以冒号 : 起始,并且缩进;
  • return [表达式] 结束函数,也可以没有返回值;
  • 默认情况下,参数值和参数名称是按函数声明中定义的顺序匹配起来的。
# 返回两数中的较大者
def max(a, b):
    if a > b:
        return a
    else:
        return b

2、函数调用

  • 调用一个函数, 直接使用 函数名+() 就可以
  • 调用注意:函数必须先定义、后调用,否则会报错,函数中调用函数不受此限制

函数调用格式:

# 先定义函数
def max(a, b):
    if a > b:
        return a
    else:
        return b
        
# 再调用函数
maxValue=max(1,2)

3、函数的参数

  • 从主调函数和被调函数之间数据传送角度可分为有参函数和无参函数
    • 形式参数:在函数声明和定义时的参数,称为形式参数(简称形参)
    • 实际参数:在函数调用时必须给出的参数,称为实际参数(简称实参)
# 函数定义
def add(a,b):	# 此 a,b 就是形参
    c = a + b
	return c
# 调用
print(add(1,2))	# 1和2 为实际给出的故为实参
  • Python 函数可使用的正式参数类型:
    • 必需参数(位置参数)
    • 关键字参数
    • 默认参数(缺省参数)
    • 不定长参数(可变参数)

3.1、可更改对象和不可更改对象参数

1)在 python 中,类型属于对象,对象有不同类型的区分,变量是没有类型的:

a=[1,2,3]

a="Python"

[1,2,3] 是 List 类型,“Python” 是 String 类型,而变量 a 是没有类型,她仅仅是一个对象的引用(一个指针),可以是指向 List 类型对象,也可以是指向 String 类型对象。

2)在 python 中,strings, tuples, 和 numbers 是不可更改的对象,而 list,dict 等则是可以修改的对象。

  • 不可更改类型:变量赋值 a=5 后再赋值 a=10,这里实际是新生成一个 int 值对象 10,再让 a 指向它,而 5 被丢弃,不是改变 a 的值,相当于新生成了 a。
  • 可更改类型:变量赋值 la=[1,2,3,4] 后再赋值 la[2]=5 则是将 list la 的第三个元素值更改,本身la没有动,只是其内部的一部分值被修改了。

3)python 函数的参数,根据参数是否为可修改对象,函数的参数可以分为可更改对象参数和不可更改对象参数

  • 不可更改类型参数:类似 C++ 的值传递,如整数、字符串、元组。如 fun(a),传递的只是 a 的值,没有影响 a 对象本身。如果在 fun(a) 内部修改 a 的值,则是新生成一个 a 的对象,不会影响外部的 a 的值。
  • 可更改类型参数:类似 C++ 的引用传递,如 列表,字典。如 fun(la),则是将 la 真正的传过去,修改后 fun 外部的 la 也会受影响。

不可更改类型参数:

def change(a):
    print(id(a))   # 指向的是同一个对象
    a=10
    print(id(a))   # 一个新对象
 
a=1
print(id(a))
change(a)


'''
输出结果:
4379369136
4379369136
4379369424
'''

# 可以看出在调用函数前后,形参和实参指向的是同一个对象(对象 id 相同),在函数内部修改形参后,函数内部的a和外部的a的对象 id 不同了,表明此时函数内部的 a 是一个新的对象。

可更改类型参数:

def changeme( mylist ):
   # 修改传入的列表
   mylist.append([1,2,3,4])
   print ("函数内取值: ", mylist)
   return
 
# 调用changeme函数
mylist = [10,20,30]
changeme( mylist )
print ("函数外取值: ", mylist)


'''
输出结果:
函数内取值:  [10, 20, 30, [1, 2, 3, 4]]
函数外取值:  [10, 20, 30, [1, 2, 3, 4]]
'''

#  可变对象在函数里被修改了,在这个函数外部,对象内容也被修改了,表明函数内部和函数外部的 mylist 是同一个对象。

3.2、必需参数(位置参数)

  • 必需参数须以正确的顺序传入函数。调用时的数量必须和声明时的一样,顺序和数量都必须一致
# 定义函数,这里printme 函数只有一个参数,并且为必需参数
def printme( str ):
   print (str)
   return
 
# 调用函数,不加参数会报错
printme()

'''
程序报错:
Traceback (most recent call last):
  File "test.py", line 10, in <module>
    printme()
TypeError: printme() missing 1 required positional argument: 'str'
'''

3.3、关键字参数

  • 关键字参数和函数调用关系紧密,函数调用使用关键字参数来确定传入的参数值。
  • 使用关键字参数允许函数调用时参数的顺序与声明时不一致,因为 Python 解释器能够用参数名匹配参数值。
  • 参数在传递时关键字参数需在所有必需参数后面, 必需参数则顺序传递, 关键字参数则不必按顺序。
def printinfo( name, age ):
   print ("名字: ", name)
   print ("年龄: ", age)
   return
 
#调用printinfo函数
printinfo( age=50, name="python" )

'''
输出结果:
名字:  python
年龄:  50
'''


def add(a,b,c,d):	# 此 a,b 就是形参
    sum = a + b	+ c + d
	return sum
# 调用
print(add(1,2,d=4,c=3))	# 1,2为位置参数顺序传递给a,b;d=4,c=3为关键字参数,传递给对应形参d,c
# 注意:如果c为关键字参数,则之后的所有参数都必须为关键字参数

3.4、缺省参数

  • 当用户给定参数内容时,则按用户给定的实参, 如果没有给定参数,则按默认的参数
# print 就是一个包含缺省参数的函数,sep 参数和 end 参数就有默认值,调用的时候若没有给定这两个参数值,默认用空格连接,结束为换行
print('hello','world',sep = '+',end = '')	# 默认用空格连接,结束为换行



# 定义缺省参数, 直接在参数后面给定默认值即可
def introduce(name, age, monthly_income='1w'):	# 缺省参数必须放在最后面
    print('大家好,我是{},今年{}岁,月入{}元'.format(name, age, monthly_income))


introduce('张三', 25)			# 大家好,我是张三,今年25岁,月入1w元
introduce('李四', 24, '9k')	# 大家好,我是李四,今年24岁,月入9k元

3.5、不定长参数

  • 可变参数表示用户输入多少参数,则接受多少:
    • 使用 *args 表示参数会以元组(tuple)的形式导入,存放所有未命名的变量参数。
    • 使用 **kwargs 表示参数会以字典的形式导入。

注:args和kwargs变量名是可以更改的

1)单星号 *不定长参数函数

def functionname([formal_args,] *var_args_tuple ):
   function_suite
   return [expression]
# 可变位置参数
def add(a, b, *args):	# 如果有缺省参数应放在*arge后面,如: def add(a, b, *args, num1=10):
    c = a + b
    for arg in args:
        c += arg
    return c


print(add(1, 2, 3, 4, 5, 6, 7))     # 1,2传递给a,b 剩下数据以元组的形式传递给args

注:如果在函数调用时没有指定参数,它就是一个空元组。

  • 声明函数时,参数中星号 *** 可以单独出现,如果单独出现星号 *** 后的参数必须用关键字传入。
>>> def f(a,b,*,c):
...     return a+b+c
... 
>>> f(1,2,3)   # 报错
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: f() takes 2 positional arguments but 3 were given
>>> f(1,2,c=3) # 正常
6
>>>

2)双星号**不定长参数函数

def functionname([formal_args,] **var_args_dict ):
   function_suite
   return [expression]
def add(a, b, *args,num1=10,**kwargs):
    c = a + b
    for arg in args:
        c += arg
    return c

print(add(1, 2, 3, 4, num1=3, x=5, y=6))	#  1,2传递给a,b,之后直到 num=3 之间的参数以元组的形式传递给args,最后剩下的参数以字典的形式传递给 kwargs(kwargs中的内容为:['x':5,'y':6])

4、函数的返回值

  • 函数按有无返回值分为有返回值函数和无返回值函数
  • 函数返回值是通过被调函数使主调函数得到一个确定值, 使用 return 语句
def add(a,b):
    c = a +b
    return c	# 将c返回给主调函数
t = add(1,2)
print(t)
  • 函数返回多个值
# 一般情况下函数只执行一个return
# 特殊情况(finally语句)下,一个函数可能执行多个return语句
def test(a, b):
    x = a // b
    y = a % b
   # return x		# return语句表示一个函数的结束
	# return y		# 所以不会执行到此行
	return x, y		# return返回的实质是一个元组,但是小括号()可以省略,等价于 return (x, y)

	return [x, y]	# 可以返回一个列表
	return {'x':x, 'y':y}	# 也可以返回一个字典


shang, yushu = test(32,6)	# 元组拆包
print('商是{},余数是{}'.format(shang, yushu))

5、参数类型建议

def add(a, b):

    c = a + b
    return c



# 在Python里的函数参数类型不会被限制
print(add('hello', 'world'))	


# 但是我们可以给使用建议数据类型
def acc(a: int, b: int):
    c = a * b
    return c


print(acc('hello', 4))		# 一般'hello'会有警告提示,但不会报错

6、匿名函数(Lambda 函数)

  • Python 使用 lambda 可以创建匿名函数
  • 匿名函数,就是不再使用 def 语句这样标准的形式定义一个函数
    • lambda 只是一个表达式,函数体比 def 简单
    • lambda 的主体是一个表达式,而不是一个代码块
    • lambda 函数拥有自己的命名空间,且不能访问自己参数列表之外或全局命名空间里的参数
    • 虽然 lambda 函数看起来只能写一行,却不等同于 C 或 C++ 的内联函数,后者的目的是调用小函数时不占用栈内存从而增加运行效率

Lambda 函数 语法格式:

lambda [arg1 [,arg2,.....argn]]:expression
sum = lambda arg1, arg2: arg1 + arg2
 
# 调用sum函数
print ("相加后的值为 : ", sum( 10, 20 ))
print ("相加后的值为 : ", sum( 20, 20 ))
  • 可以将匿名函数封装在一个函数内,这样可以使用同样的代码来创建多个匿名函数
def myfunc(n):
  return lambda a : a * n
 
mydoubler = myfunc(2)		# mydoubler=lambda a:a*2
mytripler = myfunc(3)		# mytripler=lambda a:a*3
 
print(mydoubler(11))		# 22
print(mytripler(11))		# 33
  • 把匿名函数当做参数传递给另一个函数
# 调用一个函数,完成多种运算
def calc(a, b, fn):
    c = fn(a, b)
    return c
	

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


def mul(x, y):
    return x * y


calc(4, 3, add)  # 将函数名作为参数
calc(5, 7, mul)



# 当函数表达式比较简单时,可以使用匿名函数
# 把匿名函数作为函数参数
print(calc(21, 7, lambda x, y: x / y))

7、强制位置参数

  • Python3.8 新增了一个函数形参语法 / 用来指明函数形参必须使用指定位置参数,不能使用关键字参数的形式。
def f(a, b, /, c, d, *, e, f):
    print(a, b, c, d, e, f)
    
# 形参 a 和 b 必须使用指定位置参数,c 和 d 可以是位置形参或关键字形参,而 e 和 f 要求为关键字形参:

8、函数调用

  • 函数之间可以相互调用, 也可以嵌套调用。函数还可以自己调用自己, 称为递归调用

函数之间相互调用:

def fact(n):  # 求n的阶乘
    t = 1
    for i in range(1, n + 1):
        t *= i
    return t


def fac_sum(m):		# 求阶乘的和
    x = 0
    for i in range(1, m + 1):
        x += fact(i)		# 函数调用函数
    return x

print(fac_sum(5))

函数递归调用;

# 使用递归调用,实现快排
def quick_sort(data):
    if len(data) >= 2:  # 递归入口及出口
        mid = data[len(data) // 2]  # 选取基准值,也可以选取第一个或最后一个元素
        left, right = [], []  # 定义基准值左右两侧的列表
        data.remove(mid)  # 从原始数组中移除基准值
        for num in data:
            if num >= mid:
                right.append(num)
            else:
                left.append(num)
        return quick_sort(left) + [mid] + quick_sort(right)		# 递归调用
    else:
        return data		# 递归出口		递归结束条件:len(data)<2


'''
array = [2, 3, 5, 7, 1, 4, 6, 15, 5, 2, 7, 9, 10, 5, 9, 17]
print(quick_sort(array))
# 输出为[1, 2, 2, 3, 4, 5, 5, 5, 6, 7, 7, 9, 9, 10, 15, 17]
'''

9、递归函数

在写递归函数时应该注意不能使函数调用成为”死循环”,应该设置好递归结束条件

def say_story():
    print('老头和小伙讲故事')
    print('讲故事的是')
    say_story()				# 这样会陷入死循环,导致报错
    
say_story()

10、全局变量和局部变量

  • 变量的有效范围(作用范围)称为变量的作用域
# 全局变量,在整个py文件里都可以使用
a = 14  
word = '你好'



# 在Python里,只用函数能分割变量作用域
def test():  
    x = 'ok'  # 定义在函数内部的变量为局部变量,只能在函数内度使用

    # 如果函数内变量的名和全局变量同名,会在函数内定义一个新的变量,而不是修改全局变量,即在函数作用域内,将同名全局变量屏蔽了
    a = 10
    print('函数内部a={}'.format(a))

    # 使用global进行对外部变量声明,进行修改全局变量
    # 通过global的声明,取消了对 word 的屏蔽,这里使用和外部的 word 是同一个
    global word
    word = 'hello'

    # 使用内置函数 locals()查看局部变量, globals()查看全局变量
    print('locals={},\nglobals={}'.format(locals(), globals()))


test()
# print('x={}', format(x))      #函数外部不能使用函数内部的变量,会报错,变量未定义
print('函数外部a={}'.format(a))
print('函数外部word={}'.format(word))

11、高阶应用

1)把一个函数作为另一个函数的返回值

def test():
    print('我是test函数')
    return 'hello'

def bar():
    print('我是bar函数')
    
    # 在这里返回的是对test 函数的调用,书架上是在 bar 函数结束之前对test 函数调用了一次,bar返回的是test函数的返回值
    return test()	# 返回的是函数,即调用函数	

def demo():
    print('我是demo函数')
    return test		# 返回的是变量名,可以作为字符串被python解析

# 调用 函数 bar ,实际上运行了bar函数一遍,并且还运行了一遍 test 函数
bar()
'''
输出结果:
我是bar函数
我是test函数
'''

# 将 函数 bar的返回值赋给 x,并执行了一遍 bar函数
# x中存放的是test的返回值,字符串"hello",x类似于一个宏
x=bar()
print(x)
'''
输出结果:
我是bar函数 
我是test函数
'''

# demo()()先执行一遍函数demo,之后变成 test(),再执行一遍函数 test()
demo()()
'''
输出结果:
我是demo函数
我是test函数
'''

先执行一遍demo函数此时y相当于一个宏内部存放的是字符串常量 "test"之后再执行一遍函数 test
y = demo()
y()
'''
输出结果:
我是demo函数
我是test函数
'''

2)Python支持函数的嵌套定义,在函数内部再定义一个函数

def data():
    print('data被被打印了')
    def lanm():
        print('lanm被打印了')
    return lanm()

'''
输出结果:
data被被打印了
lanm被打印了
'''

3)闭包函数

闭包函数和上面的嵌套函数类似,不同之处在于,闭包中外部函数返回的不是一个具体的值,而是一个函数。类似于把一个函数作为另一个函数的返回值实例中的demo函数的返回值

def outer():
    x = 10		# 在外部函数定义了一个变量x,为一个局部变量
    y = 30
    def inner():	
        x = 20	# 不是修改外部变量x,而是在内部函数创建了一个新的变量x
        z = y + 1	# 可以直接使用外部函数变量,但是不能修改
        # 在内部函数用 nonlocal 声明外部函数变量
        nonlocal y
        y = 10	# 此时是修改外部函数变量y
    return inner	# 返回的是 inner 函数首地址,加小括号才能调用


# outer()() 相当于是 inner()
outer()()		# 先返回的是 inner ,加上()后是调用
#闭包函数,其中 exponent 称为自由变量
def nth_power(exponent):
    def exponent_of(base):
        return base ** exponent
    return exponent_of # 返回值是 exponent_of 函数


square = nth_power(2) # 计算一个数的平方,square是一个函数指针
cube = nth_power(3) # 计算一个数的立方,cube是一个函数指针
print(square(2))  # 计算 2 的平方,相当于 nth_power(2)(2)
print(cube(2)) # 计算 2 的立方,相当于 nth_power(3)(2)


def nth_power_rewrite(base, exponent):
    return base ** exponent



# 不使用闭包
res1 = nth_power_rewrite(base1, 2)
res2 = nth_power_rewrite(base2, 2)
res3 = nth_power_rewrite(base3, 2)


# 使用闭包
square = nth_power(2)
res1 = square(base1)		# 相当于 nth_power(2)(base1)
res2 = square(base2)		# 相当于 nth_power(2)(base2)
res3 = square(base3)		# 相当于 nth_power(2)(base3)

12、装饰器

  • 装饰器指的是定义一个函数,该函数是用来为其他函数添加额外的功能,就是拓展原来函数功能的一种函数
  • 装饰器在不修改被装饰器对象源代码以及调用方式的前提下为被装饰对象添加新功能

12.1、装饰器语法结构

def function_name(fn):
    def inner():
        pass
    
    return inner

# 在不改变 demo 函数源码的条件下,为 demo 函数添加了 function_name 函数中的功能
@function_name		# 用来装饰deom函数
def deom():
    pass

12.2、装饰器原理

import time


def cal_time(fn):
    def inner():
        start = time.time()
        t = fn()
        end = time.time()
        print('程序耗时', end - start)
        return t

    return inner


@cal_time  		#第一件事调用cal_time;	第二件事把被装饰的函数传给fn;
def dome():		# 第三件事返回inner给dome,即dome=inner(dome指向inner函数首地址)
    for i in range(1,100000000):
        i += i
    return i

# 第四件事当再调用dome时,此时的dome函数不再是上面的dome,而是inner+demo
print('装饰后的dome={}'.format(dome))
# 装饰后的dome=<function cal_time.<locals>.inner at 0x00000281704D83A0>
dome()

12.3、装饰器的一个简单应用

# 提需求/改需求

def wegame(name,game):
    print('{}在玩{}'.format(name,game))
    
wegame('张三','王者荣耀')
# 该需求,在22点后不能玩了
# 一般我们不会在原函数上修改了
def funct(fn):
    def inner(x,y,time):
        if time>=22:
            ptint('太晚了,不能打游戏了')
         else:
            fn(x,y)
    
    return inner


@funct
def wegame(name,game):
    print('{}在玩{}'.format(name,game))
    
wegame('张三','王者荣耀',time=23)

注:函数名不能重名, 否则后一个会覆盖前一个

变量名不能和函数名一样, 因为函数名相当于一个变量

十三、模块

  • 模块通俗的讲就是一个符合命名规范py文件, 一个模块通常包含多个函数/变量或函数和变量

1、导入模块和的方法及使用

1) import 模块名

import time		# 使用 	import 模块名 		直接导入
time.time()		# 模块名.函数名 	使用模块里的函数
time.sleep(3)	# 可以使用模块里所有的函数或变量

2)form 模块名 import 函数名/子包名

from random import randint		# 使用	 form 模块名 import 函数名/子包名 	导入模块里一个函数或变量
randint(0,2)	# 直接使用且只能使用这一个函数

3)form 模块名 import *

from math import *		# 使用 	form 模块名 import * 		导入模块里所用函数和变量

# 可以直接使用模块里所有函数和变量
print(pi)	
abs(-4)		

注:from math import * 实质是导入模块里__all__列表包含的变量和函数,如果没有__all__才会导入所有的变量和函数,但不能导入以一个下换线开始的变量和函数

4)import datetime as dt 导入一个模块,并起一个别名

import datetime as dt	# 导入一个模块,并起一个别名
dt.MAXYEAR		# 使用别名代替原模块名

5)from copy import deepcopy as dp 导入模块里一个函数或变量,并起一个别名

from copy import deepcopy as dp		# 导入模块里一个函数或变量,并起一个别名
dp(['hello','good'[1,5,9],'yes'])

6)其他注意事项

# 也可以一次导入多个模块,多个模块之间用逗号隔开。
# 导入sys、os两个模块
import sys,os


# 导入sys、os两个模块,并为sys指定别名s,为os指定别名o
import sys as s,os as o


# 导入sys模块的argv,winver成员
from sys import argv, winver


# 导入sys模块的argv,winver成员,并为其指定别名v、wv
from sys import argv as v, winver as wv

2、分层的文件系统中常用的包结构

sound/                          顶层包
      __init__.py               初始化 sound 包
      formats/                  文件格式转换子包
              __init__.py
              wavread.py
              wavwrite.py
              aiffread.py
              aiffwrite.py
              auread.py
              auwrite.py
              ...
      effects/                  声音效果子包
              __init__.py
              echo.py
              surround.py
              reverse.py
              ...
      filters/                  filters 子包
              __init__.py
              equalizer.py
              vocoder.py
              karaoke.py
              ...
  • 在导入一个包的时候,Python 会根据 sys.path 中的目录来寻找这个包中包含的子目录。
  • 目录只有包含一个叫做 __init__.py 的文件才会被认作是一个包
  • 如果包定义文件 __init__.py 存在一个叫做 __all__ 的列表变量,那么在使用 from package import * 的时候就把这个列表中的所有名字作为包内容导入。
  • 如果 __all__ 真的没有定义,那么使用from sound.effects import *这种语法的时候,就不会导入包 sound.effects 里的任何子模块。他只是把包sound.effects和它里面定义的所有内容导入进来(可能运行__init__.py里定义的初始化代码)
  • 一般为了防止两个模块中有相同的名称的成员,不推荐使from math import *语法
from modname1 import *
from modname2 import *
from modname3 import *

# 这样写代码的时候,代码中的变量会变得非常混乱。不仅仅是后面导入的同名函数会覆盖前面的问题,而且导致在写一个函数的时候不能确定它到底来自哪里,代码可读性会变得非常差。


# 建议尽量这样写
import modname1
import modname2
import modname3

modname1.def1()
modname2.def1()
modname3.def1()
# 这样不仅不会找不见同名函数,也可以非常确切的看到这个函数来自哪里


# 如果库一层套一层,是这样的结构:
import path1.path2.path3.modname1
# 可以用as关键字给它重命名,以便于缩短代码宽度,维持可读性
import path1.path2.path3.modname1 as pm

3、OS 模块

  • os模块里提供的方法主要用来处理操作系统里的文件和文件夹
  • OS 模块常用方法
import os

# 返回正在使用的平台。如果是windows则用‘nt’表示,对于linux/unix用户则用'posix'表示。
os.name		

# 返回当前python脚本工作的目录路径。
os.getcwd()		
# 返回一个当前工作目录的Unicode对象
os.getcwdb()
# 获取当前目录的父目录,以字符串形式显示目录名。
os.pardir()

# 获取环境配置
os.environ	
# 获取指定环境配置
os.environ.get('PATH')	

# 返回指定目录下的所有文件和目录名,括号里如果调用函数则不用双引号或单引号,如果是传入一个路径,则必须要用双引号或单引号将变量标识为一个整体,否则报错。括号内可以:1)调用函数 2)传入参数(即路径)
os.listdir()	

# 重命名
os.rename(name,name1)	
# 删除一个文件,括号里必须是文件的指定路径
os.remove("文件路径")   
# 删除空文件夹
os.rmdir('文件夹路径')	
 # 删除空文件夹
os.removedirs('文件夹路径')	
# 创建一个文件夹
os.mkdir()		

# 运行shell命令
os.system("shell命令")	

# 改变当前脚本的工作目录,相当于shell下的cd命令
os.chdir(path)		
# 返回上级目录
os.chdir('../')	

# 取代操作系统特定的路径分隔符,python是跨平台的,在windows上,文件的路径分隔符是'\'。为了让代码在不同的平台上上都能运行,使用os.sep会根据你所处的平台,自动采用相应的分隔符号。
os.sep()		

# 返回当前平台使用的行终止符,Linux使用'\n', windows使用'\r\n', mac使用'\r'.
os.linesep()		

# 获取文件的属性信息。
os.path 模块
# 返回一个路径的目录名和文件名
os.path.split()		
# 检验给出的是否为文件
os.path.isfile()	
# 检验给出的是否为文件夹	
os.path.isdir() 		
# 检验给出的路径是否真实存在
os.path.exists()		
# 获得文件的绝对路径
os.path.abspath(name)	
# 规范path字符串形式
os.path.normpath(path)		
# 获取文件大小(字节); 在没写文件的路径的时候,默认的是当前的工作路径
os.path.getsize(name)	
# 分离文件名与扩展名
os.path.splitext()		
# 连接目录与文件名或目录
os.path.join(path,name)		
# 返回文件名,不包含拓展名
os.path.basename(path)		
# 返回文件路径
os.path.dirname(path)		

# 更改权限
os.chmod(path,flags)
# 更改文件所有者
os.chown(path,uid,gid)

# 改变当前进程的根目录
os.chroot(path)

# 关闭文件描述符 fd
os.close(fd)
# 关闭所有文件描述符,从 fd_low (包含) 到 fd_high (不包含), 错误会忽略
os.closerange(fd_low,fd_high)
# 复制文件描述符 fd
os.dup(fd)
# 将一个文件描述符 fd 复制到另一个 fd2
os.dup2(fd,fd2)
# 通过文件描述符改变当前工作目录
os.fchdir(fd)
# 改变一个文件的访问权限,该文件由参数fd指定,参数mode是Unix下的文件访问权限。
os.fchmod(fd,mod)
# 修改一个文件的所有权,这个函数修改一个文件的用户ID和用户组ID,该文件由文件描述符fd指定。
os.fchown(fd,uid,gid)
# 强制将文件写入磁盘,该文件由文件描述符fd指定,但是不强制更新文件的状态信息。
os.fdatafsync(fd)
# 强制将文件描述符为fd的文件写入硬盘。
os.fsync(fd)

# 打开一个文件,并且设置需要的打开选项,mode参数是可选的
os.fopen(file,flags[,mode])
# 创建一个管道. 返回一对文件描述符(r, w) 分别为读和写
os.pipe()
# 从文件描述符 fd 中读取最多 n 个字节,返回包含读取字节的字符串,文件描述符 fd对应文件已达到结尾, 返回一个空字符串。
os.read(fd,n)

# 删除文件路径
os.unlink(path)

# 写入字符串到文件描述符 fd中. 返回实际写入的字符串长度
os.write(fd,str)

4、sys 模块

  • 提供对解释器使用或维护的一些变量的访问,以及与解释器强烈交互的函数
import sys
print(sys.path)		# 返回一个列表,列出查找模块的所有路径
sys.argv		# 传递给Python脚本的命令行参数列表
sys.exit()		# 程序退出,和内置函数exit功能一样

sys.stdin		# 接收用户输入
sys.stdout		# 标准输出, 改变默认输出位置(如:输出到一个文件里)
sys.stderr		# 改变错误输出的默认位置

5、math 模块

  • math模块为浮点运算提供了对底层C函数库的访问
>>> import math
>>> math.cos(math.pi / 4)
0.70710678118654757

>>> math.log(1024, 2)
10.0

6、random 模块

  • random提供了生成随机数的工具
>>> import random
>>> random.choice(['apple', 'pear', 'banana'])
'apple'

>>> random.sample(range(100), 10)   # sampling without replacement
[30, 83, 16, 4, 8, 81, 41, 50, 18, 33]

>>> random.random()    # random float
0.17970987693706186
>>> random.randrange(6)    # random integer chosen from range(6)
4

7、datetime 模块

  • datetime模块为日期和时间处理同时提供了处理的方法。还支持时区处理
>>> from datetime import date
>>> now = date.today()
>>> now
datetime.date(2003, 12, 2)
>>> now.strftime("%m-%d-%y. %d %b %Y is a %A on the %d day of %B.")
'12-02-03. 02 Dec 2003 is a Tuesday on the 02 day of December.'


>>> birthday = date(1964, 7, 31)
>>> age = now - birthday
>>> age.days
14368

8、time 模块

import time		# 导入时间模块
start = time.time()		# 获取当前时间戳
#时间戳就是格林威治时间1970年01月01日00时00分00秒(北京时间1970年01月01日08时00分00秒)起到现在的总秒数

time.sleep(3)	# 延时3秒
time.localtime(start)	# 格式化时间戳为本地时间, 返回一个时间元组

time.asctime(time.localtime(start))	#接受一个时间元组并返回一个可读的形式


time.ctime([secs])	# 需要一个时间戳,如果没有则返回计算机时间	
time.gmtime()	# 返回一个格林威治天文时间下的时间

end=time.time();

lenTime=end-start		# 单位为秒

9、zlib 模块

>>> import zlib
>>> s = b'witch which has which witches wrist watch'
>>> len(s)
41

>>> t = zlib.compress(s)
>>> len(t)
37

>>> zlib.decompress(t)
b'witch which has which witches wrist watch'
>>> zlib.crc32(s)
226805979

10、glob 模块

  • glob模块提供了一个函数用于从目录通配符搜索中生成文件列表
>>> import glob
>>> glob.glob('*.py')
['primes.py', 'random.py', 'quote.py']

11、re 模块

  • re模块为高级字符串处理提供了正则表达式工具。对于复杂的匹配和处理,正则表达式提供了简洁、优化的解决方案
>>> import re
>>> re.findall(r'\bf[a-z]*', 'which foot or hand fell fastest')
['foot', 'fell', 'fastest']
>>> re.sub(r'(\b[a-z]+) \1', r'\1', 'cat in the the hat')
'cat in the hat'
  • 如果只需要简单的功能,应该首先考虑字符串方法,因为它们非常简单,易于阅读和调试
>>> 'tea for too'.replace('too', 'two')
'tea for two'

12、互联网访问相关 模块

  • 有几个模块用于访问互联网以及处理网络通信协议。其中最简单的两个是用于处理从 urls 接收的数据的 urllib.request 以及用于发送电子邮件的 smtplib
>>> from urllib.request import urlopen
>>> for line in urlopen('http://tycho.usno.navy.mil/cgi-bin/timer.pl'):
...     line = line.decode('utf-8')  # Decoding the binary data to text.
...     if 'EST' in line or 'EDT' in line:  # look for Eastern Time
...         print(line)

<BR>Nov. 25, 09:43:32 PM EST

>>> import smtplib
>>> server = smtplib.SMTP('localhost')
>>> server.sendmail('soothsayer@example.org', 'jcaesar@example.org',
... """To: jcaesar@example.org
... From: soothsayer@example.org
...
... Beware the Ides of March.
... """)
>>> server.quit()

13、hashlib和hmac模块

  • 这两个模块都是用来加密的,加密方式: 单向加密(只有加密过程,不能解密,如md5/sha))、对称加密、非对称加密
  • hashlib模块主要有md5sha两种加密算法
import hashlib

# 需要将加密的内容转化为二进制
x=hashlib.md5()		# 生成一个md5对象
x.update('123'.encode('utf8'))
print(x.hexdigest())
# hmac模块也是一种单向的加密算法,并且它是基于各种哈希算法/散列算法,
# 只是它可以在运算的过程中,使用一种密钥来增强安全性,hmac模块实现了HAMC算法,
# 提供了相应的函数和方法,且与hashlib提供的api基本一致.
import hmac

h = hmac.new(bytes('secret_key','utf8'),bytes('ssssddddddd','utf8'),hashlib.sha1)
#第一个参数是密钥key,第二个参数是待加密的字符串,第三个参数是hash函数
# Python3 key和带加密字符串需转换为bytes类型,且需要utf8编码
result = h.hexdigest()
print(result)

14、使用pip命令管理第三方库

14.1、pip 命令使用

# 下载安装第三方库
pip install <库名>		

# 卸载第三方库
pip uninstall <库名>		

# 列出当前环境安装了哪些模块和版本号
pip list		

# 列出当前环境安装了哪些模块和版本号
pip freeze		

# 重定向,即将安装的库及对应的版本号放到 requirements.txt文件里
pip freeze > requirements.txt		

# 读取并安装文件里的库
pip -r install requirements.txt		

# 临时从指定网站下载
pip install <库名> -i <网址> 		

14.2、永久更改默认下载地址

  • 在用户目录下创建一个pip文件夹,然后再在文件夹里创建一个pip.ini文件并输入以下内容
[global]
index-url=https://mirrors.aliyun.com/pypi/simple
[install]
trusted-host=mirrors.aliyun.com

15、自定义模块

  • 模块是符合命名规范py文件, 所以创建一个py文件就可以创建自定义模块
__all__ = ['m', 'date']
'''from <模块名> import * 语法只能调用__all__列表包含的变量和函数,
如果没有__all__才会导入所有的变量和函数,但不能导入以一个下换线开始的变量和函数'''

m = 'hello'
a = 1000


def date():
    print('我是模块里的name')


# 约定俗成: 以一个下划线开始的变量和函数只在本模块内部使用,不建议外部调用,如果强行调用可能会崩
_x = 'world'  # 使用 from <> impport * 语法无法调用以一个下划线开始的变量和函数,通过不将 _x放入 __all__来保证使用 import * 不会导入 _x



def _qute():
    print('我是_qute函数')
    
def division(a,b):
    return a/b


# __name__当直接运行py文件时,值是__main__
# 如果这个py文件作为模块导入时,值是文件名
if __name__=='__main__':       # 使用次语句可以检测模块里的函数,而在调用时不执行以下内容
    print('模块里的name是:',__name__)    # 模块里的name是: __main__
    print('测试一下 division 函数,结果是:',division(4,2))


# 在最后使用del函数删除变量和函数,即使外部强行调用也会崩,没有删除的可以调用
# 约定俗成:只删除以一个下划线开始的变量和函数
del (_x)

16、python 包

16.1、包定义

  • 为了组织好模块,会将多个模块封装为包
  • Python 处理包也是相当方便的。简单来说,包就是文件夹,但该文件夹下必须存在 __init__.py 文件
  • 常见的包结构:
sound/                          顶层包
      __init__.py               初始化 sound 包
      formats/                  文件格式转换子包
              __init__.py
              wavread.py
              wavwrite.py
              aiffread.py
              aiffwrite.py
              auread.py
              auwrite.py
              ...
      effects/                  声音效果子包
              __init__.py
              echo.py
              surround.py
              reverse.py
              ...
      filters/                  filters 子包
              __init__.py
              equalizer.py
              vocoder.py
              karaoke.py
              ...
  • 最简单的情况下,只需要一个空的 __init__.py 文件即可。当然它也可以执行包的初始化代码,或者定义 __all__ 变量

16.2、导入包

  • 包的导入仍使用 import 、 from … import 语句,使用 “圆点模块名” 的结构化模块命名空间

十四、迭代器与生成器

1、迭代器

  • 迭代器是一个可以记住遍历的位置的对象。
  • 迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束。迭代器只能往前不会后退。
  • 迭代器有两个基本的方法:iter()next()

1.1、迭代器创建

# 列表创建迭代器
>>> list=[1,2,3,4]
>>> it = iter(list)    # 创建迭代器对象
>>> print (next(it))   # 输出迭代器的下一个元素
1
>>> print (next(it))
2
>>>

1.2、迭代器遍历

1)使用 for 语句进行遍历:

list=[1,2,3,4]
it = iter(list)    # 创建迭代器对象
for x in it:
    print (x, end=" ")
    
    
'''
输出结果:
1 2 3 4
'''

2)使用 next() 函数遍历:

import sys         # 引入 sys 模块
 
list=[1,2,3,4]
it = iter(list)    # 创建迭代器对象
 
while True:
    try:
        print (next(it))
    except StopIteration:
        sys.exit()
        
'''
输出结果:
1
2
3
4
'''

2、生成器

  • 在 Python 中,使用了 yield 的函数被称为生成器(generator)
  • 生成器是一个返回迭代器的函数,只能用于迭代操作
  • 在调用生成器运行的过程中,每次遇到 yield 时函数会暂停并保存当前所有的运行信息,返回 yield 的值, 并在下一次执行 next() 方法时从当前位置继续运行。
# 使用 yield 实现斐波那契数列:
import sys
 
def fibonacci(n): # 生成器函数 - 斐波那契
    a, b, counter = 0, 1, 0
    while True:
        if (counter > n): 
            return
        yield a
        a, b = b, a + b
        counter += 1
f = fibonacci(10) # f 是一个迭代器,由生成器返回生成
 
while True:
    try:
        print (next(f), end=" ")
    except StopIteration:
        sys.exit()
        
'''
输出结果:
0 1 1 2 3 5 8 13 21 34 55
'''

十五、文件I/O

1、File 方法

1.1、open() 方法

  • Python open() 方法用于打开一个文件,并返回文件对象,如果该文件无法被打开,会抛出 OSError
  • 使用 open() 方法一定要保证关闭文件对象,即调用 close() 方法。
  • open() 函数常用形式是接收两个参数:文件名(file)和模式(mode):
open(file, mode='r')	# 以只读方式打开文件。文件的指针将会放在文件的开头。这也是默认模式。

# open函数的完整参数
open(file, mode='r', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)

'''
参数说明:
file: 必需,文件路径(相对或者绝对路径)。
mode: 可选,文件打开模式
buffering: 设置缓冲
encoding: 一般使用utf8
errors: 报错级别
newline: 区分换行符
closefd: 传入的file参数类型
opener: 设置自定义开启器,开启器的返回值必须是一个打开的文件描述符。
'''

1.2、mode 参数

模式 描述
t 文本模式 (默认)。
x 写模式,新建一个文件,如果该文件已存在则会报错。
b 二进制模式。
+ 打开一个文件进行更新(可读可写)。
U 通用换行模式(Python 3 不支持)。
r 以只读方式打开文件。文件的指针将会放在文件的开头。这是默认模式。
rb 以二进制格式打开一个文件用于只读。文件指针将会放在文件的开头。这是默认模式。
r+ 打开一个文件用于读写。文件指针将会放在文件的开头。
rb+ 以二进制格式打开一个文件用于读写。文件指针将会放在文件的开头。
w 打开一个文件只用于写入。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件。
wb 以二进制格式打开一个文件只用于写入。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件。一般用于非文本文件如图片等。
w+ 打开一个文件用于读写。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件。
wb+ 以二进制格式打开一个文件用于读写。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件。
a 打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。也就是说,新的内容将会被写入到已有内容之后。如果该文件不存在,创建新文件进行写入。
ab 以二进制格式打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。也就是说,新的内容将会被写入到已有内容之后。如果该文件不存在,创建新文件进行写入。
a+ 打开一个文件用于读写。如果该文件已存在,文件指针将会放在文件的结尾。文件打开时会是追加模式。如果该文件不存在,创建新文件用于读写。
ab+ 以二进制格式打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。如果该文件不存在,创建新文件用于读写。

2、file 对象

  • file 对象使用 open 函数来创建
  • file 对象常用函数:
方法 描述
file.close() 关闭文件。
file.flush() 刷新文件内部缓冲,直接把内部缓冲区的数据立刻写入文件, 而不是被动的等待输出缓冲区写入。
file.fileno() 返回一个整型的文件描述符(file descriptor FD 整型), 可以用在如os模块的read方法等一些底层操作上。
file.isatty() 如果文件连接到一个终端设备返回 True,否则返回 False。
file.next() Python 3 中的 File 对象不支持 next() 方法。返回文件下一行。
file.read([size]) 从文件读取指定的字节数,如果未给定或为负则读取所有。
file.line([size]) 读取整行,包括 “\n” 字符。
file.seek(offset,whence) 移动文件读取指针到指定位置
file.tell() 返回文件当前位置。
file.write(str) 将字符串写入文件,返回的是写入的字符长度。
file.writelines(sequence) 向文件写入一个序列字符串列表,如果需要换行则要自己加入每行的换行符。
# 将字符串写入到文件 foo.txt 中
# 打开一个文件
f = open("{}/foo.txt".format(path), "w")

f.write( "Python 是一个非常好的语言。\n是的,的确非常好!!\n" )

# 关闭打开的文件
f.close()

十六、Python推导式

  • Python 推导式是一种独特的数据处理方式,可以从一个数据序列构建另一个新的数据序列的结构体。
  • Python 支持各种数据结构的推导式:
    • 列表(list)推导式
    • 字典(dict)推导式
    • 集合(set)推导式
    • 元组(tuple)推导式

1、列表推导式

  • 格式:
[表达式 for 变量 in 列表] 
[out_exp_res for out_exp in input_list]

或者 

[表达式 for 变量 in 列表 if 条件]
[out_exp_res for out_exp in input_list if condition]
  • out_exp_res:列表生成元素表达式,可以是有返回值的函数。
  • for out_exp in input_list:迭代 input_list 将 out_exp 传入到 out_exp_res 表达式中。
  • if condition:条件语句,可以过滤列表中不符合条件的值。
# 过滤掉长度小于或等于3的字符串列表,并将剩下的转换成大写字母:
>>> names = ['Bob','Tom','alice','Jerry','Wendy','Smith']
>>> new_names = [name.upper()for name in names if len(name)>3]
>>> print(new_names)
['ALICE', 'JERRY', 'WENDY', 'SMITH']
# 计算 30 以内可以被 3 整除的整数:
>>> multiples = [i for i in range(30) if i % 3 == 0]
>>> print(multiples)
[0, 3, 6, 9, 12, 15, 18, 21, 24, 27]

2、字典推导式

  • 格式:
{ key_expr: value_expr for value in collection }



{ key_expr: value_expr for value in collection if condition }
# 使用字符串及其长度创建字典:
listdemo = ['sada','egvev', 'sveveavev']
# 将列表中各字符串值为键,各字符串的长度为值,组成键值对
>>> newdict = {key:len(key) for key in listdemo}
>>> newdict
{'sada': 4, 'egvev': 5, 'sveveavev': 9}
# 提供三个数字,以三个数字为键,三个数字的平方为值来创建字典:
>>> dic = {x: x**2 for x in (2, 4, 6)}
>>> dic
{2: 4, 4: 16, 6: 36}
>>> type(dic)
<class 'dict'>

3、集合推导式

  • 格式:
{ expression for item in Sequence }

{ expression for item in Sequence if conditional }
# 计算数字 1,2,3 的平方数:
>>> setnew = {i**2 for i in (1,2,3)}
>>> setnew
{1, 4, 9}
# 判断不是 abc 的字母并输出:
>>> a = {x for x in 'abracadabra' if x not in 'abc'}
>>> a
{'d', 'r'}
>>> type(a)
<class 'set'>

4、元组推导式

  • 格式:
(expression for item in Sequence )

(expression for item in Sequence if conditional )
  • 元组推导式和列表推导式的用法也完全相同,只是元组推导式是用 () 圆括号将各部分括起来,而列表推导式用的是中括号 [],另外元组推导式返回的结果是一个生成器对象。
# 生成一个包含数字 1~9 的元组
>>> a = (x for x in range(1,10))
>>> a
<generator object <genexpr> at 0x7faf6ee20a50>  # 返回的是生成器对象

>>> tuple(a)       # 使用 tuple() 函数,可以直接将生成器对象转换成元组
(1, 2, 3, 4, 5, 6, 7, 8, 9)

十七、进制表示及转换

1、进制表示

  • Python 中默认是十进制,二进制、八进制、十六进制在 Python 中的表示:
a = 0b10101		# 以0b开头表示二进制	只能是0和1
b = 0o157		# 以0o开头表示八进制	只能是0~7
c = 34			# 默认是十进制
d = 0x15af		# 以0x开头表示十六进制	10~15用a~f表示

2、进制转换

2.1、十进制转二进制

  • 整数部分,除基取余,逆序排列;小数部分,乘基取整,顺序排列

2.2、二进制转十进制

  • 二进制数1101.01转化成十进制:

$1101.01(2)=1 \times 2 ^0+0 \times 2^1+1 \times 2 ^2+1 \times 2 ^3+0 \times 2 ^{-1}+1 \times 2 ^{-2}=13.25(10)$

  • 通用公式:

$abcd.efg=d \times 2^0+c \times 2^1+b \times 2^2+a \times 2^3+e \times 2^{-1}+f \times 2^{-2}+g \times 2^{-3}$

  • 十进制和其他进制转换同理

2.3、二进制转八进制

  • 二进制的小数点为分界点,向左(向右)每三位分成一组,接着将这三位二进制按权相加,得到的数就是一位八位二进制数,然后,按顺序进行排列,小数点的位置不变,得到的数字就是我们所求的八进制数。
  • 如果向左(向右)取三位后,取到最高(最低)位时候,如果无法凑足三位,可以在小数点最左边(最右边),即整数的最高位(最低位)添0,凑足三位。

2.4、二进制转十六进制

  • 二进制的小数点为分界点,向左(向右)每四位取成一位,接着将这四位二进制按权相加,得到的数就是一位十六位二进制数,然后,按顺序进行排列,小数点的位置不变,得到的数字就是我们所求的十六进制数。
  • 如果向左(向右)取四位后,取到最高(最低)位时候,如果无法凑足四位,可以在小数点最左边(最右边),即整数的最高位(最低位)添0,凑足四位。

2.5、使用内置函数进行进制转换

a = 12

# 使用bin内置函数可以将数字转换成二进制
print(bin(a))		# 0b1100	

# 使用oct内置函数可以将数字转换成八进制
print(oct(a))		# 0o14		

# 使用hex内置函数可以将数字转换成十六进制
print(hex(12))		# 0xc		

十八、面向对象

1、面向对象简介

  • 类:用来描述具有相同的属性和方法的对象的集合。它定义了该集合中每个对象所共有的属性和方法。对象是类的实例。
  • 方法:类中定义的函数。
  • 类变量:类变量在整个实例化的对象中是公用的。类变量定义在类中且在函数体之外。类变量通常不作为实例变量使用。
  • 数据成员:类变量或者实例变量用于处理类及其实例对象的相关的数据。
  • 方法重写:如果从父类继承的方法不能满足子类的需求,可以对其进行改写,这个过程叫方法的覆盖(override),也称为方法的重写(即C++里面的重载)。
  • 局部变量:定义在方法中的变量,只作用于当前实例的类。
  • 实例变量:在类的声明中,属性是用变量来表示的,这种变量就称为实例变量,实例变量就是一个用 self 修饰的变量。
  • 继承:即一个派生类(derived class)继承基类(base class)的字段和方法。继承也允许把一个派生类的对象作为一个基类对象对待。
  • 实例化:创建一个类的实例,类的具体对象。
  • 对象:通过类定义的数据结构实例。对象包括两个数据成员(类变量和实例变量)和方法。

Python中的类提供了面向对象编程的所有基本功能:类的继承机制允许多个基类,派生类可以覆盖基类中的任何方法,方法中可以调用基类中的同名方法。

对象可以包含任意数量和类型的数据。

2、类定义

2.1、语法格式

class ClassName:
    <statement-1>
    .
    .
    .
    <statement-N>
  • 类实例化后,可以使用其属性,实际上,创建一个类之后,可以通过类名访问其属性。

2.2、类对象

# 小明今年19,早上跑步,去吃饭
# 小妹今年18,早上不跑步,直接吃饭
class Student(object):         # 使用class关键字定义类,类的命名方法遵循大驼峰命名法
    
    # 构造函数
    def __init__(self, x, y):  # 特征 使用__init__(self)函数名获取特征
        self.name = x
        self.age = y

    # 每个函数就是一个行为
    def run(self, t=''):  # 行为1
        print('跑步.', end=t)

    def ect(self, t=''):  # 行为2
        print('去吃饭.', end=t)

    def say_hello(self):
        print('大家好,我是{},今年{}.'.format(self.name, self.age), '我每天早上', end='', sep='')


s1 = Student('zhangsan', 19)		# 使用类创建对象
s1.say_hello()			
s1.run()			# 需要什么行为,则使用对应的方法
s1.ect('\n')

s2 = Student('xiaomei', 18)
s2.say_hello()
s1.ect('\n')

s3 = Student('jack', 20)
s3.say_hello()
s3.run()
'''打印结果如下:
大家好,我是zhangsan,今年19.我每天早上跑步.去吃饭.
大家好,我是xiaomei,今年18.我每天早上去吃饭.
大家好,我是jack,今年20.我每天早上跑步.'''
  • 类对象支持两种操作:属性引用和实例化。
  • 属性引用使用和 Python 中所有的属性引用一样的标准语法:obj.name
  • 类对象创建后,类命名空间中所有的命名都是有效属性名。

2.3、__init__() 方法

  • 类有一个名为 __init__() 的特殊方法(构造方法),该方法在类实例化时会自动调用
def __init__(self):
    self.data = []
    
    
# __init__() 方法可以有参数,参数通过 __init__() 传递到类的实例化操作上
# 在上面的类对象实例化过程中,就是如此
 # 构造函数
    def __init__(self, x, y):  # 特征 使用__init__(self)函数名获取特征
        self.name = x
        self.age = y

2.4、self

  • 类的方法与普通的函数只有一个特别的区别——它们必须有一个额外的第一个参数名称, 按照惯例它的名称是 self。类似于C++里面的 this
  • self 代表的是类的实例,代表当前对象的地址,而 self.class 则指向类
  • self 不是 python 关键字,我们把他换成 其他合法的标识符字符串也是可以的
class Test:
    def prt(self):
        print(self)
        print(self.__class__)
 
t = Test()
t.prt()

'''
输出结果:
<__main__.Test instance at 0x100771878>		# self的内容
__main__.Test							# self.class的内容,主方法中的Test类
'''


# self可以换成其他合法的标识符字符串
# 例如把 self 换成 fles
class Test:
    def prt(fles):
        print(fles)
        print(fles.__class__)
 
t = Test()
t.prt()

'''
输出结果:
<__main__.Test instance at 0x100771878>		# fles的内容
__main__.Test							# fles.class的内容
'''

3、类的方法

  • 在类的内部,使用 def 关键字来定义一个方法,与一般函数定义不同,类方法必须包含参数 self, 且为第一个参数,self 代表的是类的实例。
#类定义
class people:
    #定义基本属性
    name = ''
    age = 0
    #定义私有属性,私有属性在类外部无法直接进行访问
    __weight = 0
    #定义构造方法
    def __init__(self,n,a,w):
        self.name = n
        self.age = a
        self.__weight = w
    def speak(self):
        print("%s 说: 我 %d 岁。" %(self.name,self.age))
 
# 实例化类
p = people('python',32,1)
p.speak()


'''
输出结果:
python 说: 我 32 岁。
'''

4、继承

  • Python 支持类的继承,如果一种语言不支持继承,类就没有什么意义
  • 派生类的定义语法:
class DerivedClassName(BaseClassName):
    <statement-1>
    .
    .
    .
    <statement-N>
  • 子类(派生类 DerivedClassName)会继承父类(基类 BaseClassName)的属性和方法。
  • BaseClassName(实例中的基类名)必须与派生类定义在一个作用域内。除了类,还可以用表达式,基类定义在另一个模块中时这一点非常有用:
class DerivedClassName(modname.BaseClassName):
#类定义
class people:
    #定义基本属性
    name = ''
    age = 0
    #定义私有属性,私有属性在类外部无法直接进行访问
    __weight = 0
    #定义构造方法
    def __init__(self,n,a,w):
        self.name = n
        self.age = a
        self.__weight = w
    def speak(self):
        print("%s 说: 我 %d 岁。" %(self.name,self.age))
 
#单继承示例
class student(people):
    grade = ''
    def __init__(self,n,a,w,g):
       
    	#调用父类的构函
        people.__init__(self,n,a,w)
        self.grade = g
        
    #覆写父类的方法
    def speak(self):
        print("%s 说: 我 %d 岁了,我在读 %d 年级"%(self.name,self.age,self.grade))
 
 
 
s = student('ken',10,60,3)
s.speak()


'''
运行结果:
ken 说: 我 10 岁了,我在读 3 年级
'''

5、多继承

  • 多继承的类定义语法:
class DerivedClassName(Base1, Base2, Base3):
    <statement-1>
    .
    .
    .
    <statement-N>

注:需要注意圆括号中父类的顺序,若是父类中有相同的方法名,而在子类使用时未指定,python从左至右搜索 即方法在子类中未找到时,从左到右查找父类中是否包含方法。

#类定义
class people:
    #定义基本属性
    name = ''
    age = 0
    #定义私有属性,私有属性在类外部无法直接进行访问
    __weight = 0
    #定义构造方法
    def __init__(self,n,a,w):
        self.name = n
        self.age = a
        self.__weight = w
    def speak(self):
        print("%s 说: 我 %d 岁。" %(self.name,self.age))
 
#单继承示例
class student(people):
    grade = ''
    def __init__(self,n,a,w,g):
        #调用父类的构函
        people.__init__(self,n,a,w)
        self.grade = g
    #覆写父类的方法
    def speak(self):
        print("%s 说: 我 %d 岁了,我在读 %d 年级"%(self.name,self.age,self.grade))
 
#另一个类
class speaker():
    topic = ''
    name = ''
    def __init__(self,n,t):
        self.name = n
        self.topic = t
    def speak(self):
        print("我叫 %s,我是一个演说家,我演讲的主题是 %s"%(self.name,self.topic))
 
#多重继承
class sample(speaker,student):
    a =''
    def __init__(self,n,a,w,g,t):
        student.__init__(self,n,a,w,g)
        speaker.__init__(self,n,t)
 
test = sample("Tim",25,80,4,"Python")
test.speak()   #方法名同,默认调用的是在括号中参数位置排前父类的方法


'''
输出结果:
我叫 Tim,我是一个演说家,我演讲的主题是 Python
'''

6、方法重写

  • 如果父类方法的功能不能满足需求,可以在子类重写父类的方法:
class Parent:        # 定义父类
   def myMethod(self):
      print ('调用父类方法')
 
class Child(Parent): # 定义子类
   def myMethod(self):
      print ('调用子类方法')
 
c = Child()          # 子类实例
c.myMethod()         # 子类调用重写方法

# super() 函数用于调用父类(超类)的一个方法
super(Child,c).myMethod() #用子类对象调用父类已被覆盖的方法


'''
输出结果:
调用子类方法
调用父类方法
'''

7、类属性与方法

7.1、类的私有属性

__private_attrs:两个下划线开头,声明该属性为私有,不能在类的外部被使用或直接访问。在类内部的方法中使用时 self.__private_attrs

7.2、类的方法

在类的内部,使用 def 关键字来定义一个方法,与一般函数定义不同,类方法必须包含参数 self,且为第一个参数,self 代表的是类的实例。self 的名字并不是规定死的,也可以使用 其他任意合法的标识符,但是尽量还是按照约定使用 self

7.3、类的私有方法

__private_method:两个下划线开头,声明该方法为私有方法,只能在类的内部调用 ,不能在类的外部调用。在类的内部使用时self.__private_methods

class JustCounter:
    
    # 私有变量
    __secretCount = 0  
    # 公开变量
    publicCount = 0    
 

    def count(self):
        self.__secretCount += 1
        self.publicCount += 1
        print (self.__secretCount)
 
counter = JustCounter()
counter.count()				# 1
counter.count()				# 2
print (counter.publicCount)	# 2
print (counter.__secretCount)  # 报错,实例不能访问私有变量


'''
输出结果:
1		
2
2
Traceback (most recent call last):
  File "test.py", line 16, in <module>
    print (counter.__secretCount)  # 报错,实例不能访问私有变量
AttributeError: 'JustCounter' object has no attribute '__secretCount'
'''


class Site:
    def __init__(self, name, url):
        self.name = name       # public
        self.__url = url   # private
 
    def who(self):
        print('name  : ', self.name)
        print('url : ', self.__url)
 
    def __foo(self):          # 私有方法
        print('这是私有方法')
 
    def foo(self):            # 公共方法
        print('这是公共方法')
        self.__foo()
 
x = Site('百度', 'www.baidu.com')
x.who()        # 正常输出
x.foo()        # 正常输出
x.__foo()      # 报错

'''
输出结果:
name: 百度
url: www.baidu.com
这是公共方法
这是私有方法
Traceback (most recent call last):
  File "test.py", line 22, in <module>
   x.__foo()  
AttributeError: 'Site' object has no attribute '__foo'
'''

7.4、类的专有方法

  • __init__ :构造函数,在生成对象时调用
  • __del__ :析构函数,释放对象时使用
  • __repr__ :打印,转换
  • __setitem__ : 按照索引赋值
  • __getitem__ :按照索引获取值
  • __len__ :获得长度
  • __cmp__ :比较运算
  • __call__ :函数调用
  • __add__ :加运算
  • __sub__ :减运算
  • __mul__ :乘运算
  • __truediv__ :除运算
  • _mod__ :求余运算
  • __pow__ :乘方

7.5、运算符重载

  • Python支持运算符重载,可以对类的专有方法进行重载
class Vector:
   def __init__(self, a, b):
      self.a = a
      self.b = b
 
   def __str__(self):
      return 'Vector (%d, %d)' % (self.a, self.b)
   
   def __add__(self,other):
      return Vector(self.a + other.a, self.b + other.b)
 
v1 = Vector(2,10)
v2 = Vector(5,-2)
print (v1 + v2)


'''
输出结果:
Vector(7,8)
'''

十九、异常处理

1、异常

  • 运行期检测到的错误被称为异常
  • 常见的异常:
    • 0 作为除数
    • 使用未定义变量
    • ……
  • 异常不同于语法错误,多数时候是由于逻辑错误或者内存错误引起。
>>> 10 * (1/0)             # 0 不能作为除数,触发异常
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
ZeroDivisionError: division by zero
    
    
>>> 4 + spam*3             # spam 未定义,触发异常
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
NameError: name 'spam' is not defined
    
    
>>> '2' + 2               # int 不能与 str 相加,触发异常
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: can only concatenate str (not "int") to str

2、异常处理

2.1、try/except

1)使用 try/except 进行异常处理的语法:

try:
    可能存在异常的代码块
except errorType1:
    发生异常1时执行的代码块
except errorType1:
    发生异常2时执行的代码块
    ……
except errorTypen:
    发生异常n时执行的代码块
while True:
    try:
        x = int(input("请输入一个数字: "))
        break
    except ValueError:
        print("您输入的不是数字,请再次尝试输入!")

2)try/except 语句的工作方式:

  • 首先,执行 try 子句(在关键字 try 和关键字 except 之间的代码块,通过缩进来区分);
  • 如果没有异常发生,忽略 except 子句,try 子句执行后结束;
  • 如果在执行 try 子句的过程中发生了异常,那么 try 子句余下的部分将被忽略。如果异常的类型和 except 之后的名称相符,那么对应的 except 子句将被执行;
  • 如果一个异常没有与任何的 except 匹配,那么这个异常将会传递给上层的 try 中;
  • 一个 try 语句可能包含多个except子句,分别来处理不同的特定的异常。最多只有一个分支会被执行;
  • 处理程序将只针对对应的 try 子句中的异常进行处理,而不是其他的 try 的处理程序中的异常;
  • 一个except子句可以同时处理多个异常,这些异常将被放在一个括号里成为一个元组:
except (RuntimeError, TypeError, NameError):
    代码块
  • 最后一个 except 后面没有指定异常类型,那么可以将被当作通配符使用:
import sys

try:
    f = open('myfile.txt')
    s = f.readline()
    i = int(s.strip())
except OSError as err:
    print("OS error: {0}".format(err))
except ValueError:
    print("Could not convert data to an integer.")
except:
    print("Unexpected error:", sys.exc_info()[0])
    raise

2.2、try/except…else

  • try/except 语句还有一个可选的 else 子句,如果使用这个子句,那么必须放在所有的 except 子句之后。
  • else 子句将在 try 子句没有发生任何异常的时候执行。
  • 使用格式:
try:
    可能存在异常的代码块
except errorType1:
    发生异常1时执行的代码块
except errorType1:
    发生异常2时执行的代码块
    ……
except errorTypen:
    发生异常n时执行的代码块
else:
	try 代码块执行完没有异常时执行的代码块
# 在 try 语句中判断文件是否可以打开,如果打开文件时正常的没有发生异常则执行 else 部分的语句,读取文件内容
for arg in sys.argv[1:]:
    try:
        f = open(arg, 'r')
    except IOError:
        print('cannot open', arg)
    else:
        print(arg, 'has', len(f.readlines()), 'lines')
        f.close()
  • 使用 else 子句比把所有的语句都放在 try 子句里面要好,这样可以避免一些意想不到,而 except 又无法捕获的异常。
  • 异常处理并不仅仅处理那些直接发生在 try 子句中的异常,而且还能处理子句中调用的函数(甚至间接调用的函数)里抛出的异常:
>>> def this_fails():
        x = 1/0
   
>>> try:
        this_fails()
    except ZeroDivisionError as err:
        print('Handling run-time error:', err)
   
Handling run-time error: int division or modulo by zero

2.3、try-finally 语句

  • try-finally 语句无论是否发生异常都将执行最后的代码
  • 使用格式:
try:
    可能存在异常的代码块
except errorType1:
    发生异常1时执行的代码块
except errorType1:
    发生异常2时执行的代码块
    ……
except errorTypen:
    发生异常n时执行的代码块
else:
	try 代码块执行完没有异常时执行的代码块
finally:
    执行完前面那一堆之后继续执行这一个代码块

3、抛出异常

  • Python 使用 raise 语句抛出一个指定的异常。
  • raise语法格式:
raise [Exception [, args [, traceback]]]
# 如果 x 大于 5 就触发异常
x = 10
if x > 5:
    raise Exception('x 不能大于 5。x 的值为: {}'.format(x))
    
'''
输出结果:
Traceback (most recent call last):
  File "test.py", line 3, in <module>
    raise Exception('x 不能大于 5。x 的值为: {}'.format(x))
Exception: x 不能大于 5。x 的值为: 10
'''
  • raise 唯一的一个参数指定了要被抛出的异常。它必须是一个异常的实例或者是异常的类(也就是 Exception 的子类)
  • 如果你只想知道这是否抛出了一个异常,并不想去处理它,那么一个简单的 raise 语句就可以再次把它抛出:
>>> try:
        raise NameError('HiThere')
    except NameError:
        print('An exception flew by!')
        raise
An exception flew by!
Traceback (most recent call last):
  File "<stdin>", line 2, in ?
NameError: HiThere

4、用户自定义异常

  • 可以通过创建一个新的异常类来拥有自己的异常。异常类继承自 Exception 类,可以直接继承,或者间接继承:
>>> class MyError(Exception):
        def __init__(self, value):
            self.value = value
        def __str__(self):
            return repr(self.value)
   
>>> try:
        raise MyError(2*2)
    except MyError as e:
        print('My exception occurred, value:', e.value)
   
My exception occurred, value: 4
>>> raise MyError('oops!')
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
__main__.MyError: 'oops!'
  • 当创建一个模块有可能抛出多种不同的异常时,一种通常的做法是为这个包建立一个基础异常类,然后基于这个基础类为不同的错误情况创建不同的子类:
class Error(Exception):
    """Base class for exceptions in this module."""
    pass

class InputError(Error):
    """Exception raised for errors in the input.

    Attributes:
        expression -- input expression in which the error occurred
        message -- explanation of the error
    """

    def __init__(self, expression, message):
        self.expression = expression
        self.message = message

class TransitionError(Error):
    """Raised when an operation attempts a state transition that's not
    allowed.

    Attributes:
        previous -- state at beginning of transition
        next -- attempted new state
        message -- explanation of why the specific transition is not allowed
    """

    def __init__(self, previous, next, message):
        self.previous = previous
        self.next = next
        self.message = message

5、with 关键字

  • Python 中的 with 语句用于异常处理,封装了 try…except…finally 编码范式
  • 关键词 with 语句就可以保证诸如文件之类的对象在使用完之后一定会正确的执行他的清理方法
# 如果在调用 write 的过程中,出现了异常,则 close 方法将无法被执行,因此资源就会一直被该程序占用而无法被释放
file = open('./test.txt', 'w')
file.write('hello world !')
file.close()
# 对可能发生异常的代码处进行 try 捕获,发生异常时执行 except 代码块,finally 代码块是无论什么情况都会执行,所以文件会被关闭,不会因为执行异常而占用资源。
file = open('./test.txt', 'w')
try:
    file.write('hello world')
finally:
    file.close()
# 使用 with 关键字系统会自动调用 f.close() 方法, with 的作用等效于 try/finally 语句是一样的
with open('./test.txt', 'w') as file:
    file.write('hello world !')
    
 # 查看文件是否关闭
>>> f.closed
True

二十、命名空间和作用域

1、命名空间

  • 命名空间(Namespace)是从名称到对象的映射,大部分的命名空间都是通过 Python 字典来实现的。(官方文档翻译)

  • 命名空间提供了在项目中避免名字冲突的一种方法。各个命名空间是独立的,没有任何关系的

  • 同一个命名空间内不能有重复的名称,不同的命名空间可以有重复的名称而没有任何影响

  • 一般有三种命名空间:

    • 内置名称(built-in names), Python 语言内置的名称,比如函数名 abs、char 和异常名称 BaseException、Exception 等等。
    • 全局名称(global names),模块中定义的名称,记录了模块的变量,包括函数、类、其它导入的模块、模块级的变量和常量。
    • 局部名称(local names),函数中定义的名称,记录了函数的变量,包括函数的参数和局部定义的变量。(类中定义的也是)

    这三种命名空间的范围:内置命名空间 > 全局命名空间 > 局部命名空间

1.1、命名空间的查找顺序

  • 假设要使用变量 a,则 Python 的查找顺序为:局部的命名空间去 -> 全局命名空间 -> 内置命名空间
  • 如果找不到变量 a,它将放弃查找并抛出一个 NameError 异常:
NameError: name 'a' is not defined

1.2、命名空间的生命周期

  • 命名空间的生命周期取决于对象的作用域,如果对象执行完成,则该命名空间的生命周期就结束。
  • 无法从外部命名空间访问内部命名空间的对象。

2、作用域

  • 作用域就是一个 Python 程序可以直接访问命名空间的正文区域。
  • 在一个 python 程序中,直接访问一个变量,会从内到外依次访问所有的作用域直到找到,否则会报未定义的错误。
  • 有四种作用域:
    • L(Local):最内层,包含局部变量,比如一个函数/方法内部。
    • E(Enclosing):包含了非局部(non-local)也非全局(non-global)的变量。比如两个嵌套函数,一个函数(或类) A 里面又包含了一个函数 B ,那么对于 B 中的名称来说 A 中的作用域就为 nonlocal。
    • G(Global):当前脚本的最外层,比如当前模块的全局变量。
    • B(Built-in): 包含了内建的变量/关键字等,最后被搜索。
  • 搜索顺序: L –> E –> G –> B。在局部找不到,便会去局部外的局部找(例如闭包),再找不到就会去全局找,再者去内置中找。
  • Python 中只有模块(module),类(class)以及函数(def、lambda)才会引入新的作用域,其它的代码块(如 if/elif/else/、try/except、for/while等)是不会引入新的作用域的,也就是说这些语句内定义的变量,外部也可以访问:
>>> if True:
...  msg = 'I am from Runoob'
... 
>>> msg
'I am from Runoob'
>>> 

2.1、全局变量和局部变量

  • 定义在函数内部的变量拥有一个局部作用域,定义在函数外的拥有全局作用域。
  • 局部变量只能在其被声明的函数内部访问,而全局变量可以在整个程序范围内访问。调用函数时,所有在函数内声明的变量名称都将被加入到作用域中。

2.2、global 和 nonlocal关键字

  • 当内部作用域想修改外部作用域的变量时,就需要用到 global 和 nonlocal 关键字:
num = 1
def fun1():
    global num  # 需要使用 global 关键字声明
    print(num) 
    num = 123
    print(num)
fun1()
print(num)

'''
输出结果:
1
123
123
'''
# 如果要修改嵌套作用域(enclosing 作用域,外层非全局作用域)中的变量则需要 nonlocal 关键字了
def outer():
    num = 10
    def inner():
        nonlocal num   # nonlocal关键字声明
        num = 100
        print(num)
    inner()
    print(num)
outer()


'''
输出结果:
100
100
'''