Python3基础知识(一)

1.使用类似三目运算符的方式来实现一个数的绝对值 if else
# 输入一个数,然后利用一个语句求它的绝对值
num = int(input("请输入一个整数:"))
num_abs = num if num > 0 else -num
print(num_abs)
2.python3复合条件判断的使用(1
#输入一个整数,判断是否在0~100之间
num = int(input("请输入一个整数:"))

#python支持复合的条件表达式
if 0 <= num <= 100:
    print("这个数在0~100之间")
else:
    print("这个数不在0~100之间")
3.字符和Unicode编码之间的转换
  • 知道字符编码(0~65535)值获取对应的 -> chr()
n = int(input("请输入一个整数(0~65535):"))
print(n ,"对应的字符是:",chr(n))

ch = input("请输入一个字符:")
print(ch,"对应的Unicode码数为:" ,ord(ch))
4.判断是否是回文字符串,类似这种"abcba"
  • 解析,判断思路,如果是回文的话,则其字符串反转之后和原来的字符串是相同的.
s = input("请输入一个字符串:")
#使用切片的方式实现字符串的翻转
s1 = s[::-1]

#如果翻转之后的字符串和原来的字符串相等,则是回文.
if s == s1:
    print("{}是回文数".format(s))
else:
    print("{}不是回文数".format(s))
5. "字符串" * n 表示的是重复打印n次字符串.利用这个可以打印一个矩形框
#打印一个5*5矩形框,当使用一个字符串和一个数字用*联系起来的时候,表示的是重复.
for x in range(5):
    if x == 0 or x == 4:
        print("*" * 10)
    else:
        print("*" + " " * 8 + "*")
6.一个字符串去除首尾两个字符的方法.
  • 在字符串中,下标-1代表最后一个字符的下标,同时len(s) - 1也代表最后一个字符的下标.
#输入一个字符串,去除字符串的收尾两个字符
s = input("请输入一个字符串:")

#方法一,利用最后一个下标的值是-1,来进行切割
s1 = s[1:-1]

#方法二,利用最后一个下标的值是len(s) - 1,来进行切割
s2 = s[1:len(s)-1]

print("s1 = {},s2 = {}".format(s1,s2))
7.python字符串的center()方法
  • 原型是 str.center(width[,fillchar])
    fillchar参数是可选的,如果不填,则默认用空格填充.
    返回值,这个函数返回一个长度为width的新字符串,原来的字符串居中显示,两边的用空格或者fillchar填充
#   输入三行文字,让这三行文字在一个方框内居中显示
#   如输入(不要输入中文):
#     hello!
#     I'm studing python!
#     I like python
#   显示如下:
#    +---------------------+
#    |       hello!        |
#    | I'm studing python! |
#    |    I like python    |
#    +---------------------+

题目分析:
1> 首先是求出最大的字符串长度,确定它的宽是len + 2个空格
2> 然后让所有的字符串居中打印即可.

s1 = "hello!"
s2 = "I'm studing python!"
s3 = "I like python"

#利用max(a,b,c)求出最大长度
length = max(len(s1),len(s2),len(s3))
width = length + 2;

print("+" + "-" * width + "+")
print("|" + s1.center(width) + "|")
print("|" + s2.center(width) + "|")
print("|" + s3.center(width) + "|")
print("+" + "-" * width + "+")
  • 带有fillchar参数的例子,注意当width没有原来的字符串长度大时,原字符串原样返回.当width两边的剩余为奇数时,则左边会比右边的少1个.
s = "hello"
s1 = s.center(20)
print(s1)#       hello  

s2 = s.center(10,'*')      
print(s2)#**hello***
8.已知一个字符串,打印这个字符串中的Unicode码最大的字符,以及它的Unicode码时
  • 分析循环遍历字符串,先假设最大的字符的Unicode码是max_ch,然后循环比较即可.利用ord()
s = input("请输入一个字符串:")
#先设定最大的字符的unicode码为0
max_ch = 0

for ch in s:
    if ord(ch) > max_ch:
        max_ch = ord(ch)

print("最大的字符的Unicode编码是:{},对应的字符是:{}".format(max_ch,chr(max_ch)))
9.列表的前面插入数据,中间插入数据,后面插入数据,以及删除尾部操作演示
# 练习:
#   已知有列表:
#     L = [3, 5]
#     用索引和切片操作将原列表L 改变为:
#        L = [1, 2, 3, 4, 5, 6]
#     将原列表反转, 删除最后一个元素
#        打印此列表:
#     print(L)  # [6, 5, 4, 3, 2]

操作如下:

L = [3,5]
#先利用列表索引切片赋值插入4,注意这里赋值相当于是插入操作,在原列表上进行的.
L[1:1] = [4]

#然后在列表的头部插入[1,2]
L[:0] = [1,2]

#在5的后面插入6,也就是最后面
L[len(L):] = [6]
print(L)
10.使用列表的方法生成40个斐波拉切数.
  • 始终用列表的最后两项作为斐波拉契数的最后两位.有三种方式,其中最简单的一种就是利用下标-1和-2
#生成40个斐波拉切数,利用列表

def f1():
    L = [1,1] #先声明一个列表存放前两项
    while len(L) < 40:
        L.append(L[-1] + L[-2]) #将列表的最后两项加起来放到最后一项
    print(L)

def f2():
    L = [1,1]
    #用a和b代表最后两项
    a = 1
    b = 1
    while len(L) < 40:
        c = a + b
        L.append(c)
        #然后让a,b还是最后两项
        a = b
        b = c
    print(L)

def f3():
    L = [1,1]
    a = 1
    b = 1
    while len(L):
        c = a + b
        L.append(c)
        #元组赋值,序列赋值
        a,b = b,c
    print(L)

if __name__ == '__main__':
    f1()
    f2()
    f3()
11.将用户输入的带有数字的字符串转换为数字列表.
  • 分析:用到的知识点,字符串的分割还有就是列表推导式.假如字符串是"100,200,300,400,500",要得到[100,200,300,400,500]
s = "100,200,300,400,500"

#先将字符串按逗号进行分割,得到的是一个字符串列表
lst_str = s.split(',')
print(lst_str)#['100', '200', '300', '400', '500']
#利用列表推导式,将每一项转换为int
l1 = [int(x) for x in lst_str]
print(l1) #[100,200,300,400,500]

#以上的代码也可以简化为一行
l2 = [int(x) for x in s.split(',')]
print(l2)#[100,200,300,400,500]

#还有一种笨重的方法,使用循环来做.
l3 = list()
for ch in lst_str:
    l3.append(int(ch))
print(l3)#[100,200,300,400,500]
12.列表去重
  • 分析:
    方法1.使用成员判断 in 和 not in
    方法2.使用count(x),判断这个元素出现的个数
    方法3.使用集合,集合具有自动去重功能
#列表去重
L = [1,3,2,1,6,4,2,7,8,9,2,1,2,3,98,92,92,98]

#方法1,in 和 not in.遍历L,如果元素不在L2内,就追加上去
def f1():
    L2 = []
    for x in L:
        if x not in L2:
            L2.append(x)
    print(L2)

#方法2,使用count统计个数
def f2():
    L2 = []
    for x in L:
        if L2.count(x) < 1:
            L2.append(x)
    print(L2)

#方法3,使用set
def f3():
    #使用列表推导式,这里是无序的.
    L2 = [x for x in set(L)]
    print(L2)   


if __name__ == '__main__':
    f1()
    f2()
    f3()
13.统计字符串中出现过的字符,以及每个字符出现的次数.
  • 分析
    方法1. 将字符串去重放入列表中,遍历这个列表,然后使用count每个字符出现的个数.
    方法2.可以使用字典,将字符作为字典的键,因为键是不能重复的,而个数就一直累加就可以了.
#统计字符串出现的字符,以及各个字符出现的次数
s = "abcdefgabcdefadehijklmdefc"

#方法1,使用列表和count.
#去重然后遍历,无序的.
for ch in set(s):
    print("字符{}出现的次数是:{}".format(ch,s.count(ch)))

#如果按照出现的顺序,可以使用列表
print("===============================")
L = []
for x in s:
    if x not in L:
        L.append(x)
for ch in L:
    print("字符{}出现的次数是:{}".format(ch,s.count(ch)))
#方法2,使用字典
print("===============================")
d = {}

for ch in s:
    if ch not in d:
        d[ch] = 1
    else:
        d[ch] += 1

for x in d:
    print("字符{}出现的次数是:{}".format(x,d[x]))
14.单词和解释(字典的使用)
  • 输入单词和解释,将单词和解释存放起来,然后输入一个单词,查询单词对应的解释.如果输入空的时候,结束输入
#单词和解释以及查询
#先创建一个字典用来存放单词的和解释
dictionary = {}
while True:
    word = input("请输入单词:")
    # 如果输入为空,结束录入
    if not word:
        break
    explain = input("请输入单词的解释:")

    dictionary[word] = explain

query = input("请输入你要查询的单词:")
if query in dictionary:
    print("{}的解释是:{}".format(query,dictionary[query]))
else:
    print("你查询的单词不存在")
15.判断100到999之间的水仙花数,水仙花数是指个位的三次方,十位的三次方和百位的三次方的和等于自身.
  • 分析:两种方法
    方法1,最原始的方法,求出个位数,十位数,百位数,然后做运算即可.
    方法2,将数转换为字符串,然后通过取字符串的各个值,即可取到相应的位的值
#水仙花数的计算(100~999)
#先使用笨方法,将这个数的个十百提取出来
def isWaterNumber(n):
    #个位,对10求余
    a = n % 10
    #十位,对100求余数,然后地板除10
    b = (n % 100) // 10
    #百位,直接对100地板除
    c = n // 100
    #判断条件,如果是满足条件就返回True
    return a ** 3 + b ** 3 + c ** 3 == n

def isNumber(n):
    #利用字符串,字符串的三个元素就是对应了个十百位上的数
    s = str(n)
    return int(s[0]) ** 3 + int(s[1]) ** 3 + int(s[2]) ** 3 == n

if __name__ == '__main__':
    for x in range(100,1000):
        if isNumber(x):
            print(x)
16.按行打印100以内的全部素数,利用函数来做
  • 使用函数,以及print函数的end的用法.2是素数
# 打印100以内的素数

def isPrime(n):
    if(n < 2):
        return False
    for x in range(2,n):
        if n % x == 0:
            return False

    return True

def printPrime():
    for x in range(101):
        if isPrime(x):
            print(x,end = " ")
    print()

if __name__ == '__main__':
    printPrime()
17.python的局部变量和全局变量
  • 局部变量

定义在函数内部或函数形参的变量为局部变量.
局部变量只能在函数内部使用,首次对变量赋值时创建了局部变量,再次赋值的时候修改了绑定关系.
函数调用时被创建,函数调用结束之后销毁.

  • 全局变量

定义在函数外部,模块的内部的变量称为全局变量
所有的函数都可以访问全局变量,但是在函数内部不可以直接访问,必须事先用global声明,否则会被当成创建了一个局部变量

  • 注意

1> 全局变量在函数内部首次使用的时候,要加上global声明,否则会被当成是局部变量的声明和创建
2>局部变量只能在声明他的函数的内部访问,而全局变量则可以在整个模块内访问.


image.png
x = 100
def f1():
    global x #说明x变量是全局变量
    x = 200
f1()
print("x = ",x)#200

y = 200
def f2():
    y = 300
    global y #这里是错误的,因为全局变量在声明之前被赋值了.

f2()
print("y = ",y)


v = 100
def f3(v):
    global v #这里是错误,形参不能声明为全局变量.
    v = 200
    #一个变量不可能同时被声明为全局变量和形参变量.
  • globals()函数和locals()函数
    globals()和locals()函数返回的是一个字典,里面存放的是变量名和变量值的键值对.
    其中globals()返回的是当前模块所有的全局变量,不仅仅局限于你自己使用的全局变量.
#globals()和locals()返回的是一个字典
a = 1
b = 2
c = 3

def fx(c,d):
    e = 300
    print("locals() 返回",locals())
    print("globals() 返回",globals())
    print(c)

if __name__ == '__main__':
    fx(4,5)
18.python3中的函数变量
  • 函数名就是变量,它在创建的时候可以绑定一个函数名.函数变量还可以改变绑定关系.
  • 函数变量使用()的调用方法,可以调用它绑定的函数.
def f1():
    print("这是f1()")

def f2():
    print("这是f2()")

fx = f1
fx() #f1()被调用

fx = f2
fx() #f2()被调用
19.Python的四个作用域(LEGB)
  • Local(局部作用域) Local(function) L 又叫本地作用域
  • 外部嵌套函数作用域 Enclosing function locals E
  • 全局作用域(模块内作用域) Global G
  • 内置模块作用域 Builtin(python) B
变量名的查找顺序

先查找本地变量 -> 包裹这个函数外部函数的内部变量 -> 全局变量 -> 内置(内建)变量
本地变量在赋值的时候一般会创建或改变本地变量.

  • nonlocal语句

作用:
告诉解释器,nonlocal声明的变量不是局部变量,也不是全局变量,而是外部嵌套函数内的变量
说明:
1)nonlocal语句只能在被嵌套的函数内部使用
2)访问nonlocal变量将对外部嵌套函数作用域内的变量进行操作
3)当有两层或两层以上的函数嵌套时,访问nonlocal变量只对最近一层的变量进行操作
4)nonlocal语句的变量名列表里的变量名,不能出现在此函数的形参列表里.

