Python语法入门

 Python语言是比C和C++语言更高级的语言,Python不像C/C++那样,Python有系统自带的大整数模式,而且Python没有那么多的头文件,其中的一些模块使用起来比C/C++方便,本篇将会概述Python的一些入门,包括一些基本的块、数据类型、函数的使用等。

目录

一.输入和输出

1.字符串的读入

2.字符串定义时读入

3.整型的读入

4.浮点数的读入

 二.模块的应用

1.math模块

2.random模块

3.string模块

三.数据类型

1.列表

(1).声明一个列表,并使用下标访问元素。

(2).访问第一个元素

(3).列表的查询

(4).列表的添加

(5).列表的修改

(6).列表的切片

(7).列表的排序

2.元组(Tuple)

(1)元组的截取 

(2).元组的一些函数

(3).元组的拆包和装包

3.字典(Dict)

(1).定义一个空字典

(2).初始化

(3).定义一个字典,之后添加元素

(4).修改字典元素

(5).字典相关函数

(6).字典的删除

四、六种最基础的数据类型

1.type

2.数字类型

2.1.int类型(py中不用定义类型,可以直接用)

2.2.py浮点型只有float

2.3.complex复数类型

3.运算符

4.蛇形取名法

5.大驼峰小驼峰取名法

五、字符串string

1.python没有char类型

2.字符串的一些操作

3.字符串的切片

4.变量的赋值,多变量赋值

六、基本序列

1.列表list补充

2.集合

3.字典

七、强制转换与输入输出处理

1.字符串和整型数字

2.list和set

3.基本输入输出处理

4.判断语句的用法

4.1 单分支if语句

4.2双分支if-else语句

4.3多分支if-elif语句

5.比较运算符

6.循环语句

6.1 for语句和while语句

6.2并行遍历

八、序列精讲

1.索引  list[i]

2.切片

3.拼接

4.乘法

5.clear()操作

6.浅拷贝

7.深拷贝

8.count(x)

9.extend

10.index(l,r,x)

11.pop()

12.remove(x)

13.reverse

14.sort

15.sorted

16字符串转换list

17.set()

18.dict():字典

19.len()

20.列表可以进行乘法

21.列表的迭代

22.max():最大值

23.min():最小值

24.range(start,end,step)

25.dict 字典

26.字符串

九、函数

基础函数⽤法

1.基本格式

2.函数参数

3.函数的说明⽂档

4.函数的返回值

5.变量作⽤域

6.参数拓展

十、高级函数的用法

1.Python函数是可以嵌套。

2.lambda表达式

3.闭包

4.装饰器

5.⽣成器


一.输入和输出

1.字符串的读入

a=input()
print(a)

2.字符串定义时读入

a='Hello World'
print(a)

3.整型的读入

a=int(input())
print(a)

4.浮点数的读入

float型:

a=float(input())
print(a)

double型

a=float(input())
print(a)

 二.模块的应用

1.math模块

import math

print(math.ceil(4.1)) #返回数字的上入整数 5
print(math.floor(4.9)) #返回数字的下舍整数 4
print(math.fabs(-10)) #返回数字的绝对值 10
print(math.sqrt(9)) #返回数字的平方根 3.0
print(math.exp(1)) #返回e的x次幂 2.718281828459045

2.random模块

随机生成一个[0,1)范围的实数

import random
ran=random.random()
print(ran)

当使用random.seed(x)设置好种子之后,random()生成的随机数将会是同一个

print("----设置随机种子----")
random.seed(10)
print("Random number with seed 10:",random.random())

3.string模块

输出:分成单引号、双引号、三引号。

print('Hello World')
print("Hello World")
print('''Hello World''')

字符串的连接

使用加运算符

str1="Hello "
str2="World"
print(str1+str2) #Hello World

使用join 运算符

a='-'.join('Hello')
print(a) #H-e-l-l-o

三.数据类型

1.列表

(1).声明一个列表,并使用下标访问元素。

names=['jack','tom','tonney','superman','jay']

print(names[0]) #jack
print(names[1]) #tom

#访问最后一个元素
print(names[-1])
print(names[len(names)-1])

(2).访问第一个元素

print(names[-5])
print(names[0])

(3).列表的查询

第一种方法:

flag=0
for name in names:
    if name=="supperman":
        print("有超人")
        flag=1
        break;
if flag==0:
    print("无超人")

第二种方法:

if "supperman" in names:
    print("有超人")
else:
    print("无超人")

(4).列表的添加

append():在列表尾追加元素。

girls=[]
girls.append('Hello')
print(girls) #Hello

extend():合并列表。

a=['Hello','World']
girls.extend(a)
print(girls) # ['Hello','Hello',World']

