简明Python语法

1.简介

这个帖子的主要对Python的一些语法进行了总结,主要包括的是Python语言与其他编程语言所不同的部分,内容大多来源于网络。

2.Python编程基础

2.1 id()

id()函数可返回对象的内存地址,python中会为每个对象分配内存,哪怕他们的值完全相等。id(object)函数是返回对象object在其生命周期内位于内存中的地址,id函数的参数类型是一个对象。

2.2 输入输出函数

2.2.1 Input()

输入函数格式为input([prompt]),prompt是可选的,是提示信息。返回值是从键盘输入的一行文本,默认为字符串类型。不过也可以用类型转换函数进行显式的转换。

a = input("请输入字符串:")
b = int(input(("请输入一个整数:")))
c = float(input("请输入一个数值:"))

2.2.2 eval()

用于去掉字符串最外侧的引号,并按照Python语句方式执行去掉引号后的字符串,eval()函数经常和input()函数一起使用。
具体语法为:

eval(expression[, globals[, locals]])
  • expression – 表达式。

  • globals – 变量作用域,全局命名空间,如果被提供,则必须是一个字典对象。

  • locals – 变量作用域,局部命名空间,如果被提供,可以是任何映射对象。

使用实例

s='3.14+3'
print(s,type(s))
x=eval(s) # 使用eval函数去掉s这个字符串中左右的引号 ,执行加法运算
print(x,type(x))

hello='北京欢迎你'
print(hello)
print(eval('hello')) # 输出了"北京欢迎你"
print(eval('北京欢迎你')) # NameError: name '北京欢迎你' is not defined

输出结果

3.14+3 <class 'str'>
6.140000000000001 <class 'float'>
北京欢迎你
北京欢迎你
NameError: name '北京欢迎你' is not defined

特别注意的是最后一行运行会报错。

2.2.3print()

输出函数,其具体语法为:

print(*objects, sep=' ', end='\n', file=sys.stdout, flush=False)

输出函数可以支持输出多个对象,输出拼接的字符串和输出到文本文件中,还可以输出ASCII码和Unicode码对应的文字。

a=100
b=50
print(a,b,'要么出众,要么出局!!!')

#输出ASCII和Unicode对应字符
print(8)
print(chr(56))
print('[')
print(chr(91))

print(ord('北'))
print(ord('京'))
print(chr(21271),chr(20140))

# 输出到文件
fp=open('note.txt','w') # 打开文件 w-->write
print('北京欢迎你',file=fp) # 将"北京欢迎你" 输出(写入)到note.txt文件中
fp.close() # 关闭文件

如果需要输出一定位数的浮点型数字,可以用函数round()

2.4 基础运算符

赋值运算符包含-=、+=、/=、//=
运算符优先级如下
运算符优先级
与C++不同的是,多了个整除运算符“//”,其返回值是整数,除法运算符“/”的返回值为浮点型。
此外~表示按位取反。

2.5 程序流程控制

Python在程序流程控制这里有if判断语句、for和while循环语句,其中如果为空语句,则需要写pass。
在python 3.10加入了switch语句,即match…case,其具体语法为:

match expression:
    case pattern1:
        # 处理pattern1的逻辑
    case pattern2 if condition:
        # 处理pattern2并且满足condition的逻辑
    case _:
        # 处理其他情况的逻辑

3.关键字

3.1 with

Python 中的 with 语句用于异常处理,封装了 try…except…finally 编码范式,提高了易用性。
例如

file = open('./test_runoob.txt', 'w')
file.write('hello world !')
file.close()

以上代码如果在调用 write 的过程中,出现了异常,则 close 方法将无法被执行,因此资源就会一直被该程序占用而无法被释放。 接下来我们呢可以使用 try…except…finally 来改进代码:

file = open('./test_runoob.txt', 'w')
try:
    file.write('hello world')
finally:
    file.close()

以上代码我们对可能发生异常的代码处进行 try 捕获,发生异常时执行 except 代码块,finally 代码块是无论什么情况都会执行,所以文件会被关闭,不会因为执行异常而占用资源。

with open('./test_runoob.txt', 'w') as file:
    file.write('hello world !')

使用 with 关键字系统会自动调用 f.close() 方法, with 的作用等效于 try/finally 语句是一样的。

4.组合数据类型

4.1 可变与不可变类型

一些组合的数据类型只能存储可变数据,一些只能存储不可变数据。

不不可变类型可变类型
NumberList
StringDict
TupleSet

4.2 序列切片操作

可以对序列进行切片操作,不同于matlab的是,其最后一个参数表示步长。

序列[start:end:step]#参数可以省略,如果step为负值的话,则倒序计数