#nonlocal语句只能使用在嵌套函数的内部函数,如果没有外部函数,则nonlocal语句会报错
v = 100
def f1():
    # nonlocal v
    v = 200

#如果有多层,就近选择最近的层.
def f2():
    # nonlocal v 会报错,因为f2()没有外部函数
    v = 200
    def f3():
        v = 300
        def f4():
            nonlocal v #这里声明这里的v是f3()里面的v
            v = 400 #这里的赋值不会改变f2()里面的v
            print("f4()里面的v是:",v) # 400
        print("f3()里面的v是:",v) # 300
        f4()
    print("f2()里面的v是:",v) #200
    f3()

f2()
20.lambda表达式(匿名函数)
image.png
# lambda表达式,匿名函数
#创建一个两个数和的匿名函数,创建一个两个数差的匿名函数
myadd = lambda x,y:x + y
mysub = lambda x,y:x - y

print("10 + 20 = ",myadd(10,20))
print("20 - 10 = ",mysub(20,10))
# lambda依托于后面的表达式,并且表达式的结果只有一个
mymax = lambda x,y:x if x > y else y
mymax1 = lambda x,y:max(x,y)

#后面只有是个合法的表达式都是可以的
f1 = lambda n: (n ** 2 + 1) % 5 == 0 #返回值是True 或者 False
21.eval()和exec()函数介绍
image.png
#eval计算表达式的值
x = 10
def func():
    y = 20
    a = eval('x + y')
    print("a: ", a)
    b = eval('x + y',{'x':1,'y':2})
    print("b: ",b)
    c = eval('x + y',{'x':1,'y':2},{'y':3,'z':4})
    print("c: ",c)
    d = eval('print(x,y)')
    print('d: ',d)