insert():在指定位置添加。

girls.insert(1,'happy')
print(girls) #['Hello','happy','Hello','World']

(5).列表的修改

fruits=['apple','pear','香蕉','pineapple','草莓']
fruits[-1]='strawberry'
print(fruits) #['apple','pear','香蕉','pineapple','strawberry']

(6).列表的切片

#[]中设置要使用的第一个元素和最后一个元素的索引,牢记左闭右开
animals=['cat','dog','tiger','snake','mouse','bird']
#     正向索引 反向索引
# cat  0        -6
# dog  1        -5
#tiger 2        -4
#snake 3        -3
#mouse 4        -2
#bird  5        -1

print(animals[2:5]) #tiger snake mouse
print(animals[-1:]) #bird
print(animals[-3:-1] #snake mouse
print(animals[::2]) #从0开始,步数为2 ,cat,tiger,mouse
print(animals[-5:-1:2]) #从[-5,-1)的下标索引中,步数为2,dog snake

(7).列表的排序

生成10个不同的随机数,存放在列表中,并进行排序

import random

a=[]

i=0
while i<10:
    ran=random.random(1,20)
    if ran not in a:  #使列表中的随机数不重复
        a.append(ran)
        i+=1
print(a)

#默认升序
b=sorted(a)
print(b)

#降序
b=sorted(a,reverse=True)
print(b)

2.元组(Tuple)

与列表类似,区别是元组中的内容不可以修改。

注意·:元组中只有一个元素时,需要在后面加逗号。

import random
random_list=[]
for i in range(10):
    ran=random.randint(1,20) #[16,19,7,15,16,9,6,2.17]
    random_list.append(ran)  #(16,19,7,15,16,9,6,2,17)
print(random_list)

random_tuple=tuple(random_list)
print(random_tuple)

(1)元组的截取 

print(random_tuple[0]) #16
print(random_tuple[-1]) #17
print(random_tuple[1:-3]) #(19,1,7,15,16,9,)
print(random_tuple[::-1]) #(17,2,6,9,16,15,7,1,19,16)

(2).元组的一些函数

print(max(random_tuple)) #19
print(min(random_tuple)) #1
print(sum(random_tuple)) #108
print(len(random_tuple)) #10

(3).元组的拆包和装包

#元组个数与变量的个数相等
t3=(1,2,3)

#将元素赋给a,b,c
a,b,c=t3

print(a,b,c) #1 2 3

#元组个数与变量的个数不相等
t4=(1,2,3,4,5)

#将t4[0],t4[1]分别赋给a,b;其余元素封装好赋给c
a,b,*c=t4
print(a,b,c) #1 2 [3 4 5]
print(c) [3,4,5]

3.字典(Dict)

(1).定义一个空字典

dict2={}

(2).初始化

dict2={'name':'Hello','weight':45,'age':25}
print(dict2['name']) # Hello 

(3).定义一个字典,之后添加元素

dict4={}
dict4['name']='Hello'
dict4['weight']=43
print(dict4)

(4).修改字典元素

dict4['weight']=44

(5).字典相关函数

items()

dict5={'A':165,'B':166}
print(dict5.items())

for key,value in dict5.items():
    if value>165:
        print(key) #'B'

keys()

names=dict5.keys()
print(names) #'A','B'

values()

height=dict5.values()
print(height)
total=sum(height)
avg=total/len(height)
print(avg) #165.0

(6).字典的删除

del:

dict6={'A':1,'B':'2','C':3,'D':4}
del dict6['A']
print(dict6) #B:2 C:3 D:4

pop:

result=dict6.pop('B')
print(dict6) #C:3 D:4

四、六种最基础的数据类型

1.type

type(变量):可以返回变量的数据类型

a=10
print(type(a))#打印a的数据类型

2.数字类型

2.1.int类型(py中不用定义类型,可以直接用)

a=10

2.2.py浮点型只有float

a=1.00
print(a)
print(type(a))

2.3.complex复数类型

类似于高中学过的复数

注意:j前面的虚部数字一定要写,不然会报错

x=1+1j
print(x)
print(type(x))

3.运算符

(1)除法

/:返回一个浮点数

//:返回一个整数,相当于整除

a=2
b=1
print(a/b) #返回的是一个浮点数
print(a//b) #返回的是一个整数

(2)取余:%

a=1
b=2
print(a%b)

(3)乘法

a=2
b=3
print(a*b)

(4)乘方

a=2
b=3
print(a ** b) #2^3

4.蛇形取名法

name_and_sex

5.大驼峰小驼峰取名法

#NameAndSex

首字母大写

五、字符串string

1.python没有char类型

单引号和双引号甚至三引号都可以表示字符串

a='123456'
b="123456"
c="""123456"""
#a和b和c相等
print(a,b,c)

2.字符串的一些操作

s="i love py"

print(s.title())#给每个单词首字母大写
print(s.upper())#把所有字母变成大写
print(s.lower())#把所有字母变成小写

a = ",too"
print(s+a)#拼接

sn=f"i {a} love py"#插入字符串

#'\n'表示换行

print(1,end='123')

s=r'\n'#取消所有的转义字符

#给字符串删除一些空白
s='    1234     '
print(s.strip())#去除头尾空格
print(s.lstrip())#去除左边的空格
print(s.rstrip())#去除右边的空格

3.字符串的切片

s="aabbccdd"
#切片
#print(s[头下标:尾下标+1:步长])

print(s[0:8:1]) #aabbccdd
print(s[0:8:2]) #abcd
print(s[7::-1]) #ddccbbaa 从左往右切片
print(s[7::-2]) #dcba

字符串不能进行更改。

4.变量的赋值,多变量赋值

x=1
y=2
z=3

x,y,z=1,2,3

六、基本序列

1.列表list补充

相当于c\c++里面的数组

List = []   #空列表
print(List)
List = [1,2,3]
print(List)
print(type(List))

#列表的切片
print(List[0:2:]) #[1,2]
print(List[1])

#修改
List[1]=3

#list里面可以套list

2.集合

#集合的性质:
    #互异性
    #无序性

L1={1,2}
L2={2,1}

if L1==L2:
    print("ok")
else:
    print("no")

#集合set和list的转换
b=[1,1,2,3,4]
b=set(b) #用于去重

a={1,2,3,4}
a.clear()
a.pop()
a.add()
a.update()
a.remove()

3.字典

#字典 相当于哈希表
#定义一个空字典
d={} #空字典

#元素类型键值对 key:value

d={'name':'zsy','sex':'male','qq':1110012}

print(d['name']) #zsy

print(d.get('name')) #通过键取值

d.pop('qq') #通过键删除

print(d.keys()) #获取所有的键
print(d.values()) #获取所有的值
d['nmae']='li' #修改

七、强制转换与输入输出处理

1.字符串和整型数字

a=1
print(str(a))

a='110'
print(a) # '110'
print(int(a)) # 110

2.list和set

L=[1,1,2,3]
L=set(L)
print(L) #123

3.基本输入输出处理

对输出的字符串进行追加处理:

names=['zsy','wq']

print(f'hello {names[0]}')

print("hello {0},{1}".format(names[0],names[1]))

基本的输入输出处理,和C++类似:

#和C语言类似的格式化输出
print("%d %f"%(5,1.0))
print("%8d %f"%(5,1.0))
print("%-8d %f"%(5,1.0))
print("%s"%('zsy'))
print("%.2f"%(5.223))

4.判断语句的用法

4.1 单分支if语句

#3.判断语句 True,False
#被视为假的:False,0,None,"",[],(),{}
#单分支if语句,必须要缩进
#if 条件表达式:
#   执行语句
a=10
if a>0:
    print(True)

4.2双分支if-else语句

a=10
if a==0:
    print(False)
else:
    print(True)

4.3多分支if-elif语句

b=1
if b==3:
    print('y')
elif b==1:
    print('n')

5.比较运算符

#>,<,>=,<=,==,!=
#is,is not,in,not in
#is:双目运算符,必须两个变量值和对象都一样,才为真
#is not:和is相反
#in:判断一个是否在另一个中



a=1 #int
b=1.0 #float
#is不仅仅要求值一样,类型也要一样
if a is b: #如果换成==,输出的是y,因为==比较的仅仅是值,而is不仅比较值,而且还有类型,只有全部相同,才是一样
    print('y')
else:
    print('n')

#&:逻辑和 相当于and
#|:逻辑或,相当于or
#not:逻辑非

6.循环语句

6.1 for语句和while语句

#循环语句

#c/c++
#for(int i=1;i<=n;i++)

n=3
for i in range(1,n):
    print('*')

#while
#continue,break

b=True
flag=0
while b:
    flag+=1
    print('*')
    if flag==10:
        continue
    elif flag==15:
        break

#for i in range(1,9,步长):

num=[1,2,3,4]

a=len(num) #获取序列长度

for i in num:
    print(i)

6.2并行遍历

#并行遍历
#调用zip()方法
age=[18,19,17,20]

for i,j in zip(num,age):
    print(i,j)


#字典的迭代
d={
    'name':'zsy',
    'age':20,
    'sex':'male',
} 

#要所有的值
for it in d:
    print(it,d[it])

for it in d.values():
    print(it)

# 打印键和值
for key,value in d.items():
    print(key,value)

#获取1~9的平方
a=range(1,10)
b=[]
for i in range(1,9):
    b.append(i*i)

#列表推倒式实现获取1~9的平方
b=[i*i for i in a]

#C:switch case
#py:match...case a | case

#异常捕捉
a=[]
try:
    print(a[2])
except:
    print("Program is error!")

八、序列精讲

python中序列的概述

列表,元组,字典,集合:容器,数据结构

序列的通用操作

1.索引  list[i]

2.切片

索引的进阶用法,通过两个下标或者步长来确定序列中的一段/间隔的一段。

        [start:end:step]=赋值为新的序列

3.拼接

      通过+,将两个序列拼接起来,两个序列对象必须相同。

4.乘法

序列*int(n),可以得到类型n个相同的序列。

print("abc"*3)

5.clear()操作

list=['1','2']
list.clear()

6.浅拷贝

相当于list的切片,全复制一遍,只会复制值,改变a不影响list.

a=list.copy() #构造了一个新的对象
a.clear()

7.深拷贝

相当于地址,如果清除b,那么list也会清除,改变b影响list。

b=list.deepcopy()
b.clear()

8.count(x)

输出序列中x的个数。

List=[1,2,3,4]
print(List.count(3))

9.extend

在序列后面追加。

List.extend({'6':6.0,'7':7.0}) #把键追加到List后面
#键:'6'
#键值对:6.0

10.index(l,r,x)

可以判断x中是否在[l,r]中,如果存在,返回下标。

print(List.index(0,3,3))

#insert(i,x):在i这个位置插入x
List.index(1,6)

11.pop()

将最后一个元素输出,还可以输出。

x=List.pop()
print(x)

12.remove(x)

把值为x的删除。

List.remove(x)

13.reverse

把序列变成相反的。

List.reverse

14.sort

List.sort() #默认升序

List.sort(reverse=True) #降序排序

List.sort(key=lambda x:x+1) #把所有的值+1后升序排序

List.sort(key=lambda x:x+1,reverse=True) #降序

15.sorted

生成一个全新的升序序列,可以做到改变新的序列,不影响原本序列。

y=List.sorted()

16字符串转换list

s='123'
l=list(s)
print(l)

17.set()

集合,集合中不能有相同的元素,可以自动去重。

list.set() #可以实现列表的去重

18.dict():字典

19.len()

返回序列长度,int型。

20.列表可以进行乘法

print([1.3]*3)

21.列表的迭代

for i in List:
    print(i)

for i in List[0:3:2]:
    print(i)

22.max():最大值

print(max(List))

23.min():最小值

print(min(List))

24.range(start,end,step)

常在循环中出现。

25.dict 字典

Dict={
    '1':1,
    '2':2
}
#'1':键
#1:键值对

26.字符串

print(s.index('d')) #找到字符串的下标
print(s.title())
s.rstrip() #去除尾空格
s.lstrip() #去除头空格
s.strip() #去除头尾空格
s.lower() #把所有的字母变成小写
s.upper() #把所有的字母变成大写
s.split('分隔符') #通过分裂
    #list.split(" ") 通过空格隔开
s.join("123") 
s.replace('ab','xx') #将ab替换为xx

九、函数

基础函数⽤法

函数 (function) ⼜称为⽅法 可以理解为⽤⼾个⼈定义的公式 当定义好⼀个公式后, 我们可以⽤此公式得到⼀定的答案 或是完成⼀些功能 即函数必须先定义才能使

1.基本格式

使⽤关键字 def 本⾝是英⽂单词 define 的缩写 意为定义 随后写上函数名和括号 ,函数名与变量名的编写规则⼀样。
定义函数的优点
整理和优化代码 提⾼代码的复⽤率 避免重复代码 使代码保持简洁
使代码可以更好的编写 阅读和维护。
def 函数名(参数):
    return #可以有返回值,也可以没有返回值

2.函数参数

主要了解如何定义参数以及参数的基本⽤法 ” 参数 - 在调⽤函数式 向函数提供数据
此处我们定义⼀个函数 line() 功能为打印⼀条横线
def line():
    print("-----")
调⽤函数即可得到⼀条⻓度为5 的横线 若我们想得到可变⻓的横线⼜该如何做呢
可以如下 在编写函数时给 line() 函数⼀个 width 形式参数 通过 width 变量控制打印
的内容
# 在python中我们定义函数参数还是较为简单的,只需要在括号内按照顺序添上形参即可
def line(width):
    print("-" * width)
同样的 如果我们⼜想将函数功能改为打印⼀条可变⻓相同字符的字符串 即传⼊两个参
我们直接将两个参数放⼊括号内即可
需要牢记的是 我们在调⽤函数时 实参需要按照形参的顺序传⼊ 这种参数我们也称为
位置参数
我们在使⽤ IDEL 进⾏代码编写时 按照变量的类型 我们可以得到不同的代码提⽰
是在函数中的形参变量却⽆法得到代码提⽰ 这是因为 python ⽆法识别出参数的类型
对于这种情况 我们可以使⽤ 参数 : 数据类型
这种⽅式声明我们的参数类型
们同样也使⽤该⽅法在调⽤该函数时告诉外界此函数的参数类型 但是在调⽤函数时传⼊
不同类型的值 只要⽆基本错误 则不会影响函数的运⾏
def line(width: int, char: str):
    print(char * width)

3.函数的说明⽂档

在使⽤外⼈定义的函数时 若不清晰的看到函数代码逻辑 我们⽆法知道此函数的⽤法
那么在 python 规定函数在定义时应该尽量的写上说明⽂档来帮助他⼈使⽤该函数
⽅法即在函数头下⽅直接使⽤⽂档字符串 三引号字符串 ), 在其中写上函数说明 参数
说明和返回说明
def line():
    '''
    打印⼀条⻓度为5的横线
    return: None
    '''
    print("-----")
如何查看函数的⽂档说明呢
使⽤属性 doc 即双下划线 doc 双下划线
def line():
    """
    print a line
    :return: None
    """
    print("-----")

print(line.__doc__)
# 打印结果:
# print a line
# :return: None

4.函数的返回值

所谓函数的返回值 即调⽤函数后获得到的结果 例如
def get_max(a, b):
    '''获取a和b中的较⼤值'''
    # 将return后⾯的值返回给外界
    # return可以提前结束整个函数
    return a if a > b else b
    # python中三⽬运算符的⽤法:
    # <表达式1> if <条件> else <表达式2>
python 函数的返回值不仅仅可以返回⼀个 实际上可以返回多个 例如
def func(a, b):
    '''获取变量a和b的和差'''
    return a + b, a - b
add, reduce = func(21, 9)
# 同时需要两个变量来接收返回值
# 若只⽤⼀个变量接收,这多个值会被识别为元组,该变量则直接作为元组接收所有的值

5.变量作⽤域

主要了解全局 global 变量和局部 local 变量的⽤法 变量作⽤域是指, 在程序的哪些地⽅可以使⽤变量.
⾸先在函数外部定义的变量 我们称为全局 (global) 变量 在程序的任意位置 变量 的后续代码中) 都可以访问该变量 但存在⼀定限制.
在函数中或者条件语句中定义变量我们称为局部 (local) 变量 此变量只能在其声明的
区域进⾏使⽤或修改.
a = 1 # a 为全局变量