4.3 序列和索引操作

操作符/函数描述说明
x+y两个序列拼接
x in s如果x是s的元素,结果为True,否则结果为False
x not in s如果x不是s的元素,结果为True,否则结果为False
len(s)序列s中元素的个数(即序列的长度)
max(s)序列s中元素的最大值
min(s)序列s中元素的最小值
s.index(x)序列s中第一次出现元素x的位置
s.count(x)序列s中出现x的总次数

4.4 list

Python中内置的可变序列,在Python中使用[]定义列表,元素与元素之间使用英文的逗号分隔,列表中的元素可以是任意的数据类型。

  1. 列表的创建
  • 使用[]直接创建列表
列表名=[element1,element2,......elementN]

# 直接使用[]创建列表
lst=['hello','world',98,100.5]
print(lst)
  • 使用内置函数list()创建列表
列表名=list(序列)

# 可以使用内置的函数list()创建列表
lst2=list('helloworld')
lst3=list(range(1,10,2)) # 从1开始到10结束,步长为2,不包含10
  1. 列表的遍历
    列表的遍历有如下三种方法
# 使用遍历循环for遍历列表元素
for item in lst:
    print(item)

# 使用for循环,range()函数,len()函数,根据索引进行遍历
for i in range(0,len(lst)):
    print(i,'-->',lst[i])

# 第三种遍历方式 enumearte()函数
for index,item in enumerate(lst):
    print(index,item) #index是序号,不是索引
# 手动修改序号的起始值
for index,item in enumerate(lst,start=1): #
    print(index,item)

for index, item in enumerate(lst,1):  #  省略start不写,直接写起始值
    print(index, item)
  1. 列表相关操作
列表的方法描述说明
del lst删除列表
lst.append(x)在列表lst最后增加一个元素
lst.insert(index,x)在列表中第index位置增加一个元素
lst.clear()清除列表lst中所有元素
lst.pop(index)将列表lst中第index位置的元素取出,并从列表中将其删除
lst.remove(x)将列表lst中出现的第一个元素x删除
lst.reverse(x)将列表lst中的元素反转
lst.copy()拷贝列表lst中的所有元素,生成一个新的列表
  1. 列表排序
  • 列表对象的sort方法
    该方法并不会生成新的列表对象
lst.sort(key=None,reverse=False)
# key表示排序规则
# reverse表示排序方式
  • 内置函数sorted()
    该方法会生成一个新的列表对象
sorted(iterable,key=None,reverse=False)
# iterable表示排序对象
  1. 列表生成式
    列表生成式是一种基于其他iterable(如集合、元组、其他列表等)创建列表的方法。它还可以用更简单、更吸引人的语法表示for和if循环。不过,列表生成式比for循环要快得多。
    其语法为:
lst=[expression for item in range if condition]

实例:

lst=[item for item in range(1,11)]
print(lst)

lst=[item*item for item in range(1,11)]
print(lst)

lst=[random.randint(1,100) for _ in range(10)]
print(lst)

# 从列表中选择符合条件的元素组成新的列表
lst=[i for i in range(10) if i%2==0]
print(lst)

输出结果为