if __name__ == '__main__':
    func()
  • 输出结果

a: 30
b: 3
c: 4
10 20
d: None

  • 输出结果的解释

对于变量a,eval函数的globals和locals参数都被忽略了,因此变量x和变量y都取得的是eval函数被调用环境下的作用域中的变量值,即:x = 10, y = 20,a = x + y = 30
对于变量b,eval函数只提供了globals参数而忽略了locals参数,因此locals会取globals参数的值,即:x = 1, y = 2,b = x + y = 3
对于变量c,eval函数的globals参数和locals都被提供了,那么eval函数会先从全部作用域globals中找到变量x, 从局部作用域locals中找到变量y,即:x = 1, y = 3, c = x + y = 4
对于变量d,因为print()函数不是一个计算表达式,没有计算结果,因此返回值为None

image.png
  • 实例2
x = 10
expr = """ 
z = 30
sum = x + y + z
print(sum)
"""

def func():
    y = 20
    exec(expr)
    exec(expr,{'x':1,'y':2})
    exec(expr,{'x':1,'y':2},{'y':3,'z':4})
    
if __name__ == '__main__':
    func()
  • 输出结果

60
33
34

  • 对输出结果的解释

前两个输出跟上面解释的eval函数执行过程一样,不做过多解释。关于最后一个数字34,我们可以看出是:x = 1, y = 3是没有疑问的。关于z为什么还是30而不是4,这其实也很简单,我们只需要在理一下代码执行过程就可以了,其执行过程相当于:

