扩大
缩小
人生本来就短暂,为什么还要栽培苦涩。
返回顶部

python基础 :函数 装饰器,迭代器,面向过程编程

目录

函数 装饰器,迭代器,面向过程编程

1、什么是函数?

def 函数名()

参数:

参数:

在函数的定义阶段,写在括号中变量名就是形参

实参:

在函数的调用阶段,写在括号中的具体的值就是实参

是在调用函数的时候生效,函数执行结束关系解除

注释

1、要写当前函数具体的功能
2、解释当前函数参数作用
3、解释当前函数返回值的特点
函数体代码:函数的具体功能

函数的返回值:

1、不写返回值

ython中所有的函数都有返回值,不写默认为None

2、写return,返回一个值

1、return
函数体代码结束的标识,默认None
2、return None
函数体代码结束的标识,默认None
3、return 值
可以是python的任意数据类型

3、写return,返回多个值

return 值1,值2,值3...
以逗号隔开多个值,可以返回多个任意类型的值,最后以元组的形式返回给调用者

return [值1,值2,值3...]
                自己指定返回的数据类型

                   def index(x,y,z):
                        return x,y,z


                   a,*_ = index(1,2,3)

                   print(a,*_)

4、参数的详细描述

1、位置参数

1、位置参数
在函数定义阶段按照顺序从左到右书写的变量名就叫位置形参

在函数调用阶段按照顺序从左到右书写的具体的值就叫位置实参

位置参数定义之后一定要传递参数

2、关键字参数

在函数调用阶段,以key=value形式进行,关键子参数

3、默认值参数

在函数定义阶段提前给形参赋值的操作就叫默认值参数

4、可变长参数

*
**

* 在函数定义阶段:接收所有溢出的位置参数,将接受的值以元组的形式传入* 后面的变量中
* 在函数调用阶段:将列表、元组、字符串、集合等可以使用的for循环的容器类型打散成位位置参数

** 在函数定义阶段:接收所有溢出的关键字参数,将接受的值以字典的形式传入** 后面的变量中
** 在函数调用阶段:将字典打散成关键字参数传入形参

5、定义函数的三种形式

1、无参函数:

def index():
    print("from index")

2、有参函数:

def func(x,y):
    print(x,y)

3、空函数

def register():
     pass
def login():
	pass
                        。。。

命名关键字参数

# 定义在* 和**之间
            # 在给命名关键字传值的时候一定要以关键字形式传递

            def index(x, y, z, *args, a=1, b, **kwargs):
                print(x, y, z)
                print(args)
                print(a, b)
                print(kwargs)


            index(1, 2, 3, 354353, 4342, 3213123, a=111, b=222, c=333, d=444)


函数对象

1.函数对象什么?

函数的名字就是函数对象,函数名指向的是函数的内存地址。

函数对象四大特征:

1.函数名可以被的引用

def index()
	print('from index')
a = index
a()  #直接加括号调用

from index

2.可以当作参数传给一个函数

def func():
    print('123')
def func1(new):
    new()
func1(func)

123

3.可以当作一个返回值。

def func():
    print('123')
    return func

msg = func()
print(msg)
msg()

123
<function func at 0x000002B054691F78>
123

4.可以当作容器类型的元素。

dic = {}

def abc():
    print('oldboy')

dic['a'] = abc

print(dic)

res= dic['a']
res()

{'a': <function abc at 0x00000284A3D11EE8>}
oldboy

列:

def register():
    print('register')


def login():
    print('login')


def shopping():
    print('shopping')


def pay():
    print('pay')


func_dic = {
    '1': register,
    '2': login,
    '3': shopping,
    '4': pay
}

def main():
    while True:
        print("""
            1、注册
            2、登录
            3、购物
            4、付款
            5、退出
        """)
        choice = input("请输入对应的编号:").strip()
        if choice == '5':
            break
        if choice not in func_dic:
            continue
        else:
            func_dic[choice]()

main()

函数对象的应用:

补充--》可以优雅地取代if分支