[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
[82, 24, 7, 20, 45, 2, 44, 44, 76, 56]
[0, 2, 4, 6, 8]

4.5 enumerate()

函数用于将一个可遍历的数据对象(如列表、元组或字符串)组合为一个索引序列,同时列出数据和数据下标,一般用在 for 循环当中。语法如下

enumerate(sequence, [start=0])

# sequence -- 一个序列、迭代器或其他支持迭代对象。
# start -- 下标起始位置的值。
# 返回 enumerate(枚举) 对象。

4.6 元组

元组是Python中内置的不可变序列,在Python中使用()定义元组,元素与元素之间使用英文的逗号分隔元组中只有一个元素的时候,逗号也不能省略。

  1. 元组的创建与删除
  • 使用()直接创建元组
    语法如下:
元组名=(element1,element2,......elementN)

 # 使用小括号创建元组
t=('hello',[10,20,30],'python','world')
print(t)

输出结果为

('hello', [10, 20, 30], 'python', 'world')
  • 使用内置函数tuple()创建元组
元组名=tuple(序列)

# 使用内置函数tuple()创建元组
t=tuple('helloworld')
print(t)

t=tuple([10,20,30,40])
print(t)
  • 元组的删除
    元组的删除可以使用关键字del
del 元组名
  1. 元组的遍历与访问
    元组的遍历方式和访问的方式与列表相同,这里不在叙述。

  2. 元组生成式

  • 元组生成式的结果是一个生成器对象,需要转换成元组或列表才能查看到元素内容
t=(i for i in range(1,4))
print(t)
t=tuple(t)
print(t)

输出结果如下

<generator object <genexpr> at 0x00000287BF9A9820>
(1, 2, 3)

可以看到第一个是生成器对象的地址,无法打印出我们所需要的1,2,3。而在用tuple()函数处理过后,我们可以输出元组,此时为元组类型。

如果不将其转化为元组或者列表,我们可以用__next__()方法将其中的元素取出来

print(t.__next__())
print(t.__next__())
print(t.__next__())

输出结果为

1
2
3

但是就如同上面一样,所有的元素被遍历过一遍后,都已经被取出,这个生成器对象中已经不含元素。所以,我们再用tuple()函数将其转化为元组,得到的是一个空的元组。

  1. 元组和列表的对比
元组列表
不可变序列可变序列
无法实现添加、删除和修改元素等操作append()、insert()、remove()、pop()等方法实现添加和删除列表元素
支持切片访问元素,不支持修改操作支持切片访问和修改列表中的元素
访问和处理速度快访问和处理速度慢
可以作为字典的键不能作为字典的键

4.7 字典dictionary

字典是一种可变的数据类型,根据一个信息查找另一个信息的方式构成了“键值对”,它表示索引用的键和对应的值构成的成对关系。这一点有点类似于map。
字典的一个特点是键key是不可以重复的,而值value是可以重复的,学过数据库的人应该不难理解,key就像是主键一样。key是唯一标识,不能有重复的,且不允许为空。
特别注意的是,字典中的键是不可变序列,故而列表是不可以作为字典中的键,而元组、字符串等都可以。
字典示意

  1. 字典的创建与删除
    字典的创建有两种方法
  • 用{}创建
    语法如下
d={key1:value1,key2:value2......}

d={10:'cat',20:'dog',30:'pet',20:'zoo'}# 当key一样的时候,value会自动覆盖
  • 使用内置函数dict()创建字典
    dict()的语法为
dict(key1=value1,key2=value2......)

# 使用参数创建字典
d=dict(cat=10,dog=20) # 左侧cat是key ,右侧的是value
print(d)
  • 映射函数zip(lst1,lst2)

zip() 函数用于将可迭代的对象作为参数,将对象中对应的元素打包成一个个元组,然后返回由这些元组组成的列表。

如果各个迭代器的元素个数不一致,则返回列表长度与最短的对象相同,利用 * 号操作符,可以将元组解压为列表。

>>> a = [1,2,3]
>>> b = [4,5,6]
>>> c = [4,5,6,7,8]
>>> zipped = zip(a,b)     # 返回一个对象
>>> zipped
<zip object at 0x103abc288>
>>> list(zipped)  # list() 转换为列表
[(1, 4), (2, 5), (3, 6)]
>>> list(zip(a,c))              # 元素个数与最短的列表一致
[(1, 4), (2, 5), (3, 6)]

>>> a1, a2 = zip(*zip(a,b))          # 与 zip 相反,zip(*) 可理解为解压,返回二维矩阵式
>>> list(a1)
[1, 2, 3]
>>> list(a2)
[4, 5, 6]
>>>
  1. 字典也是序列,支持序列的操作
# 字典属于序列
print('max:',max(d))# 输出的结果是最大的键对应的值
print('min:',min(d))
print('len:',len(d))
# 字典的删除
del d
#print(d)
  1. 字典的访问与遍历
  • 字典的访问
d[key]或d.get(key)

两者不同的是d[key]在键不存在时,会报错。而d.get(key)在键不存在的时候,返回值为None或者返回默认值(如果给了的话)。

print(d.get('java')) # None
print(d.get('java','不存在'))

其输出结果为

None
不存在
  • 字典的遍历
    1) 遍历出key与value的元组
# 字典的遍历
for item in d.items():
    print(item) # key=value组成的一个元素

输出结果为:

('hello', 10)
('world', 20)
('python', 30)

2) 遍历出key和value

# 在使用for循环遍历时,分别获取key,value
for key,value in d.items():
    print(key,'--->',value)

输出结果为:

hello ---> 10
world ---> 20
python ---> 30
  1. 字典的操作方法
字典的方法描述说明
d.keys()获取所有的key数据
d.values()获取所有的value数据
d.pop(key,default)key存在获取相应的value,同时删除key-value对,否则获取默认值
d.popitem()随机从字典中取出一个key-value对,结果为元组类型,同时将该key-value从字典中删除
d.clear()清空字典中所有的key-value对
  1. 字典生成式
    字典生成式的语法为
d={  key:value for item in range  }
或
d={key:value for key,value in zip(lst1,lst2)}

示例

import random
d={item :random.randint(1,100) for item in range(4)}
print(d)