x = 1
y = 2
def func():
    y = 3
    z = 4
    z = 30
    sum = x + y + z
    print(sum)
func()
  • 再来一个实例,eval()的参数问题
#此示例示意eval(expression,global=None,local=None)
x = 100
y = 200
v = eval('x + y')
print(v)  # 300

dict_local = {'x':1,'y':2}  #这个是eval的参数
v = eval('x + y',None,dict_local)

print(v)  # 这里会使用dict_local的值 3

dict_global = {'x':10,'y':20}
v = eval('x + y',dict_global,{'y':2})

print(v)  # 这里x会使用dict_global的值,但是y会使用local里面的值.这里结果是12

v = eval('x + y',None, {'y':2})
print(v) #这里显示的结果是 100 + 2 = 102

v = eval('x + y',{'x':1})#第二个参数必须是字典,并且必须包含表达式里的所有的元素
print(v)
22.Python内建的高阶函数map,filter,sorted
  • 函数式编程(函数可以作为参数插入另一个函数,还可以返回一个函数)

1> 特点1: 函数名也是一个变量,可以赋值给一个变量
2> 特点2:函数可以作为另外一个函数的参数出入
3> 特点3:函数可以作为另外一个函数的返回值.

好处:

用每一个函数完成完成细小的功能,然后一系列函数任意组合之后可以完成更大的功能.

函数的可重入性:

当一个函数在运行时,不读取或改变除局部作用域以外的其他变量的时候,此函数为可重入函数.可重入函数有一个特性,如果每一次的参数一样,则其结果也是一样的.

#可重入函数示例
def myadd(x,y):
      return x + y

#不可重入额函数示例
y = 300
def myadd2(x):
      return x + y
print(myadd2(10)) #310
y = 400
print(myadd2(10))#410
  • 什么是高阶函数
    满足下列条件之一的即为高阶函数

1> 函数接收一个或多个函数作为参数传入
2> 函数的返回值依旧是一个函数

23.python中的内建高阶函数map,filter,sorted
  • map()函数
    iterable = map(function,iterable1,iterable2,...)
  • 作用

用函数和可迭代对象作为参数,用函数的返回值重新生成一个新的可迭代对象作为返回值.

  • 要求

function的参数的个数必须和后面的可迭代对象的个数一样.并且迭代调用结束的标志是可迭代参数有一个迭代结束就停止

# 求 1**2 + 2**2 + 3**2 + ...+ 9**2的和
#      (用函数式和高阶函数map实现)

#求x的平方
def mypow(x):
    return x ** 2
s = 0
#生成可迭代对象it,里面存放的就是各项的平方
it = map(mypow,range(1,10))
for x in it:
    s += x

print("和是:",s)
# 以上代码可以简化为一行
print("和是:",sum(map(mypow,range(1,10))))