def func():
    b = 2 # b为局部变量

if 1 > 2:
    v = 3 # v为局部变量

for i in range(0, 10):
    m = 4 # m为全局变量
全局变量作⽤于全局 但是若在函数中 直接声明⼀个与全局变量相同名称的变量 则在
该作⽤域中会⾃动屏蔽对应的全局变量 使⽤该变量名只会对局部作⽤域中的对应变量造
成影响 与外部的全局变量⽆关
除此之外 在局部作⽤域中 ⽆法对全局变量进⾏修改 只能进⾏访问
若想在局部作⽤域中对全局变量进⾏修改 则必须使⽤关键词 global ⽤于声明该变量 ⾮同名的局部变量, ⽽是全局变量 由此可以进⾏全局变量的修改.
x = 1
def func():
    '''change global x'''
    global x
    x = 2

6.参数拓展

默认值 (default) 参数
在使⽤函数时 可能存在某个参数不常更改 但是每次调⽤参数的时候都必须去传⼊相同
的参数 为了简化操作 我们可以在声明函数时 给对应的参数赋予⼀个默认值 如此可
以在调⽤函数时不⽤传⼊该参数 其在函数中的值直接被赋予默认值
# 值得注意的是,如果我们是想省略某个参数的传递,根据位置参数按照顺序传参的⽅式,如果
前⽅参数赋予默认值⽽后⽅参数不予默认值,则很容以看出会有逻辑上的⽭盾,故默认值只能从
后往前进⾏设置
def f(a, b = 0, c = 1):
    return a + b + c