# 创建两个列表
lst=[1001,1002,1003]
lst2=['a','b','c']
d={key:value for key,value in zip(lst,lst2)}
print(d)

其输出结果为:

{0: 97, 1: 25, 2: 47, 3: 24}
{1001: 'a', 1002: 'b', 1003: 'c'}

4.8 集合(set)

Python中的集合与数学中集合的概念一致,它是一个无序不重复元素序列,集合中只能存储不可变数据类型。在Python中集合使用{}定义,与列表、字典一样,都是Python中的可变数据类型,即其中内容是可以改变的。
特点:集合中的元素不会重复,并且可以进行交集、并集、差集等常见的集合操作。

  1. 集合的创建与删除
    集合的创建有两种方法
  • 用{}创建
    语法如下
s={element1,element2,......elementN}

s={10,20,30,40}
print(s)
# 集合中只能存储不可变数据类型
#s={[10,20],[30,40]} #TypeError: unhashable type: 'list'

注意s={},创建结果为字典类型。

  • 使用内置函数set()创建集合
    set()的语法为
s=set(可迭代对象)

s=set('helloworld')
print(s)
#删除使用del
  1. 集合也是序列,支持序列的操作,但是集合是无序的,不可以遍历。
  2. 集合的遍历和集合生成式
# 集合的遍历操作
for item in s:
    print(item)

# 使用enumerate()函数
for index,item in enumerate(s):
    print(index,'-->',item)

# 集合的生成式
s={i for i in range(1,10)}
print(s)

s={i for i in range(1,10) if i%2==1}
print(s)
  1. 集合的操作方法
集合的方法描述说明
A&B交集
A|B并集
A-B差集
A^B补集
s.add(x)如果x不在集合s中,则将x添加到集合s
s.remove(x)如果x在集合中,将其删除,如果不在集合中,程序报错
s.clear()清除集合中所有元素

这里仅仅介绍了部分常用操作,更多细节可以查看菜鸟教程里面关于集合的描述。

4.9 组合数据类型对比总结

数据类型序列类型元素是否可重复是否有序
列表list可变序列可重复有序
元组tuple不可变序列可重复有序
字典dict可变序列Key不可重复,Value可重复无序
集合set可变序列不可重复无序

5.字符串

5.1 字符串的操作方法

方法名描述说明
str.lower()将str字符串全部转成小写字母,结果为一个新的字符串
str.upper()将str字符串全部转成大写字母,结果为一个新的字符串
str.split(sep=None)把str按照指定的分隔符sep进行分隔,结果为列表类型
str.count(sub)结果为sub这个字符串在str中出现的次数
str.find(sub)查询sub这个字符串在str中是否存在,如果不存在结果为-1,如果存在,结果为sub首次出现的索引
str.index(sub)功能与find()相同,区别在于要查询的子串sub不存在时,程序报错
str.startswith(s)查询字符串str是否以子串s开头
str.endswith(s)查询字符串str是否以子串s结尾
str.replace(old,news)使用news替换字符串s中所有的old字符串,结果是一个新的字符串
str.center(width,fillchar)字符串str在指定的宽度范围内居中,可以使用fillchar进行填充
str.join(iter)在iter中的每个元素的后面都增加一个新的字符串str
str.strip(chars)从字符串中去掉左侧和右侧chars中列出的字符串
str.lstrip(chars)从字符串中去掉左侧chars中列出的字符串
str.rstrip(chars)从字符串中去掉右侧chars中列出的字符串

5.2 字符串的格式化方法

字符串的格式化有三种方法

  1. 占位符
    用占位符去格式化字符串,其中%s表示字符串格式,%d 表示十进制整数格式,%f 表示浮点数格式
  2. f-string
    这是一种引入的格式化字符串的方式,用{}标明被替换的字符
  3. str.format()方法
    format 函数可以接受不限个参数,位置可以不按顺序。

三种方法的具体实例为

#(1)使用占位符进行格式化
name='马冬梅'
age=18
score=98.5
print('姓名:%s,年龄:%d,成绩:%f' % (name,age ,score))
print('姓名:%s,年龄:%d,成绩:%.1f' % (name,age ,score))

# (2)f-string
print(f'姓名:{name},年龄:{age},成绩:{score}')

# (3)使用字符串的format方法
print('姓名:{0},年龄:{1},成绩:{2}'.format(name,age,score))
print('姓名:{2},年龄:{0},成绩:{1}'.format(age,score,name))
"{} {}".format("hello", "world")    # 不设置指定位置,按默认顺序 
"{0} {1}".format("hello", "world")  # 设置指定位置
"{1} {0} {1}".format("hello", "world")  # 设置指定位置