#2. 求 1**3 + 2**3 + 3**3 + ...+ 9**3的和
# 可以使用匿名函数代替mypow
s2 = 0
it2 = map(lambda x:x ** 2,range(1,10))
#可以使用sum(iterable) 一个可迭代对象的求和公式
s2 = sum(it2)
print("和是:",s2)

#1**9 + 2**8 + 3**7 + .... + 9**1的和,一行代码实现.匿名函数以及range()从大到小迭代.
s3 = sum(map(lambda x,y:x ** y,range(1,9),range(9,0,-1)))
print("和是:",s3)
  • filter()函数
    iter = filter(function,iterable)
  • 作用

对iterable进行过滤,将iterable作为参数依次传递给function,如果function的返回值为True,就保留,如果为False就丢弃掉.然后将保留的数据作为一个可迭代对象返回.

#写一个过滤器求出100~200之间的所有的素数的和
def isPrime(n):
    if n < 2:
        return False

    for x in range(2,n):
        if n % x == 0:
            return False
        return True

s = sum(filter(isPrime,range(100,201)))
print("和是: ",s)
  • sorted()函数
    list = sorted(iterable,key=None,reverse=False)

默认升序返回一个新的列表包含了按照指定规则所有项目的迭代.不改变原来的可迭代对象

  • 参数说明

iterable可迭代对象,key排序规则,将可迭代对象带入key绑定的函数,按照结果进行排序,还可以指定可迭代对象的同一位置进行排序.reverse表示的是排序是否按照降序排列
reverse排序规则,False默认是升序排序,如果为True,表示的是降序排列

  • sort 与 sorted 区别:

sort 是应用在 list 上的方法,sorted 可以对所有可迭代的对象进行排序操作。
list 的 sort 方法返回的是对已经存在的列表进行操作,而内建函数 sorted 方法返回的是一个新的 list,而不是在原来的基础上进行的操作。

实例

  • 使用reverse


    image.png
  • 使用key方法
    key是一个方法,默认值是None,用来指定具体的排序算法;sorted对可迭代对象的每个元素使用key算法后再排序,返回一个排序后的可迭代对象。

# 按年龄排序,以列表元素tuple的第3个索引排序,升序排序
students=[('john', 'A', 15), ('jane', 'B', 12), ('dave', 'B', 10)]
#使用lambda表达式    
print(sorted(students,key=lambda s:s[2]))
print(sorted(students,key=lambda s:s[2],reverse = True)) #降序排列
  • 输出结果

[('dave', 'B', 10), ('jane', 'B', 12), ('john', 'A', 15)]
[('john', 'A', 15), ('jane', 'B', 12), ('dave', 'B', 10)]

# 字符转换成小写后再排序,'a'和'A'值一样
a = ['a','s','d','X','D','U','H','G','E','s','d','a','s']

print(sorted(a, key = str.lower))
#['a', 'a', 'd', 'D', 'd', 'E', 'G', 'H', 's', 's', 's', 'U', 'X']
#将names的内容按照每个元素的倒叙的排列顺序进行排列
names = ['Tom','Jerry','Spike','Tyke']
def get_key(name):
    return name[::-1]

L = sorted(names,key = get_key)
print(L)#['Spike', 'Tyke', 'Tom', 'Jerry']
24. 闭包和装饰器
  • 闭包(closure)
    在嵌套函数中引用了自由变量的函数.这个自由变量就是外层嵌套函数中的变量(非全局变量).
  • 闭包必须满足三个条件

1> 必须有嵌套函数
2> 内层嵌套函数必须引用外层函数的变量.这个变量就是自由变量
3>外层函数的返回值必须是内层函数

  • 作用

嵌套的内层函数可以使用外层函数中的局部变量,即使外层函数返回了,或者外层函数被删除了,内层函数依然可以使用外层函数的那个变量.

  • 一个简单的闭包的示例
# 闭包,fn使用了变量y并且外层函数make_power的返回值是fn(内层函数)
# 这个闭包可以实现x的y次方
def make_power(y):
    #自右变量就是y,当函数make_power返回后,fn()依旧可以使用y的值
    def fn(x):
        return x ** y
    return fn

#假如让起实现平方的功能
f2 = make_power(2)
# 求某个数的平方
print("5的平方是:",f2(5))
#求立方的功能
f3 = make_power(3)
#求某个数的立方
print("5的立方是:",f3(5))
  • 闭包自由变量的分析
def fun_closule(y):
    """闭包的作用: 当外部函数返回了, 外部函数的局部变量还可以被内部函数引用"""
    print ('id(num):{}'.format(id(y)))

    def tmp(x):
        return x * y

    print ('id(tmp): {}'.format(repr(tmp)))
    return tmp

if __name__ == '__main__':
    closule = fun_closule(4)

    print ('id(closule)', repr(closule))

    #当删除了fun_closule对象后, 外部参数还可以被内部函数引用.
    del fun_closule
    print (closule(2))
  • 打印结果