关键字 (keyword) 参数
若存在未初始化的参数 则可以 kwarg=value 形式的 关键字参数 调⽤函数
def solve(age, name="lys", status="dog"):
    print(f"{name} is", end=' ')
    print(f"{age} years old, and {name}", end=' ')
    print(f"is a {status} .")
# solve(114514) # 第⼀个参数是必选参数,剩余参数可不选
# solve(114514, "LYS") # 不声明关键字会默认匹配除默认参数后的最近的关键字参数
# solve(114514, name="LYS")
# solve(14, status="debu cat", name="Hiiro") # 传⼊关键字参数与参数列表的
关键字对应
除上述调⽤⽅法外 以下调⽤⾮法
solve() # 缺省 age 参数
solve(name="Hiiro") # 缺省 age 参数
solve(age=114514, "debu cat") # debu cat 需要照应⼀个关键字
solve(114514, age=1919) # age 存在多个不同的值
可变⻓参数
        *args
        **kwargs
先来看个例⼦
def foo(*args, **kwargs):
    print('args = ', args)
    print('kwargs = ', kwargs)
    print('---------------------------------------')

if __name__ == '__main__':
    foo(1,2,3,4)
    foo(a=1,b=2,c=3)
    foo(1,2,3,4, a=1,b=2,c=3)
    foo('a', 1, None, a=1, b='2', c=3)