5.3 详细的format格式化方法

参数介绍

  • 示例
s='helloworld'
print('{0:*<20}'.format(s)) # 字符串的显示宽度为20,左对齐,空白部分使用* 号填充
print('{0:*>20}'.format(s))
print('{0:*^20}'.format(s))

# 居中对齐
print(s.center(20,'*'))

# 千位分隔符(只适用于整数和浮点数)
print('{0:,}'.format(987654321))
print('{0:,}'.format(987654321.7865))

# 浮点数小数部分的精度
print('{0:.2f}'.format(3.1419826))
# 字符串类型 .表示是最大的显示长度
print('{0:.5}'.format('helloworld')) # hello

# 整数类型
a=425
print('二进制:{0:b},十进制:{0:d},八进制:{0:o},十六进制:{0:x},十六进制:{0:X}'.format(a))

# 浮点数类型
b=3.1415926
print('{0:.2f},{0:.2E},{0:.2e},{0:.2%}'.format(b) )

5.4 字符串分割

split() 方法语法:

str.split(str="", num=string.count(str)).

# str -- 分隔符,默认为所有的空字符,包括空格、换行(\n)、制表符(\t)等。
# num -- 分割次数。默认为 -1, 即分隔所有。

6.函数

6.1 定义方法

  • 函数代码块以 def 关键词开头,后接函数标识符名称和圆括号()。
  • 任何传入参数和自变量必须放在圆括号中间。圆括号之间可以用于定义参数。
  • 函数的第一行语句可以选择性地使用文档字符串—用于存放函数说明。
  • 函数内容以冒号起始,并且缩进。
  • return [表达式] 结束函数,选择性地返回一个值给调用方。不带表达式的return相当于返回 None。
# 定义格式
def 函数名称(参数列表):
    函数体
     [return返回值列表]
# 举例如下

def get_sum(num): #num叫形式参数
    s=0
    for i in range(1,num+1):
        s+=i
    print(f'1到{num}之间的累加和为:{s}')

# 函数的调用
get_sum(10) # 1-10之间的累加和     10是实际参数值
get_sum(100) # 1-100之间的累加和   100是实际参数值
get_sum(1000) # 1-1000之间的累加和  1000是实际参数值

6.2 参数传递

  • 对于不可变类型如数字、元组等,函数并不改变数据。

  • 对于可变类型如列表、字典,函数中若修改了该参数,原数据也会发生变化,有点类似于是C++中的传引用。
    python 中一切都是对象,严格意义我们不能说值传递还是引用传递,我们应该说传不可变对象和传可变对象。

6.2.1 四种传参方式

  1. 位置参数
    位置参数必须以正确的顺序传入函数。调用时的数量必须和声明时的一样,这是一种最常见的参数传递方式。
 
def happy_birthday(name,age):
    print('祝'+name+'生日快乐')
    print(str(age)+'岁生日快乐')

happy_birthday('小明',18)# 参数位置不能反,也不能缺失
  1. 关键字参数

关键字参数和函数调用关系紧密,函数调用使用关键字参数来确定传入的参数值。
使用关键字参数允许函数调用时参数的顺序与声明时不一致,因为 Python 解释器能够用参数名匹配参数值。
但是要注意的是,若同时有位置参数和关键字参数的话,必须关键字参数在后,位置参数在前传递,否则会报错。

#可写函数说明
def printinfo( name, age ):
   "打印任何传入的字符串"
   print "Name: ", name
   print "Age ", age
   return
 
#调用printinfo函数
printinfo( age=50, name="miki" )
  1. 默认值参数
    默认参数的值如果没有传入,则被认为是默认值,类似于是缺省值的意思。
def printinfo( name, age = 35 ):
   "打印任何传入的字符串"
   print "Name: ", name
   print "Age ", age
   return
 
#调用printinfo函数
printinfo( age=50, name="miki" )
printinfo( name="miki" )
  1. 可变参数
    分为个数可变的位置参数和个数可变的关键字参数两种,其中个数可变的位置参数是在参数前加一颗星(*para),para形式参数的名称,函数调用时可接收任意个数的实际参数,并放到一个元组中。**个数可变的关键字参数是在参数前加两颗星(para),在函数调用时可接收任意多个 “参数=值”形式的参数,并放到一个字典中。
# 个数可变的位置参数
def fun(*para):
    print(type(para))
    for item in para:
        print(item)

# 调用
fun(10,20,30,40)
fun(10)
fun(20,30)
fun([11,22,33,44]) # 实际上传递的是一个参数,
 # 在调用时,参数前加一颗星,分将列表进行解包
fun(*[11,22,33,44])