id(num):10919520
id(tmp): .tmp at 0x7fa23501e730>
id(closule) .tmp at 0x7fa23501e730>
8

  • 分析:
    从结果可以看出,当fun_closule(4) 执行后, 创建和返回了 closule 这个函数对象,内存地址是0x7fa23501e730,
    并且发现tmp内部函数和它的内存地址相同,即closule只是这个函数对象的一个引用。

  • 闭包的应用 (装饰器)

描述

装饰器是一个函数,它用来包装另外一个函数.使得被装饰的函数在不改变原来代码的情况下添加新的功能.
装饰器的概念首先要明白两点:
1> 装饰器函数
2> 被装饰的函数
装饰器函数是用被装饰的函数作为参数来实现的.将被装饰的函数带入到装饰器函数得到的返回值就是装饰过后的函数.

# 装饰器函数.以被装饰的函数为参数,返回内层函数.
#在内层函数内可以实现对被装饰的函数的功能的添加
def mydeco(func):
    def funcDeco():
        #原来函数的功能
        func()
        print("装饰器函数funcDeco()被调用了")
    return funcDeco
# myfunc()函数前面加了装饰器,相当于是被装饰的函数的绑定对象改变了.
# 相当于是调用了如下代码:
# myfunc = mydeco(myfunc)
# 将被装饰的函数作为参数传给装饰器函数,然后重新绑定了装饰器函数的返回值
@mydeco
def myfunc():
    print("被装饰函数myfunc()被调用")

# myfunc = mydeco(myfunc) 这样的写法可以用装饰器来代替

myfunc() # 这里实际的调用的是funcDeco; myfunc经过装饰之后,已经指向了funcDeco
  • 下面通过示例演示装饰器的好处
1.一个初始函数
import time
def func():
    print("hello")
    time.sleep(1)
    print("world")
2.如果想要记录这个函数的执行时间,最初始的方法是入侵到原来的函数进行修改
import time
# 计算一个函数的运行的时间,最暴力的方法
def func():
    startTime = time.time()

    print("hello")
    time.sleep(1)
    print("world")

    endTime = time.time()

    seconds = endTime - startTime
    print("函数运行了{}秒".format(seconds))

if __name__ == '__main__':
    func()
3.如果想不侵入原来代码,可以将原来的函数作为参数放入另外一个函数中.
import time
#不改变原函数的代码的情况下统计函数执行所需的时间
def myfunc():
    print("hello")
    time.sleep(1)
    print("world")

#不改变原来的函数功能,但是每次都要执行该函数
def deco(func):
    startTime = time.time()
    # 运行函数
    func()
    endTime = time.time()

    seconds = endTime - startTime
    print("func()执行了{}秒".format(seconds))

if __name__ == '__main__':
    f = myfunc;
    #这里要统计时间的时候,每次都要调用deco()函数
    deco(f)
  • 这样也有一个问题,就是每次要完成统计功能的时候都要调用deco()函数.
4.使用装饰器,既不改变原来函数的功能,又不需要重复调用deco()函数
# 既不需要入侵原函数,也不用重复调用
import time
def deco(func):
    def wrapper():
        startTime = time.time()
        func()
        endTime = time.time()
        print("程序执行了{}秒".format(endTime - startTime))

    return wrapper
    
#声明myfunc()是一个装饰器函数
@deco
def myfunc():
    print("Hello!")
    time.sleep(1)
    print("World!")

if __name__ == '__main__':
    f = myfunc #将myfunc赋值给f变量
    f();

这里的deco函数就是最原始的装饰器,它的参数是一个函数,然后返回值也是一个函数。其中作为参数的这个函数func()就在返回函数wrapper()的内部执行。然后在函数func()前面加上@deco,func()函数就相当于被注入了计时功能,现在只要调用func(),它就已经变身为“新的功能更多”的函数了。所以这里装饰器就像一个注入符号:有了它,拓展了原来函数的功能既不需要侵入函数内更改代码,也不需要重复执行原函数。

5.带有参数的装饰器
# 带有参数的装饰器
import time

def deco(func):
    def wrapper(a,b):
        startTime = time.time()
        func(a,b)
        endTime = time.time()
        seconds = (endTime - startTime)

        print("func()运行了{}秒".format(seconds))
    return wrapper

@deco
def func(a,b):
    print("hello,here is a func for add:")
    time.sleep(1)
    print("result is {}".format(a + b))

if __name__ == '__main__':
    f = func
    f(3,4)
6.带有多个不定参数的装饰器
#带有不定参数的装饰器
import time

def deco(func):
    def wrapper(*args,**kwargs):
        startTime = time.time()
        func(*args,**kwargs)
        endTime = time.time()

        seconds = endTime - startTime
        print("函数func()运行了{}秒".format(seconds))

    return wrapper

@deco
def func(a,b):
    print("hello,here is a func for add:")
    time.sleep(1)
    print("result is {}".format(a + b))

