函数

  •  1、它是什么?
  •  2、为什么要用它?
  •  3、怎么用?

函数

什么是函数?
  函数就是工具 为什么用函数?
  增强代码的可读性,解决代码重复 怎么用函数?
  函数分类:
    1,内置函数:Python提供的函数
    2,自定义函数:我们自己可以根据自己的需求封装一个函数

定义函数

1,先定义 后调用
  a.申请内存空间保存函数体代码
  b.将上述内存地址绑定函数名
  c.定义函数不会执行函数体代码,但会检测语法
#语法 def 函数名(参数1,参数2,参数3,...): '''注释''' 函数体 return 返回的值 2,调用
  a.通过函数名找到函数内存地址
  b.加括号就触发函数体代码执行
#定义阶段 def foo(): print('from foo') bar() def bar(): print('from bar') #调用阶段 foo()

定义函数的三种形式

#1、无参:应用场景仅仅只是执行一些操作,比如与用户交互,打印
def func()
#2、有参:需要根据外部传进来的参数,才能执行相应的逻辑,比如统计长度,求最大值最小值
def func(x,y)
#3、空函数:设计代码结构
def func():
  pass
#有参数
#定义阶段
def tell_tag(tag,n):
    print(tag*n)

#无参数
def tell_msg():
    print('hello world')

#调用阶段
tell_tag('*',12)
tell_msg()
tell_tag('*',12)

函数返回值

无return->None
return 1个值->返回1个值
return 逗号分隔多个值->元组

应用

#1、位置参数:按照从左到右的顺序定义的参数
        位置形参:必须传参数,多一个不行,少一个也不行
        位置实参:按照位置给形参传值,传入的值必须与形参位置一一对应
def func(x, y):
    print(x, y)


func(1, 2)
#2、关键字参数:按照key=value的形式定义的实参
        无需按照位置为形参传值
        注意的问题:
                1. 关键字实参必须在位置实参右边
                2. 对同一个形参不能重复传值
          3. 可以不用按照顺序传参
def func(**kwargs):
    print(kwargs)


func(y=2, a=1)
#3,混合使用:
  1. 关键字实参必须在位置实参右边
  2. 对同一个形参不能重复传值
def func(x, y, **kwargs):
    print(x, y)
    print(kwargs)


func(1, y=2, a=1)
#,4、默认参数:形参在定义时就已经赋值  
    可以传值也可以不传值
    注意的问题: 
         1. 只在定义时赋值一次
          2. 默认参数的定义应该在位置形参右面 
         3. 默认参数通常应该定义成不可变类型
def func(x,y=2):
    print(x,y)

func(1)
#5、可变长参数:  
    可变长指的是实参值的个数不固定 而实参有按位置和按关键字两种形式定义,
    针对这两种形式的可变长,形参对应有两种解决方案来完整地存放它们,分别是*args,**kwargs
def foo(a,b,c):
    print(a,b,c)
def info(*args,**kwargs):
    foo(*args,**kwargs)

info(1,b=3,c=4)
#6、命名关键字参数:*后定义的参数,必须被传值(有默认值的除外),且必须按照关键字实参的形式传递
def foo(x, y, *args, a=1, b, **kwargs):
    print(x, y)
    print(args)
    print(a)
    print(b)
    print(kwargs)


foo(1, 2, 3,b=3, c=4, d=5)

名称空间与作用域

什么是名称空间?
    存放变量名的地方
名称空间的分类
    1.内置名称:Python内置的名字
          存活周期:Python启动则产生,Python关闭则销毁
    2. 全局名称:运行顶级代码所产生的名称,不是函数定义的,也不是内置的。
      存活周期:
Python执行前则产生,Python执行完则销毁
   3.局部名称:在调用函数时,运行函数体代码过程产生的函数名
      存活周期:在调用时存活,调用结束则销毁
名称空间加载顺序
  内置名称空间 > 全局名称空间 > 局部名称空间 销毁顺序
  局部名称空间 > 全局名称空间 > 内置名称空间 名称访问顺序(先在自己找没有,去外面找没有,在去外面外面找)
  
局部名称空间 > 全局名称空间 > 内置名称空间
x = 123
def f1():
    # x = 111
    def f2():
        # x = 999
        print(x)
    f2()
f1()

作用域

#1、作用域即范围
        - 全局范围:全局存活,全局有效
      - 局部范围:临时存活,局部有效
#2、作用域关系是在函数定义阶段就已经固定的,与函数的调用位置无关,
x=1
def f1():
    def f2():
        print(x)
    return f2
# x=100
def f3(func):
    x=2
    func()
# x=10000
f3(f1())
#3、查看作用域:globals(),locals()
def foo():
    global x  # 局部修改全局
    x = 100


foo()
print(x)

def foo():
    x = 100
    def fune():
        nonlocal x # 局部变量修改局部变量
        x = 123
    fune()
    print(x)
foo()

函数对象

1.函数可以被引用
def add(x, y):
    print(x + y)


func = add
func(1, 2)
2.函数可以当做另外一个函数的参数
def add(x, y):
    print(x + y)


# add(1,2)

def info(x, y, add):
    return add(x, y)


# info(1, 2, add)

3.函数可以当做另外一个函数的返回值
def add(x, y):
    print(x + y)


def bar():
    return add


func = bar()
func(1, 2)
4.函数可以当做容器的一个元素
def add(x, y):
    print(x + y)


dic = {"add":add}
dic["add"](1,2)