可以看到 这两个是 python 中的可变参数 args 表⽰任何多个⽆名参数 它是⼀个 tuple **kwargs 表⽰关键字参数 它是⼀个 dict 并且同时使⽤ args kwargs 必须 * args 参数列要在 kwargs foo (a=1, b='2', c=3, a', 1, None,) 这样调⽤的话 会提⽰语法错误 “SyntaxError: non-keyword arg after keyword arg”。 知道 * args **kwargs 是什么了吧 还有⼀个很漂亮的⽤法, 就是创建字典
def kw_dict(**kwargs):
    return kwargs
print(kw_dict(a=1,b=2,c=3) == {'a':1, 'b':2, 'c':3})
其实 python 中就带有 dict 使⽤ dict (a=1,b=2,c=3) 即可创建⼀个字典 了。

十、高级函数的用法

1.Python函数是可以嵌套

实际上在 python 中万物皆对象
那么我们在声明⼀个函数的时候 实际上是声明了⼀个全局的函数对象
# 声明⼀个函数对象
def func():
    print("hello!")

# 给⼀个变量浅拷⻉为func函数变量
a = func
a() # 将a作为函数⽅法调⽤

# 结果:hello!
由此可⻅ 函数与其他变量⽆异 那么 函数变量也满⾜其他变量的作⽤域使⽤规则
时也可以在函数中声明⼀个函数变量 从⽽实现函数的嵌套
def outer():
    def inner():
        print("This is inner.")
    print('This is outer.')
    b = inner
    b()

a = outer
a()
# 结果:
# This is outer.
# This is inner.
# b = inner
# b()
# 结果:报错
同样的 函数也可以如其他变量⼀样 作为对象被返回 (return)
def outer():
    def inner():
    print('This is inner.')
    print('This is outer.')
    return inner

a = outer
b = a() # 结果: This is outer.
b() # 结果: This is inner.
并且 函数也可以作为参数传⼊另⼀个函数
def func_1():
    print('This is func_1.')

def func_2(func):
    print('This is func_2.')
    func() # 在func_2中调⽤func函数

func_2(func_1) # 调⽤func_2, 同时把func_1作为参数传⼊

# 结果:
# This is func_1.
# This is func_2.

2.lambda表达式

许多时候 我们或许会使⽤⽐较简单的函数 但是声明起来却很⿇烦 需要⼀块位置去专
⻔写⼀块代码
实际上在许多的⾼级语⾔中都涉及了匿名函数的设计 可以快速的设计⼀个函数对象
么在 python 中也同样可以使⽤ 我们称为 lambda 表达式 使⽤ lambda 关键字和规定语
法即可申请⼀个匿名的函数对象
def GetAnonymous():
    '''获取⼀个匿名的函数对象,且其功能为获得参数加上偏移量5的值'''
    return lambda x: x + 5

a = GetAnonymous()
print(a(10))

# 结果:
# 15

3.闭包

所谓闭包 简⽽⾔之就是将数据封装在⼀个包 区域 使⽤时我们再去⾥⾯取 。(
质上 闭包是基于函数嵌套搞出来的⼀个中特殊嵌套
· 闭包应⽤场景 1 封装数据防⽌污染全局
def func(age, sex: string):
    name = 'zsy'
    # 如此可以防⽌name全局变量的污染
    def func_1():
        print(name, age)
    
    def func_2():
        print(name. sex)
    
    func_1()
    func_2()

a = func
a()
# 但实际上我们很少能⽤得上该种⽅式
· 闭包场景应⽤ 2 封装数据到⼀个包中 使⽤时再取
def task(arg):
    def inner():
        print(arg)
    return inner

innner_func_list = []
for val in range(0, 4):
    inner_func_list.append(task(val))

for val in inner_func_list:
val()
# 结果:
# 0
# 1
# 2
# 3
实际上在 python 中闭包使⽤得到的场景是没有那么清晰直观的 这边有⼀些提前的知识
来让⼤家了解到闭包的使⽤场景
"""基于多线程并⾏完成爬⾍任务"""
from concurrent.futures.thread import ThreadPoolExecutor
import requests
# 构建线程池
POOL = ThreadPoolExecutor(5)
# 三个爬⾍任务
spider_tasks = [
    ('哪⾥都是你mv.mp4',

'http://vodkgeyttp8.vod.126.net/cloudmusic/da70/core/b88c/70c2e21a75785
7fe8a12fe0345986398.mp4?
wsSecret=b815d122a2dd93eaf122c52686da471d&wsTime=1675325208'),
    ('成都mv.mp4',

'http://vodkgeyttp8.vod.126.net/cloudmusic/IjAyMCAgMyEgYDEwIDhhMg==/mv/
5619601/79bd07d7bd9394871da0c324d53f48dd.mp4?
wsSecret=efd55511ee0c07c53c230301d116d6e6&wsTime=1675325208'),
    ('江南mv.mp4',

'http://vodkgeyttp8.vod.126.net/cloudmusic/MTI5MDc0OTc=/d23df6673394543
e4d1dd291e566c337/767999bafb2a5d407708e2770f7725e8.mp4?
wsSecret=f010419757e1f2359119519422967ce2&wsTime=1675325208')
]
def task(url):
    content = requests.get(url=url).content
    # return content
    print('任务:', url, '已完成!')
    return content

def outer(filename):
    def done(arg):
        data = arg.result()
        with open(filename, 'wb') as f:
            f.write(data)

    return done

for item in spider_tasks:
    a = POOL.submit(task, item[1])
    print('已分配任务:', item[0])
    a.add_done_callback(outer(item[0]))

# 结果:
已分配任务: 哪⾥都是你mv.mp4
已分配任务: 成都mv.mp4
已分配任务: 江南mv.mp4
任务:
http://vodkgeyttp8.vod.126.net/cloudmusic/IjAyMCAgMyEgYDEwIDhhMg==/mv/5
619601/79bd07d7bd9394871da0c324d53f48dd.mp4?
wsSecret=efd55511ee0c07c53c230301d116d6e6&wsTime=1675325208 已完成!
任务:
http://vodkgeyttp8.vod.126.net/cloudmusic/da70/core/b88c/70c2e21a757857
fe8a12fe0345986398.mp4?
wsSecret=b815d122a2dd93eaf122c52686da471d&wsTime=1675325208 已完成!
任务:
http://vodkgeyttp8.vod.126.net/cloudmusic/MTI5MDc0OTc=/d23df6673394543e
4d1dd291e566c337/767999bafb2a5d407708e2770f7725e8.mp4?
wsSecret=f010419757e1f2359119519422967ce2&wsTime=1675325208 已完成!
# 由此在⼀系列⼯作中,闭包可以在不需要更改原本函数的情况下添加上额外的功能

4.装饰器

装饰器其实也是⼀种闭包 作为⼀种语法糖在 python 中⼴泛使⽤ 在写 python 的时候
偶尔会对某个冗⻓的函数加上其他功能 但是如此修改起来会很⿇烦 那么此时装饰器可
以帮助我们在不修改原本函数内容的同时增添新的功能 名⽈ 装饰
例如 要求在函数 func 执⾏时在先前操着之前和之后执⾏分别打印 before after
def func():
    print('This is func.')
第⼀时间想到的思路是直接修改 func
# 简单思路
def func():
    print('before')

    print('This is func.')

    print('after')
通过前⽅的闭包思路 其实可以如此修改
# 闭包思路
def outer(func):
    def inner():
        print("before")
        func()
        print('after')
    return inner

task = outer(func)
task()
实际上 上述⽅法反⽽会显得冗杂 那么有没有办法可以简单化呢 这就要讲到 python
的语法糖 所谓语法糖 甜的 好的 就是将⼀系列冗杂的语法简单化
对于闭包的使⽤ 就拥有⼀个语法糖 我们也称为装饰器 即使⽤ @ 函数名的⽅式实现
实现⽅式如下
"""
语法糖的使⽤:

@func
def xxx():
    pass

其中,python会根据该段代码⾃动执⾏如下代码:
xxx = func(xxx)

那么我们即可以根据闭包,甚⾄可以在func中使⽤额外参数去装饰函数xxx
"""
如此上⽅代码可以简化为下
# 闭包思路
def outer(func):
    def inner():
        print("before")
        func()
        print('after')
    return inner

@outer
def func():
    print('This is func.')

func() # 调⽤func
但是在此中 虽然是简化了语法 但是有种曲线救国的意思 依然是显得冗杂 不如最简
单的思路 实际上 在此需求中 确实第⼀种⽅法最为⽅便和简洁 那么此时更换⼀下需
若是要在多个函数中不修改函数内容 在每次函数调⽤时先打印⼀个 before 执⾏
后再打印⼀个 after
def func_1():
    print('this is func_1')
def func_2():
    print('this is func_2')
# ........
此时 再逐⼀更改函数内容会显得很⿇烦了 再之 若我们的需求不仅仅是打印 before
after ⽽是完成其他更复杂的操作 加之需要修改的函数⼗分之多 则会显得装饰器
的使⽤反⽽更为简洁了 并且在维护代码时 装饰器会更为优秀
那么对于装饰器的使⽤场景 还需要⾃⼰去思考和发现 例如 对于参数可变 我们则可
以对 inner 函数加上 *args **kwargs 来实现装饰带有可变⻓参数的函数 除此之外 我们需要认识到 使⽤装饰器或者闭包时 声名的函数本质上是⼀个 inner
其函数⽂档和函数名 通过 name doc 都是 inner 函数的内容
那么如何拿到原函数内容呢
这⾥要使⽤的⼀个内置库 名为 functools
def outer(func):

    @functools.wraps(func)
    def inner(*args, **kwargs):
        data = func(*args, **kwargs)
        return data

    return inner
# 如此即可得到相应的⽂档名称等等
在使⽤装饰器时加上 functools 是更好的习惯

5.⽣成器

对于任何⼀个函数 我们都有⼀个返回值 使⽤ return 去返回⼀个值 当不⽤ return
者使⽤ return 后续不接任何值时会默认返回⼀个 None 的值
但其实在 python 中我们有⼀个更为⾼级的关键字 yield 来实现可变的返回值
使⽤⽅式很简单 return 改回 yield :
def func():
    yield None
此种函数 我们称之为⽣成器函数 简称⽣成器.
其⽤法在特定情况下可以帮我们节省内存.
def func():
    '''使⽤该函数进⾏⼀个计数,每次调⽤得到⼀个更⼤的⾃然数'''
    
    for num in range(0, 100):
        print("计数ing...")
        yield num

a = func() # 得到⽣成器对象
print(a) # 得到⽣成器时,是不会执⾏函数内部代码的

# 使⽤next()对象进⼊⽣成器,执⾏代码,同时可以⽤变量的到yield的返回值
num = next(a)
print(num)

num = next(a)
print(num)

num = next(a)
print(num)

# 返回结果:
# <generator object func at 0x0000021D0A50EE40>
# 计数ing...
# 0
# 计数ing...
# 1
# 计数ing...
# 2
当⽣成器的代码实际执⾏完毕之后 会报错 错误类型为 :StopIteration
来表⽰该⽣成器已结束 对于该错误我们可以⽤异常捕捉来解决.
对于更简单的⽣成器调⽤ 可以⽤ for 循环来执⾏⽣成器对象.
def func():
    '''使⽤该函数进⾏⼀个计数,每次调⽤得到⼀个更⼤的⾃然数'''
    
    for num in range(0, 5):
        print("计数ing...")
        yield num

a = func() # 得到⽣成器对象

for item in a:
    print(item)

# 结果:
# 计数ing...
# 0
# 计数ing...
# 1
# 计数ing...
# 2
# 计数ing...
# 3
# 计数ing...
# 4
如此我们可以不需要捕捉异常 即可将⽣成器完整地迭代完毕 在⼯程设计时 也经常如
此使⽤
需要牢记的是⽣成器的最⼤作⽤ 是实现内存的节省
例如要求⽣成 300000000 多个对象 如果使⽤其他⽅法 开销是巨⼤的 特别是在
redis 这种数据库中 若不适⽤⽣成器 则可能会直接导致 redis 爆炸 内存直接爆栈
⽣成器拓展.
该处不要求记住 只要求能看懂
实际上 在⽣成器函数中 我们可以使⽤ < 变量名 > = yield < 返回值 > 的⽅式将⽣成
器封存 直到下次对⽣成器对象使⽤ send(value) ⽅法将 value 的值赋给 < 变量 > 之后
才可以继续往下执⾏代码
def func():
    for i in range(5):
        v = yield i
        print(v)

g = func()

g.send(None)
for i in range(4):
    a = g.send('计数ing')
    print(a)

# 结果:
# 计数ing
# 1
# 计数ing
# 2
# 计数ing
# 3
# 计数ing
# 4
"""
值得注意的是,send函数会直接进⾏⽣成器的迭代
"""

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值