@deco
def func2(a,b,c):
    print("hello,here is func for add:")
    time.sleep(1)
    print("result is {}".format(a + b +c ))

if __name__ == '__main__':
    f = func
    func2(2,3,4)
    f(3,4)
7.如果要为函数添加多个功能,这时就需要为函数添加多个装饰器
# 多个装饰器
import time

def deco01(func):
    def wrapper(*args,**kwargs):
        print("this is deco01")
        startTime = time.time()
        func(*args,**kwargs)
        endTime = time.time()

        seconds = endTime - startTime
        print("函数的执行时间是:{}".format(seconds))

        print("deco01 end here")
    return wrapper


def deco02(func):
    def wrapper(*args,**kwargs):
        print("this is deco02")
        func(*args,**kwargs)

        print("deco02 end here")
    return wrapper


@deco01
@deco02
def func(a,b):
    print("hello,here is a func for add:")
    time.sleep(1)
    print("result is {}".format(a + b))

if __name__ == '__main__':
    f = func
    f(3,4)
25.python中有几种跳出双重循环的方法
  • 运用函数的return语句,把for循环封装为一个函数
def func():
    for i in range(5):
        for j in range(5):
            if(i == j == 2):
                return i,j

print(func())
  • 定义一个标志位,当内层循环结束的时候,同时结束外层循环
break_flag = False

for i in range(10):
    # 先判断标志位,是否要继续进行循环
    if break_flag:
        break;
    for j in range(10):
        if(i == j == 2):
            # 内层循环更改标志位的值,通知外层循环可以终止
            break_flag = True
            print(i,j)
            break;
        else:
            print(i,j)
26.python3中的for-else的用法
  • 用 break 关键字终止当前循环就不会执行当前的 else 语句,而使用 continue 关键字快速进入下一轮循环,或者没有使用其他关键字,循环的正常结束后,就会触发 else 语句。


    image.png
27.函数的参数传递
  • 大体上分为三种(位置传参和关键字传参以及综合传参)
    位置传参又包含普通位置传参和序列传参(也是位置传参的一种)
    关键字传参又包含普通的关键字传参和字典传参
    综合传参是以上传参的方式混合使用
1.位置传参(实参和形参按照对应的位置进行传参)
#位置传参
def myfun(a,b,c):
    print('a = ',a)
    print('b = ',b)
    print('c = ',c)

myfun(1,,2,3) #形参和实参按照位置进行传参
2.序列传参(将实参序列按照*进行拆解,然后按照对应的位置进行传参)
#序列传参(将序列)

def func(a,b,c):
    print("a = ",a,end=" ")
    print("b = ",b,end=" ")
    print("c = ",c,end=" ")


lst = [1,2,3] #列表序列
s = "xyz" #String序列
t = (4,5,6) #元组序列
st = {2,3,4} #集合序列

func(*lst)
func(*s)
func(*t)
func(*st)
3.关键字传参(按照形参的名称对形参进行赋值,实参和形参一一进行匹配)
# 此示例示意关键字传参
def myfun(a,b,c):
    print("a = ",a)
    print("b = ",b)
    print("c = ",c)

myfun(b = 2,c = 3, a = 1)
myfun(c = 222,a = 1111,b = 333) #关键字传参不要求传递顺序
# myfun(a = 1,b = 2) 错误,参数不能缺少
# myfun(a = 1,b = 2,a = 3) 错误,参数必须一一对应
4.字典传参(是指实参为字典,将字典用**进行拆分后按照关键字传参的方式)
  • 说明

1> 字典的键名和形参名必须一致,字典的键名要在形参当中
2>字典的键名必须为字符串

# 此示例示意字典关键字传参

def func(a,b,c):
    print('a = ',a)
    print('b = ',b)
    print('c = ',c)

d = {'a':111,'c':333,'b':222}
func(**d) #等同于func(a = 111,c = 333,b = 222)

# 以下是错误的写法
# d2 = {1:'一','c':333,'b':222}
# func(**d2)
5.函数的综合传参:
  • 函数的传参方式在能够确定形参能够唯一匹配到当前实参的情况下可以任意的组合.
  • 要求:

位置传参在前,关键字传参在后.

# 函数的组合传参

def myfunc(a,b,c):
    print("a = ",a)
    print("b = ",b)
    print("c = ",c)

myfunc(1,c = 3,b = 2) #正确
# myfunc(b =  2,a = 1,3) #错误,关键字传参必须在位置传参的后面
myfunc(100,*[200,300]) #正确,前面是位置传参,后面是星号序列传参
myfunc(*"AB",300)#正确,前面是星号序列传参,位置传参,后面也是位置传参
myfunc(*[100],c = 300, b = 200) #正确,
  • 列表推导式 + filter + lambda 表达式实现数据列表的奇数和偶数分离
# 创建一个列表存放输入的数据,然后将数据按奇数和偶数分离成两个列表,返回给主函数