# 个数可变的关键字参数
def fun2(**kwpara):
    print(type(kwpara))
    for key,value in kwpara.items():
        print(key,'-----',value)

# 调用
fun2(name='小明',age=18,height=170) # 关键字参数

d={'name':'小明','age':18,'height':170}
#fun2(d) # TypeError: fun2() takes 0 positional arguments but 1 was given

fun2(**d) #系列解包操作

6.3 返回值

return可以出现在函数中的任意一个位置,用于结束函数。返回值可以是一个值,或多个值,如果返回的值是多个,结果是一个元组类型。

6.4 变量作用域

在函数内部用global可以声明全局变量。

6.5 lambda表达式

这种函数只能使用一次,一般是在函数的函数体只有一句代码且只有一个返回值时,可以使用匿名函数来简化。

# 语法格式
result=lambda 参数列表:表达式


def calc(a,b):
    return a+b

print(calc(10,20))

# 匿名函数
s=lambda a,b:a+b # s表示就是一个匿名函数
print(type(s)) # <class 'function'>
# 调用匿名函数
print(s(10,20))
print('-'*30)
# 列表的正常取值操作
lst=[10,20,30,40,50]
for i in range(len(lst)):
    print(lst[i])
print('-'*30)

for i in range(len(lst)):
    result=lambda x:x[i] # 根据索引取值 ,result是的类型是function  ,x是形式参数
    print(result(lst)) # lst是实际参数


#
student_scores=[
    {'name':'陈梅梅','score':98},
    {'name': '王一一', 'score': 95},
    {'name': '张天乐', 'score': 100},
    {'name': '白雪儿', 'score': 65}
]
# 对列表进行排序, 排序的规则 是字典只的成绩
student_scores.sort(key=lambda x:x.get('score'),reverse=True) # 降序
print(student_scores)

6.6 常用函数

6.6.1 类型转换函数

函数名称描述说明
bool(obj)获取指定对象obj的布尔值
str(obj)将指定对象obj转成字符串类型
int(x)将x转成int类型
float(x)将x转成float类型
list(sequence)将序列转成列表类型
tuple(sequence)将序列转成元组类型
set(sequence)将序列转成集合类型

6.6.2 数学计算函数

函数名称描述说明
abs(x)获取x的绝对值
divmod(x,y)获取x与y的商和余数
max(sequence)获取sequence的最大值
min(sequence)获取sequence的最小值
sum(iter)对可迭代对象进行求和运算
pow(x,y)获取x的y次幂
round(x,d)对x进行保留d位小数,结果四舍五入

6.6.3可迭代对象操作函数

函数名称描述说明
sorted(iter)对可迭代对象进行排序
reversed(sequence)反转序列生成新的迭代器对象
zip(iter1,iter2)将iter1与iter2打包成元组并返回一个可迭代的zip对象
enumerate(iter)根据iter对象创建一个enumerate对象
all(iter)判断可迭代对象iter中所有元素的布尔值是否都为True
any(iter)判断可迭代对象iter中所有元素的布尔值是否都为False
next(iter)获取迭代器的下一个元素
filter(function,iter)通过指定条件过滤序列并返回一个迭代器对象
map(function,iter)通过函数function对可迭代对象iter的操作返回一个迭代器对象

7.面向对象的编程

7.1 类(class)和实例(instance)

在python中一切皆对象。类就是一个模板,对象则是这个模板具体的实例。
一个类主要有如下几个部分构成

  • 类属性:直接定义在类中,方法之外的变量。
  • 实例属性:定义在_init_() 方法中,使用self打点的变量。这也说明了self是实例。
  • 实例方法:定义在类中的函数,自带参数self。
  • 静态方法:使用装饰器@staticmethod修饰的方法。
  • 类方法:使用装饰器@classmethon修饰的方法。

简而言之,self对应的是实例方法和实例属性。

7.2 类的创建及调用

class Student:
    # 类属性:定义在类中,方法外的变量
    school = "xx大学"

    # 初始化方法
    def __init__(self,xm,age):  # name和age是该方法的变量,为局部变量,其作用域为该方法
        self.name=xm  # =左侧为实例属性,其定义在实例方法中。
        self.age=age  # 允许实例属性和参数同名

    # 定义在类中的函数称为方法,自带参数self
    def show(self):
        print(f'我叫:{self.name},今年:{self.age}岁了')

    # 静态方法
    @staticmethod
    def good():
        print('这是一个静态方法')  # 不能调用实例属性和实例方法

    # 类方法
    @classmethod
    def bad(cls):  # 自带参数cls,它是class的简写
        print('这是一个类方法')  # 不能调用实例属性和实例方法