闭包函数

什么是闭包函数?
    “闭”:闭是关闭,“包”:包是包裹起来,闭包函数把一个函数定义
在另一个函数里,该函数对外层名字作用域的引用。
可以通过函数__closure__属性,查看闭包函数所包裹外部的变量

闭包用途

#第一种:直接把函数体需要的参数定义为形参
def f1(x,y):
    print(x,y)

f1(1,2)
# 第二种:闭包
def outer(x):
    def inner(y):
        nonlocal x
        x += y
        return x
    return inner
a = outer(5)
print(a(1)) #6

装饰器

为什么是装饰器?
    装饰器是可以在被装饰对象上添加新功能,并且不修改代码
为何要有装饰器?
    装饰器是开发封闭原则,对修改封闭,对扩展开发。

import time
def index(x):
    print("index:%s"%x)
def outer(func):
    def waper(*args,**kwargs):
        start = time.time()
        func(*args,**kwargs)
        stop = time.time()
        print(stop-start)
    return waper
insex = outer(index)
index(1)

语法糖:在被装饰的对象正上方单独一行写@装饰的名字

#1. 加载顺序:自下而上
# 2. 执行顺序:自上而下

def outer(func):
    def waper(*args,**kwargs):
        start = time.time()
        func(*args,**kwargs)
        stop = time.time()
        print(stop-start)
    return waper
@outer
def index(x):
    time.sleep(0.3)
    print("index:%s"%x)
index(1)

装饰器模板

# 无参装饰器
import time

def outer(func):
    def waper(*args,**kwargs):
        start = time.time()
        res = func(*args,**kwargs)
        stop = time.time()
        print(stop-start)
        return res
    return waper

@outer
def index():
    print("222")
index()

# 有参装饰器
def demo(x):
    def outer(func):
        def waper(*args,**kwargs):
            res = func(*args,**kwargs)
            return res
        return waper
    return outer

@demo(x=1)
def index():
    print("111")
index()

迭代器

什么是迭代?
    迭代是一个重复的过程        
什么是迭代器?
     迭代器就是迭代的工具。 
为什么用迭代器?
    可提升代码的可读性,减少重复代码
什么是可迭代对象?
    可迭代对象就是指内置方法里有__iter__方法
什么是迭代对象?
    迭代对象就是指内置方法里有__iter__方法又有__next__方法



迭代器
    优点:
           1.统一取值
           2.节省内存空间
    缺点: 
            1.没有索引
            2.只能next取,如果值取完了还继续取值会抛出异常,而我们要自己捕获异常

迭代器对象的使用

dic = {"a":1,"b":2}
a = dic.__iter__()
print(a)
print(a.__next__())
print(a.__next__())

for循环

dic = {"a": 1, "b": 2}
for k in dic:
    print(dic[k])

# for 循环
# 执行 in 后对象dic.__iter__(),得到一个迭代对象iter_dic
# 执行next(iter_dic),赋值给k然后继续循环代码
# 重复执行next(iter_dic),直到把值取完,
# 捕捉到异常StopIteration,循环结束

生成器

什么是生成器?
    函数内部yield关键字,那么函数名就得到结果就是生成器

def func():
    print(">>>:1")
    yield 1
    print(">>>:2")
    yield 2
    print(">>>:3")
    yield 3
print(func())


生成器就是迭代器
因为生成器有__iter__方法和__next__方法


def func():
    print(">>>:1")
    yield 1
    print(">>>:2")
    yield 2
    print(">>>:3")
    yield 3


print(func().__iter__())
print(func().__next__())

三元表达式、列表推导式、生成器表达式

三元表达式(if 语句的简写形式)
语句:
    成立 if 条件 else 不成立

x = 1
y = 2
res = x if x > y else y
print(res)
列表推导式
# 通常写法
egg_list = []
for i in range(5):
    egg_list.append('鸡蛋%s' % i)
print(egg_list)

# 列表推导写法
res = ['鸡蛋%s' % i for i in range(5)]
print(res)
# 表达式
# l = [表达式 for x in 可迭代对象  if 条件 else 不成立 ]
res = ['鸡蛋%s' % i for i in range(5)]
print(res)

# 生成器表达式
# i = (表达式 for x in 可迭代对象  if 条件 else 不成立 )
egg = ('鸡蛋%s' % i for i in range(5))
print(egg.__iter__())
print(egg.__next__())
print(egg.__next__())
print(egg.__next__())

递归

什么是递归?
    递归本质就是循环(递归循环可以节省内存)
    递归是函数调用的一种,可以直接或者间接的调用本身

ps:默认递归为1000层

#直接调用本身
def f1():
    print('from f1')
    f1()
f1()

# #间接调用本身
def f1():
    print('from f1')
    f2()

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

递归不应该无限的循环而是在满足某种条件是结束调用 return

递推,回溯

回溯:一层一层的调用
递推:满足某种结束条件时,结束递归调用然后一层一层的返回

def f1(x):
    if x == 0:
        return 10
    return f1(x-1) + 1
print(f1(5)) #15

匿名函数

什么是匿名函数?
  匿名就是没有名字的函数

res = (lambda x,y:x+y)(1,2)
print(res)


#有名函数与匿名函数的对比
有名函数:循环使用,保存了名字,通过名字就可以重复引用函数功能

匿名函数:一次性使用,随时随时定义

内置函数

 

posted @ 2020-04-25 22:42  zhw_sylvia  阅读(153)  评论(0)    收藏  举报