def get_number_lst():
    # 存放输入的数据列表,这里我们直接生成
    L = [x for x in range(20)]
    # 将这个列表拆分成奇数和偶数列表,filter返回的是一个可迭代对象
    odds = [x for x in filter(lambda x : x % 2 == 0,L)]
    evens = [x for x in filter(lambda x : x % 2 != 0,L)]

    return odds,evens
if __name__ == '__main__':
    odds,evens = get_number_lst()
    print("奇数是:",odds)
    print("偶数是:",evens)
6.函数的缺省参数
  • def 函数名(形参1=默认值1,形参2=默认值2,...)

1> 调用的时候可以不提供参数,使用默认的缺省参数就可.
2>缺省参数必须从右到左边依次存在,如果一个参数是缺省参数,则它的右边必须全部是缺省参数.
右边可以有可变参数,命名关键字参数,字典双星参数.
3>缺省参数可以有1个或多个,甚至可以全部是缺省参数.

# 缺省参数的使用

def info(name,age = 1,address = "不详")
    print(name,"今年",age,"岁, 住在:",address)

# info() 出错,至少要提供一个实参给name绑定
info('小李')
info('tarena',15)
info('小魏',3,'北京市朝阳区')
7.位置形参
  • def 函数名(形参1,形参2,....)
8.星号元组形参
  • def 函数名(*args):

*收集多余的位置传参.

  • 写一个函数可以接收n个参数,然后返回这些参数的和
def mysum(*args):
    # args实际上是一个元组
    return sum(args)

print(mysum(1,2,3))
print(mysum(4,3,2,3,5))
9.命名关键字形参
  • def 函数名(,形参1,形参2): 或是 def 函数名(args,形参1,形参2)

作用:强制*后面的参数必须是关键字传参.字典传参也是关键字传参的一种

def fa(a, b, *, c, d):
    '''强制c,d必须用关键字传参 '''
    print(a, b, c, d)

fa(1, 2, d=400, c=300)  # 对的


def fb(a, b, *args, c, d):
    print(a, b, args, c, d)

fb(1, 2, 3, 4, d=400, c=200)
fb(1, 2, 3, 4, 5, **{'d': 400, 'c': 300})

# 问题:
# fb(1,2,3,4, c=400, d=300, e=500)  # 出错,e是多余的

# fa(1, 2, 3, 4)  # 错的
10.双星号字典传参
  • def 函数名(**字典形参名):
    作用: 收集多余的关键字传参
# 双星号字典形参的用法

def fa(**kwargs):
    ''' kwargs是一个字典,里面用键值对的方式存放了参数名称和对应的值
        作用就是收集多余的关键字参数
    '''
    print("多余的关键字传参的个数是:",len(kwargs))
    print("kwargs = ",kwargs)

fa(a = 10,b = 20,c = 30)
# fa(10,a = 10,b = 20,c = 30)错误,没有位置形参
# 多余的关键字传参的个数是: 3
# kwargs =  {'b': 20, 'c': 30, 'a': 10}


# *args是星号元组传参,会收集前面n个位置传的形参,a必须是命名关键字形参.
# **kwargs负责收集后面的命名关键字传参(b and c)
def fb(*args,a,**kwargs):
    print(args,a,kwargs)

fb(1,2,3, b = 30,c = 30,a = 10)
#(1, 2, 3) 10 {'b': 30, 'c': 30}
  • 注意:
    python中参数传递的一般顺序是:
    位置传参 > 默认参数 > 星号元组传参 > 命名关键字传参 > 双星号字典传参
28.print()参数详解
  • print的原型
    print(*values,sep = ' ',end = '\n',file = sys.stdout,flush = false)
    *values 表示要打印出输出的各个数据
    sep表示各个数据用什么分隔,中间默认使用
    end表示的是用什么结束,默认是换行.
    file表示的内容输出到哪里?默认是终端
    flush是否马上清空缓存
29.Python中的模块学习
  • 模块(module)概念

Python中的模块是一个以.py结尾的文件,里面包含了Python的对象定义和语句定义.
使用模块,可以让我们的代码的逻辑更加的清晰,使得代码的书写更加的规范.我们可以将我们的类
函数,语句,变量定义到一个模块当中,同时也可以使得代码的复用更加的简单.

  • 模块的分类
模块名称 使用方式
内置模块(builtins) 在解析器的内部就可以直接使用
标准库模块 安装python时已经安装直接可以使用
第三方模块 需要自己安装之后才可以使用
用户编写的模块 需要自己手动导入才可以使用
  • 模块的导入
模块导入语句 示例 作用 属性用法
import module [as m1],.. import math 将一个模块整体导入到当前模块 math.abs(-1)
from module import 模块属性名 from math import sin 导入模块的1个或多个属性 math.sin(2)
from module import * from time import * 将模块的所有属性导入 sleep(2)

你可能感兴趣的:(Python3基础知识(一))