python学习基础知识2

7月28号小结

目录

函数

函数的参数

全局变量和局部变量

迭代器和生成器

匿名函数

递归调用

高阶函数

装饰器

函数

函数的作用:将面向过程的代码变得模块化,能够实现重复调用。

以前使用过的函数有:input、print、type等。

函数的语法
  1. 使用def关键字定义函数,def后面跟函数名(本质:变量)、圆括号和冒号。

  2. 圆括号中放形参(形参是向函数内部传参的变量)

  3. 函数内部代码块通常第一行写多行注释,作为解释函数作用的注释。

  4. 代码块结束以后使用return,将函数内部产生的结果返回到函数外部。

  5. 函数定义完,使用函数时叫做调用函数,如何调用?

    函数名后面跟圆括号

  6. 调用函数时需要在圆括号中写实参传递给形参。

实例

def rangeSum(start, end):
    """计算某个范围的和"""
    sum = 0
    for i in range(start, end + 1):
        sum += i
    print(sum)
    return sum
    # print('fd')


# 调用函数
print(rangeSum(1, 100))
print(rangeSum(1, 1001))
  • 函数:可以降低代码段冗余度,也可以给代码阅读者更清晰的思路(一个函数代表一个功能)。
return的作用
  1. 能够将函数内部产生的结果返回到函数外部。
  2. 结束函数的执行。
  3. return后面可以放任何东西。(比如:变量(一个或者多个),变量与变量的运算,字符串等其他东西)

实例:将判断一个年份是否是闰年的代码封装成函数

def is_leap_year(year):
    """判断是否是闰年"""
    if (year % 4 == 0 and year % 100 != 0) or year % 400 == 0:
        return '闰年'
    else:
        return '平年'


# for i in range(1, 2023):
#     print(is_leap_year(i))

print(is_leap_year(2005))

总结

封装函数(自定义函数)在不改变原有代码执行逻辑、顺序的基础上做封装。

函数执行的顺序

从调用函数开始执行,函数定义时,程序不参与1执行。

例子(在Python Tutor中进行运行,去一步步看程序执行的过程)

a = 0
def is_leap_year(year):
    """判断是否是闰年"""
    if (year % 4 == 0 and year % 100 != 0) or year % 400 == 0:
        return '闰年'
    else:
        return '平年'


# for i in range(1, 2023):
#     print(is_leap_year(i))

print(is_leap_year(2005))

函数的参数

  1. 默认值参数

    自定义一个函数,函数的功能是计算某个范围中整数的和,默认计算1-100的和或者也可以自定义范围计算和

    def rangeSum(start=1, end=100):
        sum = 0
        for i in range(start, end + 1):
            sum += i
        return sum
    
    
    print(rangeSum())
    print(rangeSum(200, 1000))
    
  2. 位置参数

    形参和实参之间的顺序要一一对应

    print(rangeSum(100, 1000))
    print('|', '\t', 1, 2, 3)
    
  3. 关键字参数

形参和实参之间的对应关系

关键字参数传参方式:

调用函数时:rangeSum(形参1 = 值1, 形参2 = 值2)

print(rangeSum(start=100, end=1000))
print(rangeSum(end=1000, start=100))

那个形参等于什么值,相当于在调用函数时提前规定好了。

  1. 位置参数和关键字参数混用

    位置参数必须在前面,关键字参数在后面。

    def numSum(x, y, z):
        print(f'x:{x},y:{y},z:{z}')
        return x + y + z
    
    
    print(numSum(10, 20, z=30))
    print(numSum(10, z=50, y=20))
    # print(numSum(z=10, y=50, 20)) # ---> 错误:positional argument follows keyword argument
    
  2. 不定长参数(带*的变量)

    不定长参数包含:*args,**kwargs

    一个*不定长参数必须放在两个**的不定长参数前面

    def selfTest(*args, **kwargs):
        # pass不参与程序执行,仅仅是保证代码结构的完整性
        # pass
        print(args, kwargs)
    selfTest(1, 2, 2, 4, x=1, y=2, z=3)
    

    传参:一个*不定长参数只能接收"位置参数";两个**的不定长参数只能接收"关键字参数"。

    为什么使用不定长参数?

    不定长参数可以一次性传入N个参数(N>=0),可以解决实参和形参数量不一致的问题。

    • *args接受位置参数后将所有数据转换成一个元组。
    • **kwargs接受关键字参数后将所有数据转换成一个字典。
  3. 参数指定数据类型

    1. 给形参赋默认值,默认值时什么数据类型等于传参的数据类型。
    2. 直接以"冒号数据类型(形参: int)"的形式创建形参。
    3. 在定义函数时使用"-> int"表明此函数返回什么数据类型。
    def rangeSum(start=1, end=100) -> int:
        sum = 0
        for i in range(start, end + 1):
            sum += i
        return sum
    
    
    rangeSum()
    # ----------------------------
    
    
    def rangeSum(start: int, end: int):
        sum = 0
        for i in range(start, end + 1):
            sum += i
        return sum
    
    
    rangeSum(10, 100)
    