函数的嵌套

函数嵌套定义: 让内层函数封闭起来,不让外部直接调用。

函数的嵌套调用:在函数内调用函数

def f1():
    def f2():
        print('from f2')
    f2()

f1()
from f2

# 函数的嵌套定义:
def index():    
	def home():        
		print("from home")    
	home()
index()

名称空间

什么是名称空间?

用来存放名字的,名称空间是一个在内存中的空间。

名称空间的分类?

1.内置名称空间:

python提前给你的定义完的名字,就是存在内置名称空间,   简称:存放内置方法

2.全局名称空间

除了内置和局部就是全局

存放于文件级别的名字,就是全局名称空间
if while for 内部定义的名字执行之后都存放于全局名称空间

3.局部名称空间

函数内部的定义的变量/函数

函数内部定义的所有名字都是存放与当前函数的内置名称空间

生命周期:

1、内置名称空间

在python解释器启动的时候生效,关闭解释器的时候失效

2、全局名称空间

当你启动当前这个py文件的时候生效,当前页面代码执行结束之后失效

3、局部名称空间

当你调用当前函数时生效,函数体最后一行代码执行结束就失效名称空间的查找顺序:

名称空间的查找顺序:内置 --》 全局 --》 局部
				局部:局部 > 全局 > 内置
    			全局:全局 > 内置  # 内置再找不到就报错

函数内部使用的名字,在定义阶段已经规定死了,与你的调用位置无关

作用域的分类

全局作用域

全局可以调用的名字就存在于全局作用域
内置名称空间+全局名称空间

局部作用域

局部可以调用的名字就存放与局部作用域局部名称空间

需要注意的是:作用域关系在函数定义阶段就固定死了,与函数的调用无关。

global

局部的可以修改全局的

修改全局作用域中的变量。
x = 1

def f1():
    x = 2

    def f2():
        #         global x  # 修改全局
        x = 3
    f2()

f1()
print(x)

#  1

只有可变类型可以在局部修改外部变量的值

nonlocal

局部的修改外层局部的

x = 1

def f1():
    x = 2

    def f2():
        #         nonlocal x
        x = 3

    f2()
    print(x)


f1()
2

x = 1

def f1():
    x = 2

    def f2():
        nonlocal x
        x = 3

    f2()
    print(x)

f1()
3

命名关键字参数

定义在* 和**之间# 在给命名关键字传值的时候一定要以关键字形式传递# 关键字参数一定不能放在位置参数前面

1.可变长参数

可变长参数:在调用函数时,参入的参数个数可以不固定。

调用函数时,传值的方式莫非两种,一种是位置实参,另一种是关键字实参,因此形参也必须的有两种解决方式,以此来分别接收溢出的位置实参(*)也关键字实参(**)

一.可变长形参之*

形参中的会将溢出的位置实参全部接收,然后存储元组的形式,然后把元组赋值给后的参数。需要注意的是:*后的参数名约定俗成为args。

二 .可变长实参之*

实参中的会将后参数的值循环取出,达三成位置实参。以后但凡碰到实参中带的,他就是位置实参,应该马上打散成位置实参去看。

三. 可变长实参之**

形参中的** 会将溢出的关键字实参全部接收,然后存储字典的形式,然后把字典赋值给** 后的参数。需要注意的是:**后的参数名约定俗成为kwargs。

def func(**kwargs):
    print(kwargs)
func(a=5)  #{"a":5}

四 .可变长实参之**

实参中的会将** 后参数的值循环取出,打散成关键字实参。以后但凡碰到实参中带**的,它就是关键字实参,应该马上打散成关键字实参去看。

五. 关键字形参

现在有一个需求,函数的使用者必须按照关键字实参传。

def register(x, y, **kwargs):
    if 'name' not in kwargs or 'age' not in kwargs:
        print('用户名和年龄必须使用关键字的形式传值')
        return
    print(kwargs['name'])
    print(kwargs['age'])
register(1, 2, name='liangjing', age=20)
#liangjing
# 20