# 创建类的对象
stu=Student('zhangyang',18)  # 不传入self
# 实例属性调用,使用对象名打点调用
print(stu.name,stu.age)
# 类属性调用,类名打点调用
print(Student.school)

# 实例方法,使用对象名打点调用
stu.show()
# 类方法调用
Student.bad()
# 静态方法调用
Student.good() 

  • 其中还可以定义私有属性,用两个下划线开头,声明该属性为私有,不能在类的外部被使用或直接访问。在类内部的方法中使用时 self.__private_attrs。
    类属性和实例属性

7.2.1 动态绑定属性和方法

python中可以动态的给对象绑定属性和方法,举例如下。

class Student:
    # 类属性:定义在类中,方法外的变量
    school = "xx大学"

    # 初始化方法
    def __init__(self,xm,age):  # name和age是该方法的变量,为局部变量,其作用域为该方法
        self.name=xm  # =左侧为实例属性,其定义在实例方法中。
        self.age=age  # 允许实例属性和参数同名

    # 定义在类中的函数称为方法,自带参数self
    def show(self):
        print(f'我叫:{self.name},今年:{self.age}岁了')

stu1 = Student('Alice', 17)
# 动态绑定一个属性
stu1.gender = '女'
print(stu1.gender)


# 绑定一个方法
def introduce():
    print('普通该函数被动态绑定成了stu1对象的方法')
    
    
stu1.fun = introduce  # 将该函数赋值过去,即绑定完毕方法,但是不要有括号
#调用
stu1.fun()

7.2.2 权限控制

  • 单下划线开头:表示被保护的成员protected,可以允许类本身和子类访问。
  • 双下划线开头:表示private私有成员,仅允许定义该属性或者方法的类进行访问
  • 首位双下划线:表示特殊方法

访问方式

stu._name # 访问受保护的属性
stu._fun1() # 子类和本身可以直接访问
stu._Student__Age #访问私有的属性
stu._Studnet__fun2() # 访问私有的方法


7.2.3 属性设置

上面的对于私有方法和属性的调用是极其不推荐的,可以用property函数或者函数装饰器@property来设置访问。

7.2.3.1 property() 函数
  • 语法:property(fget=None, fset=None, fdel=None, doc=None) -> property attribute

  • 说明:
    fget 是获取属性值的方法。
    fset 是设置属性值的方法。
    fdel 是删除属性值的方法。
    doc 是属性描述信息。如果省略,会把 fget 方法的 docstring 拿来用(如果有的话)

  • 示例代码:

class Student:
    def __init__(self):
        self._age = None

    def get_age(self):
        print('获取属性时执行的代码')
        return self._age

    def set_age(self, age):
        print('设置属性时执行的代码')
        self._age = age

    def del_age(self):
        print('删除属性时执行的代码')
        del self._age

    age = property(get_age, set_age, del_age, '学生年龄')


student = Student()
# 注意要用 类名.属性.__doc__ 的形式查看属性的文档字符串
print('查看属性的文档字符串:' + Student.age.__doc__)
"""
查看属性的文档字符串:学生年龄
"""

# 设置属性
student.age = 18
"""
设置属性时执行的代码
"""

# 获取属性
print('学生年龄为:' + str(student.age))
"""
获取属性时执行的代码
学生年龄为:18
"""

# 删除属性
del student.age
"""
删除属性时执行的代码
"""

7.2.3.2 @property 装饰器

@property 语法糖提供了比 property() 函数更简洁直观的写法。

  • @property 装饰的方法是获取属性值的方法,被装饰方法的名字会被用做 属性名。
  • @属性名.setter 装饰的方法是设置属性值的方法。
  • @属性名.deleter 装饰的方法是删除属性值的方法。

以下示例代码与使用 property() 函数版本的代码等价:

class Student:
    def __init__(self):
        self._age = None

    @property
    def age(self):
        print('获取属性时执行的代码')
        return self._age

    @age.setter
    def age(self, age):
        print('设置属性时执行的代码')
        self._age = age

    @age.deleter
    def age(self):
        print('删除属性时执行的代码')
        del self._age


student = Student()

# 设置属性
student.age = 18
"""
设置属性时执行的代码
"""

# 获取属性
print('学生年龄为:' + str(student.age))
"""
获取属性时执行的代码
学生年龄为:18
"""

# 删除属性
del student.age
"""
删除属性时执行的代码
"""


这段内容转载自博客Python 中 property() 函数及 @property 装饰器的使用

所以说,利用上述方法可以用于读取、修改和删除私有属性。

7.3 继承

在python中一个子类可以继承N多个父类,且一个父类也可以拥有多个子类。如果说一个类没有继承任何类,这个类默认继承了object

  • 语法结构