全局变量和局部变量

按照作用域不同可以将变量分为全局变量和局部变量。

  1. 全局变量
  • 从变量定义开始到程序结束,整个范围都是全局变量的作用域。
  1. 局部变量
  • 在函数或类中创建的变量,从函数或类中变量定义开始导函数或类结束,此方位是局部变量的作用域。
a = 0


def selfTest():
    print(a)
    b = 1
    print(b)


selfTest()
print(a)
# print(b)    # NameError:name 'b' is not defined
  1. 局部变量的作用或意义?

    局部变量创建函数或类中,当函数或类被调用时局部变量才开始创建,当函数或类结束时,局部变量被销毁。

    global:在函数内部修改全局变量。

    nonlocal:在函数A的函数B中修改函数A的变量。

    # global和nonlocal
    x = 100
    
    
    def func1(x):
        print(x)  # 100
        x = 0
        print(x)  # 0
    
    
    func1(x)
    print(x)  # 100
    
    # global:在函数内部修改全局变量
    """
    alobal 变量
    变量 = 值
    """
    y = 100
    
    
    def func2():
        global y
        y = 666
    
    
    func2()
    print(y)
    
    # nonlocal:在函数A的函数B中修改函数A的变量
    """
    nonlocal 变量
    变量 = 值
    """
    
    
    def A():
        z = 0
    
        def B():
            nonlocal z
            z = 6
    
        B()
        print(z)
    
    
    A()
    

迭代器和生成器

一、迭代

迭代在Python中就是属于可以做for循环遍历的对象,被叫做可迭代对象。

二、可迭代对象分为容器和迭代器两个,迭代器又有生成器分支。
三、迭代器

性质

  1. 使用print无法查看迭代器中的元素。
  2. 使用len方法也无法查看其中元素个数。
  3. 迭代器(iterator)
  4. 迭代器类似于数据结构中的队列(先进先出),迭代器中的元素被取出,迭代器即消失。
  5. 任何容器型数据类型都可以使用iter方法转为迭代器。
str1 = 'hello'
str1_iter = iter(str1)
print(str1_iter, type(str1_iter))
list1 = [1, 2, 3]
list1_iter = iter(list1)
print(list1_iter, type(list1_iter))
# print(len(list1_iter))    # TypeError: object of type 'list_iterator' has no len()
四、如何获取迭代器中的元素

方法一:for循环遍历

方法二:next():适用于取单个元素

print(next(str1_iter))    # 一次只取一个值
print(next(str1_iter))
for i in str1_iter:
    print(i)
五、迭代器能做什么?

全部元素被取出,迭代器消失,迭代器所占内存被释放,程序就可以减小内存占用。

六、生成器(generator)

性质

  1. 生成器是为了生成迭代器(生成就是迭代器,但是迭代器不一定是生成器)。
  2. 生成器是一个函数。
  3. 调用生成器函数时,函数不执行,只有在获取元素时生成器函数才执行。并且是获取一个元素才能够让生成器函数执行一次。
  4. 生成器函数返回内部结果使用yield来代替return(可以同时存在,但是没必要)
  5. yield执行几次,生成器就产生几个元素。
def myGener():
    print('123')
    yield 100
    yield 200
    if 100 > 200:
        yield 300
    return 1
    yield 400


f = myGener()
print(f)
print(next(f))
for i in f:
    print(i)
七、yield和return的区别
  1. return被触发,函数立即结束。yield不会结束函数的执行。
  2. return和yield都可以将函数的内部结构返回到外部。
  3. return和yield后面都是跟表达式。

练习:使用生成器创建Python001-Python999学号

def stu_gener(num):
    for n in range(1, num):
        yield f'Python{n:0>3d}'


fc = stu_gener(1000)
print(fc)
print(next(fc))
for _ in range(100):
    print(next(fc))
# for j in fc:
#     print(j)

# =======================
print(next(fc))

print('*' * 20)
# rjust的用法(字符串)
for l in range(1, 1000):
    print('Python' + f'{l}'.rjust(3, '0'))

匿名函数

一、概念

Python中有一个lambda表达式,lambda有匿名的意思,并且lambda表达式就是简化的函数,所以被叫做匿名函数。

二、理解

匿名函数和普通函数的关系理解为单分支结构和三目运算符的关系。

三、匿名函数在语法上就是由单一的严格限制的固定语法。在语义上是普通函数的语法糖。

语法糖(糖衣语法),是英国计算机学家提出的一个概念。语法糖就是对已经存在的语法的简化。