命名关键字形参:在函数定义阶段,*后面的参数都是命名关键字参数。

特点:在传值时,必须按照key=value的方式传值,并且key必须命名关键字参数的指定的参数名。

闭包函数:

闭包函数是

: 函数对象、函数嵌套、名称空间与作用域的结合体。

注意:

1.必须要在函数内定义
- 2.可以引用外层函数的名字
		def outer(x):
            def inner():
                print(x)
                pass
            return inner
        x = 10
        inner = outer(x)
        inner()

闭包函数的作用

- 闭包函数的作用:
1.为了装饰器作准备的。
2.减少代码冗余

装饰器:

1.什么是装饰器?

在不修改被装饰对象的源代码与调用方式的前提下,为其添加新的功能。

2.定义装饰器:

- 不修改被装饰对象的源代码
- 不修改被装饰对象的调用方式


- 被装饰对象 ---》 需要添加新功能的  函数
            - 装饰器 ---> 为需要添加新功能的函数添加功能  函数
    # 模板
    		def wrapper(func):  # func函数对象 ---> 被装饰对象
                # *args, **kwargs用于接收被装饰对象的参数
                def inner(*args, **kwargs):
                    # 在调用被装饰对象前 添加新功能
                    res = func(*args, **kwargs)

                    # 在调用被装饰对象后 添加新功能
                    return res
                return inner

3.统计时间认证

import time
def download_movie():
	print('开始下载')
	time.sleep(5)
	print('下载结束')
	return 'cang老师.mp4'
def time_record(func):
	def inner(*args, **kwargs):
		start_time = time.time()  # 获取当前时间戳
		res = func(*args, **kwargs)  # func --> download_movie
		end_time = time.time()
		print(end_time - start_time)
		return res
    return inner

4.装饰器的语法糖

语法糖是python内置的,可以引用所有的装饰器

@: 就是语法糖

- 如何使用:
	@装饰器
     def 被装饰对象():
     	pass

注意: 使用语法糖必须遵循,装饰器的定义必须要在被装饰对象之上。

有参装饰器模板

def user_info(user):
    def wrapper(func):
        def inner(*args,**kwargs):
            res = func(*args,**kwargs)
            return res
        return inner
    return wrapper

无参装饰器模板

def wrapper(func):
	def inner(*args,**kwargs):
		res = func(*args,**kwargs)
        # 在被装饰对象前调用添加功能
		return res
	return inner

1.叠加装饰器

 1.叠加装饰器
        同一个被装饰对象可以叠加装饰多个装饰器
        装饰顺序:
            由下往上装饰

        执行顺序:
            由上往下执行

2.有参装饰器

本质上就是在无参装饰器上套了一个外层函数,
无参装饰器可以引用外层函数的名字。

应用:用户权限的认证

无参装饰器与有参装饰器的使用

@无参装饰器
- @有参装饰器('参数1', '参数2')  ---》 调用有参装饰器会得到一个无参装饰器

3.迭代器

迭代

迭代: 重复迭代的过程,每一次都是基于上一次的结果而来的。

迭代器:

迭代取值的工具。

可迭代对象:

凡是内部有__iter__()方法对象。
            list, str, tuple, dict, set, f

获取迭代器:

list1 = [1, 2, 3]
# 调用__iter__()会得到一个返回值,该返回值是一个迭代器对象。
iter_list = list1.__iter__()

如何通过迭代器取值

每一次调用__next__()都会从迭代器中取出一个值
iter_list.__next__()
注意: 取到最后一个时,若值没有,则会报错。

捕获异常

while True:
	try:
		print(iter_list.__next__())

	except StopIteration:
		break

for循环原理

# in: 会将可迭代对象自动调用__iter__()变成迭代器对象。
for i in 可迭代对象:
	# 会自定帮你调用__next__
     print(i)
# for循环内部也会有一个捕获异常机制,一旦遇到异常也会停止取值。

迭代器的优缺点:

优点:
1.提供了一种不依赖于索引的取值方式
2.节省内存