class 类名(父类1,父类2......,父类N)
  • 示例代码
#类定义
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()

7.3.1 多继承

python允许一个子类同时继承多个父类。

  • 语法结构
class DerivedClassName(Base1, Base2, Base3):
       pass

需要注意圆括号中父类的顺序,若是父类中有相同的方法名,而在子类使用时未指定,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()   #方法名同,默认调用的是在括号中参数位置排前父类的方法

7.3.2 方法重写

子类继承了父类就拥有了父类中公有成员和受保护的成员。但是父类的方法如果不能够完全适合子类的需要的时候,子类就可以重写父类的方法。
子类重写父类的方法时候,要求方法名称相同,在子类重写后仍然可以通过super().xxx()调用父类的方法。

class Parent:        # 定义父类
   def myMethod(self):
      print ('调用父类方法')
 
class Child(Parent): # 定义子类
   def myMethod(self):
      print ('调用子类方法')
 
c = Child()          # 子类实例
c.myMethod()         # 子类调用重写方法
super(Child,c).myMethod() #用子类对象调用父类已被覆盖的方法

7.3.3 多态

python根据变量所引用对象的数据类型,动态的决定调用哪个对象中的方法。在python中,并不关心对象的数据类型和继承关系,只关心对象的方法。只要不同类中有同名方法,就可以实现多态。

"""
面向对象 - 多态
"""
class Animal:
    name = "Animal"
    age = 0

    def make_sound(self):
        print("动物发音")


class Dog(Animal):
    def make_sound(self):
        print("汪汪")


class Cat(Animal):
    def make_sound(self):
        print("喵喵")


def fun(obj):
    obj.make_sound()


animal = Animal()
dog = Dog()
cat = Cat()

fun(animal)
fun(dog)
fun(cat)

7.4 object类

object是所有类的父类。

object类中的特殊方法描述说明
_new()_由系统调用,用于创建对象
_init()_创建对象的时候手动调用,用于初始化
_str()_对象的描述,返回值为str,默认输出对象的内存地址,print(对象)自动调用

dir()函数可以用于查看该对象属性和方法。

7.5 类的浅拷贝和深拷贝

  • 变量的赋值:只是形成两个变量,实际上还是指向同一个对象
class CPU:
    pass

class Disk:
    pass

class Computer:
    def __init__(self,cpu,disk):
        self.cpu = cpu 
        self.disk = disk

# 声明一个cpu1变量并将CPU实例对象赋予它
cpu1 = CPU()
print(cpu1,id(cpu1))
# 将cpu1赋予cpu2
cpu2 = cpu1
print(cpu2,id(cpu2))
<__main__.CPU object at 0x00000182116B6820> 1658149627936
<__main__.CPU object at 0x00000182116B6820> 1658149627936

赋值对应的内存地址是相同的

  • 浅拷贝:拷贝时,对象包含的子对象内容不拷贝,因此源对象和拷贝对象引用的是同一个对象
import copy
disk = Disk()
comp1 = Computer(cpu1, disk)
print(comp1,id(comp1),id(comp1.cpu),id(comp1.disk))
comp2 = copy.copy(comp1)
print(comp2,id(comp2),id(comp2.cpu),id(comp2.disk))
<__main__.Computer object at 0x000001FAFD3986A0> 2177501857440 2177503160352 2175472490912
<__main__.Computer object at 0x000001FAFD4AC460> 2177502987360 2177503160352 2175472490912

变量comp1和comp2分别指向两个不同的对象实例,是对原有的对象实例的一个拷贝,而在对象中的子对象cpu和disk指向同一个对象实例,因此为浅拷贝。

  • 深拷贝:使用copy模块的deepcopy函数。递归拷贝对象中包含的子对象,源对象和拷贝对象所有的子对象也不相同
import copy
disk = Disk()
comp1 = Computer(cpu1, disk)
print(comp1,id(comp1),id(comp1.cpu),id(comp1.disk))
comp3 = copy.deepcopy(comp1)
print(comp3,id(comp3),id(comp3.cpu),id(comp3.disk))

```bash
<__main__.Computer object at 0x000001FC093586A0> 2181997889184 2181999192096 2182115809696
<__main__.Computer object at 0x000001FC0946C490> 2181999019152 2182117519712 2182117519904

id均不相同,即为深拷贝,深拷贝改变对象的值会影响源的值,而浅拷贝不会。

参考资料:
[1] python子木https://www.bilibili.com/video/BV1wD4y1o7ASp=8&vd_source=3c45104f01803b9a022fe28bbd87a603
[2] 菜鸟教程https://www.runoob.com/python/python-tutorial.html

  • 15
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Serein朔一

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值