语法糖能提高代码的可读性,但是不会影响其功能。

案例:计算两个数字的和

def numSum(num1, num2):
    return num1 + num2


print(numSum(10, 20))
# -----------------------
numSum_lambda = lambda num1, num2: num1 + num2
print(numSum_lambda(10, 20))
  • 匿名函数的语法:

    函数名 = lambda 形参: 返回值

    函数名(实参)

练习:计算1-100的和(使用匿名函数)

def num_sum(start=1, end=100):
    n = 0
    for i in range(start, end + 1):
        n += i
    return n


total_lambda = lambda start, end: sum([i for i in range(start, end + 1)])
print(total_lambda(1, 100))

并不是所有的函数都可以转为匿名函数

练习:使用匿名函数判断年份是否是闰年

year_lambda = lambda year: '闰年' if year % 4 == 0 or year % 100 != 0 and year % 400 == 0 else '平年'
print(year_lambda(2000))

递归调用

一、递归

递归就是一种循环的思想。

函数之间是一个相互调用的过程,递归式对于函数来说的,但是递归是一种特殊的函数调用(自己调自己)。

二、迭代(递推)思想和递归思想

递推思想:斐波那契数列:根据已有的数据推算规律(正向的推算)。

递归思想:根据规律逆向推算。

三、递归虽然是循环的思想,但是要注意循环结束的条件,不然就陷入了死循环。

著名的计算机学家:迭代是人,递归是神。

例子:斐波那契数列

# 迭代(递推)思想
a = 1
b = 1
N = 9
for i in range(N - 2):
    mid = a + b
    a = b
    b = mid
print(b)


# 递归思想
def fib(n):
    if n == 1 or n == 2:
        return 1
    else:
        return fib(n - 1) + fib(n - 2)


print(fib(9))

解释递归思想的过程:

fib(9) = fib(8) + fib(7)
fib(8) = fib(7) + fib(6)
fib(7) = fib(6) + fib(5)
fib(6) = fib(5) + fib(4)
fib(5) = fib(4) + fib(3)
fib(4) = fib(3) + fib(2)
fib(3) = fib(2) + fib(1)

如何写出递归思想的代码:

  1. 知道最终结果的计算规律。
  2. 从需要算的结果向前推。
  3. 了解递归结束的条件。
  4. 学会自己调自己的方式。

递归练习:计算n的阶乘

def factorial(n):
    if n == 1:
        return 1
    else:
        return n * factorial(n - 1)


print(factorial(10))

注意

  1. 能使用循环解决的就能使用递归。

  2. 但是递归使用时需要谨慎,如果涉及计算量很大,有一个拓栈和压栈的过程,拓栈时容易内存溢出。

    :先进后出(的形式)

高阶函数

一、定义

将一个函数当作另一个函数的参数,叫做高阶函数。

print(max)    # <built-in function max>

例子

def func1():
    print('这是一个函数')


print(func1)
func1()
a = func1
a()


# 自定义函数相当于是定义了一个数据类型为function的变量


def func2(func):
    print('这是另一个函数')
    func()


func2(func1)
二、Python常用的高阶函数

max、min、sorted、map、reduce

maxmin:获取容器中最大(最小)的元素

nums = [10, 55, 67, 666, 900]
print(max(nums))
print(min(nums))

max(容器, key=函数):按照函数定义的方式获取容器中的最大值。

min同理

函数的要求:

  1. 函数有且只有一个形参。
  2. 必须有返回值。

案例:按照数字中个位数的大小取值。(找出哪个数字的个位数最大)

nums = [10, 55, 67, 666, 900]


def unitNum(num):
    return num % 10


print(max(nums, key=unitNum))
print(max(nums, key=lambda num: num % 10))
print(min(nums, key=unitNum))

sorted(容器,key=函数):按照函数指定的形式对容器中元素排序

函数的要求:

  1. 函数有且只有一个形参。
  2. 必须有返回值。
nums = [10, 55, 67, 666, 900]
print(sorted(nums, key=lambda num: num % 10))

reduce:根据传递的容器对容器中每个元素做累计。

reduce(函数,容器,初始值)

函数的要求:

  1. 函数要有两个形参。第一个形参开始指向初始值,然后再指向每次累积的结果。第二个形参指向容器中每个元素。
  2. 必须有返回值。
from functools import reduce

nums = [10, 55, 67, 666, 900]
# 对列表中的元素做累乘。
print(reduce(lambda total, num: total * num, nums, 1))
  • reduce和for循环对比:

    reduce性能明显不及for循环,但是从代码可读性(优雅的写法)reduce是更好的。

map():根据容器产生一个新的序列

map(函数,容器1,容器2,…容器n…)