缺点:
1.指定取某个值麻烦,每一次取值都要从第一个开始查找补充: 
2.不能通过len计算长度

.生成器

生成的工具
生成器是一个自定义的迭代器。

yield:方法

- yield必须在函数内部定义
- yield可以保存函数的暂停状态
yield的效果与return雷同

生成器 ---》 生成器对象
迭代器 ---》 迭代器对象

凡是函数内部有yield,在调用函数时不会执行函数体代码,会返回一个生成器对象,本质上是一个迭代器。

return与yield的区别:

相同点:
    都可以返回无限制的值。

不同点:
    yield可以返回多次值,return只能返回一次
    
迭代器对象.__next__()  ==   next(迭代器对象)

.面向过程编程

核心是 “过程” 二字, 过程指的是解决问题的步骤,即先干什么再干什么。
基于该编程思想编写程序,就好在设计一条流水线,一种机械式的思维方式。


 # 设计编写程序的步骤:
注册功能: ----> 用户合法性的校验 ----> 拼接用户数据格式---->
保存到文件中。

优缺点

        优点:
            复杂的流程化,进而简单化

        缺点:
            牵一发而动全身,扩展性差


.三元表达式

成立返回的结果  if 判断条件 else 不成立返回的结果

列表生成式

- 生成一个列表
# for循环了几次,列表中就有几个值
l = [line for line in 可迭代对象]
[任意的值 for line in 可迭代对象]
print(l)  # list


生成器生成式

- 生成一个生成器对象 ---》 生成一个迭代器对象
tuple = ()
(line for line in 可迭代对象)
g = (任意值 for line in 可迭代对象)
print(g)  # 生成器对象

列表生成式与生成器生成式的区别

        - 列表生成式
            优点:
                可以依赖于索引取值,取值方便

            缺点:
                在数据量过大时浪费资源

        - 生成器生成式
            优点:
                在数据量过大时节省资源

            缺点:
                不依赖于索引取值,取值麻烦。


匿名函数

匿名函数

匿名函数:没有名字的函数:
            lambda x: x + x  # ---> 内存地址
                # def (x):
                #    return x + x
            名字 = lambda x: x + x
            名字()  # 匿名---》 有名  ---》 还不如直接通过def 来定义。

有名字的函数:

def 名字(x):  # 名字 ---> 内存地址
    pass

注意

函数名字 + ()调用,执行函数体代码

匿名函数没有名字,不能单独使用。

匿名的应用:

配合内置函数一起使用。

内置函数

max: 获取可迭代对象中最大值
min: 获取可迭代对象中最小值
sorted: 对可迭代对象中的数据进行排序
   默认是: 升序
   reverse=True: 降序

map,reduce,filter

map: 映射
map(函数地址, 可迭代对象)
将可迭代对象中的值遍历取出,并且按照指定的规则映射出新的map对象。
调用返回的是map对象。

reduce: 合并
reduce(函数地址, 可迭代对象, 初始值)
将可迭代对象中的值两两合并,并且可以设置初始值
return 合并后的值

filter: 过滤
filter(函数地址, 可迭代对象)
将可迭代对象中的值遍历取出,然后通过判断,若条件成立 “过滤获取” 对应的值。
并将获取的值放到一个filter对象中。
return filter对象

函数递归

函数重复 “直接或间接” 调用函数本身,会进入死循环。

        缺点:
            1.毫无意义
            2.内存溢出


有意义的递归:
- 递推:
指的是重复地执行, 每一次执行都要拿到一个更接近于结果的结果,
                递推必要有一个终止条件。

- 回溯:
当递推找到一个终止条件后,开始一步一步往上回溯,最终得到一个结果。

            age(5) = age(4) + 2
            age(4) = age(3) + 2
            age(3) = age(2) + 2
            age(2) = age(1) + 2
            age(1) = 80

posted @ 2019-11-28 09:42  晴天sky  阅读(141)  评论(0编辑  收藏  举报
左边日期 搜索的制定样式