函数的要求:

  1. 函数有N(容器数量)个形参。
  2. 必须有返回值。
  • map函数的结果是一个可迭代对象,可以将这个可迭代对象使用构造器语法转换为列表、元组、集合等容器

    names = ['小明', '小王', '小李']
    chinese = [90, 95, 80]
    english = [60, 70, 80]
    # {'name':'小明','chinese':90, 'english': 60}
    map_iter = map(lambda a, b, c: {'name': a, 'chinese': b, 'english': c}, names, chinese, english)
    print(map_iter)    # <map object at 0x000001998DF22700>
    # for i in map_iter:
    #     print(i)
    print(list(map_iter))
    

    案例:将列表[10, 5, 30, 100, 900, 666]中每个元素乘以2。

    nums = [10, 5, 30, 100, 900, 666]
    
    result = map(lambda num: num * 2, nums)
    print(result)
    print(list(result))
    print(tuple(result))
    
    # <map object at 0x7fe83809dd30>
    # [20, 10, 60, 200, 1800, 1332]
    # ()
    

装饰器

一、装饰器前提

一、Python中装饰器是为了从已经存在的函数体上添加新功能,但是不队员函数体做修改。

二、为什么函数能够被装饰?

  1. 函数能够作为参数传给另一个函数。
  2. 函数A还可以将函数B作为其返回值。
  3. 《流畅的Python》中说道:”Python在的函数是一等公民。“

案例一:函数能够作为参数传给另一个函数。

def func1(a, b):
    print('[函数func1]正在被执行')
    return a + b


def func2(func, c, d):
    print('[函数func2]正在执行')
    return func(c, d)


# 分别调用函数
print(func1(1, 2))
print(func2(func1, 1, 2))

案例二:函数内部还可以再创建函数。

def func3(a, b):
    print('[函数func3]正在执行')

    def func4():
        print('[函数func4]正在执行')
        return a + b

    print(func4())


func3(10, 20)

案例三:函数A还可以将函数B作为其返回值。

def A(a, b):
    print('[函数A]正在执行')

    def B(c):
        print('[函数B]正在执行')
        return a + b + c

    return B


B = A(10, 20)
print(B)
print(B(30))
二、无参装饰器

案例:在一个已经实现1-100的求和功能的函数上,外加功能进行性能测试。

import time


# 测试函数
def inner(func):
    def outer(*args, **kwargs):
        start1 = time.time()
        result = func(*args, **kwargs)
        end1 = time.time()
        print(f'程序执行花费{end1 - start1}秒')
        return result

    print(outer)
    return outer


# 功能函数
def numSum(start, end):
    total = 0
    for i in range(start, end + 1):
        total += i
    return total


numSum = inner(numSum)  # 函数numSum等于变量numSum传递给形参func,inner执行,先打印outer变量代表的函数,再将outer函数返回,重新给numSum赋值
print(numSum)  # 打印numSum,等价于打印outer
print(numSum(1, 100))  # 调用numSum等于调用outer变量等于调用outer函数


# 传参1和100,因为装饰器是具有通用性的,所以一个装饰器可以借用给任何函数,所有的函数传参不一定一致,所以使用不定长参数*args和**kwargs接受参数。
# 在outer函数内部有调用了func函数,func函数就是一开始的numSum,将传递的所有参数(*args,**kwargs)再传递给func函数,此时才开始真正的调用功能函数numSum
# 最终既能得到功能函数应该得到的结果,有能够测试成功功能函数的性能。

# 可以将测试函数inner写为语法糖的形式:@测试函数名


# 功能函数
@inner
def numSum1(start, end):
    total = 0
    for i in range(start, end + 1):
        total += i
    return total


print(numSum1(1, 50))

# 无参装饰器标准写法
import time


def inner(func):
    def outer(*args, **kwargs):
        start1 = time.time()
        result = func(*args, **kwargs)
        end1 = time.time()
        print(f'程序执行花费{end1 - start1}秒')
        return result

    return outer


@inner
def numSum1(start, end):
    total = 0
    for i in range(start, end + 1):
        total += i
    return total


print(numSum1(1, 100))
三、有参装饰器
  • 有参装饰器:可以在函数体执行功能时再多做验证(Web权限验证)

案例

def limit(kind):
    def inner(func):
        def outer(*args, **kwargs):
            result = func(*args, **kwargs)
            if result == '登陆成功':
                if kind == '会员':
                    return result, '尊敬的vvvvvvip用户'
                else:
                    return result, '感谢白嫖用户登录'
            else:
                return result

        return outer

    return inner


# 语法糖的参数是登陆账号时程序同时验证账号权限得到的结果
@limit('非会员')
def userLogin(username, pwd):
    if username == 'admin' and pwd == '123456':
        return '登陆成功'
    else:
        return '登录失败'


print(userLogin('admin', '123456'))
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值