函数、装饰器、迭代器、内置方法

函数是什么:

  函数是指将一组语句的集合,通过一个名字(函数名)封装起来,想要执行这个函数,只需要调用具体函数名即可(函数名+())

  特征:

  1.减少重复代码

  2.使程序变得可扩展

  3.是程序变得易维护

  语法定义:

def sayhi(): #函数名
    print(‘Hello!‘)
sayhi() #调用函数

  带参数的函数

a,b = 5,8
c = a**b
print(c)

#用函数实现以上代码
def calc(x,y):#x,y为形参
    res = x**y
    return res #将函数执行结果返回

c = calc(5,8) #将函数结果赋值给c,5,8为实参
print(c)

  默认参数

#默认参数
def stu_register(name,age,country,course):
    print("----注册学生信息------")
    print("姓名:",name)
    print("age:",age)
    print("国籍:",country)
    print("课程:",course)

stu_register("王山炮",22,"CN","python_devops")
stu_register("张叫春",21,"CN","linux")
stu_register("刘老根",25,"CN","linux")

def stu_register(name,age,course,country="CN"):  #country="CN" 就是默认参数,如调用时不指定,就默认为CN,如调用时指定,就使用指定值
    print("registriation info...")
    print(name, age, course, country)

stu_register("alex", 22, "python")
stu_register("kris", 23, "python", "CN")
stu_register("shanshan", 18, "python", "Korean")

  

  关键参数 (必须放在位置参数之后)

  正常情况下,给函数传参数要按顺序,不想按顺序就可以用关键参数,只需指定参数名即可(指定了参数名的参数就叫关键参数),但记住一个要求就是,关键参数必须放在位置参数(以位置顺序确定对应关系的参数)之后

  

def stu_register(name, age, course=‘PY‘ ,country=‘CN‘):
    print("----注册学生信息------")
    print("姓名:", name)
    print("age:", age)
    print("国籍:", country)
    print("课程:", course)
stu_register("王山炮",course=‘PY‘, age=22,country=‘JP‘ )  #调用可以是这样
#但绝不可以是这样
stu_register("王山炮",course=‘PY‘, 22,country=‘JP‘ )
stu_register("王山炮", 22,age=2,5,country=‘JP‘ ) #这样相当于给age赋值2次

  非固定参数(*args,**kwarge)

def stu_register(name, age, *args): #*args会把多传入的参数按元祖方式储存
    print(name,age,args)
stu_register("王山炮", 22 )
#输出
#王山炮 22()#后面这个()就是args,只是因为没有传值,所以为空

stu_register("Jack", 22, "CN", "Python")
#输出
#Jack 22(‘CN‘ ‘Python‘)

def stu_register(name, age, *args, **kwargs): #**kwargs会把多传入的参数按dict方式储存
    print(name,age,args,kwargs)
stu_register("王山炮", 22 )
#输出
#王山炮 22(){}#后面这个{}就是kwargs,只是因为没有传值,所以为空

stu_register("Jack", 22, "CN", "Python", sex = "Male", province = "ShanDong")
#输出
#Jack 22(‘CN‘ ‘Python‘){‘sex‘:‘Male‘, ‘province‘:‘ShanDong‘}

  

  返回值 (return代表函数的终值)

  外部的代码要想获取函数的执行结果,就可以在函数里用return语句把结果返回;return语句退出函数,并返回一个表达式。不带参数值的return语句返回None

  全局与局部变量

  定义在函数外部一级代码的变量,叫全局变量,全局能用;  局部变量就是指定义在函数里的变量,只能在局部生效;  在函数内部,可以引用全局变量;

如果全局和局部都有一个变量叫name,函数查找变量的顺序是由内而外的。

  里边可以调用外边,但是不能修改。外边不能调用里边的变量。 局部只能引用全局,是修改不了的

  在函数里修改全局变量(整体改,要加global)

name = "Black girl"
def change_name():
    global name  #改为全局
    name = "黑色的姑娘"
    age = 25
    print("在" ,name ,"里面...", id(name))   

change_name()
print(name, id(name) )

  在函数里修改列表数据  字典、列表、集合、类,不可以修改的有字符串

names = [‘alex‘ , ‘black girl‘ , ‘peiqi‘ ]
def change_name():
    del names[2]
    names[1] = "黑姑娘"  #整体不可以修改,但里边内部可以改
    print(names)
change_name()
print(names)

  在函数中定义的变量称为局部变量,在程序的一开始定义的变量称为全局变量

  全局变量作用域是整个程序,局部变量作用域是定义该变量的函数

  当局部变量与全局变量同名时,在定义局部变量的函数内,局部变量起作用,在其他地方全局变量起作用

  嵌套函数

#嵌套函数

#1
def func1():
    print(‘alex‘)
    def func2():
        print(‘eric‘)  #它没有被调用所以就不会输出eric
func1()  #输出alex

#2
def func1():
    print(‘alex‘)
    def func2():
        print(‘eric‘)
    func2()
func1()   #输出alex  eric
             # ====>1.函数内部可以再次定义函数。 2.执行需要被调用

#3
def func1():
    age = 73
    print(age)
    def func2():
        print(age) #它会去父级找
    func2()
func1()  #输出 73  73


自己没有,就去父级找,没有再去爷爷级。由内向往,一层层的找。局部变量之间也是有等级关系的。

age = 19
def func1():
    age = 73
    def func2():
        print(age)  #输出 73
    func2()
func1()  

age = 19
def func1():
    def func2():
        print(age)  #输出73
    age = 73  #程序是从上往下读的,先读age,再去调用func2()
    func2()
func1()  

age = 19
def func1():
    global age  #把age=19拿回了
    def func2():
        print(age)  #19
    func2() #当程序走到这的时候,调用func2()然后往上走,输入age=19,再往下走age=73
    age = 73        #73 它已经是全局了
func1()
print(age) #73

age = 19
def func1():
    global age  #把全局拿过来了
    def func2():
        print(age)  #73
    age = 73  #把全局的给改了,然后再往下走去执行func2()
    func2()
func1()
print(age)   #73

  匿名函数

匿名函数就是不需要显示的指定函数名

#这段代码
def calc(x,y):
    return x**y
print(calc(2,5))  #32

#换成匿名函数
calc = lambda x,y:x**y
print(calc(2,5))

data = list(range(10))
print(data)    #[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

#for index,i in enumerate(data):
#    data[index] = i * i
#print(data)   #[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

def f2(n):
    return n *n
print(list(map(f2, data)))   #map函数 #[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

print(list(map(lambda x:x*x, data))) #[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

  高阶函数

  变量可以指向函数,函数的参数能够接收变量,那么一个函数就可以接收另一个函数作为参数,这种函数就称之为高阶函数

def calc(x):
    return x*x
#f = lambda x:x*x  #变量指向匿名函数
f = calc  #变量不光可以赋值,可以指向函数,什么都可以赋值;
f()

def calc(x):
    return x*x
n = 10
calc(n) #函数的参数能接收变量
print(calc(n)) #100

def func(x,y):
    return x+y
def calc(x):
    return x  #x()可以执行这个函数; x=func
n = func
calc(n)  #一个函数可以接收另一个函数作为参数

def func(x,y):
    return x+y
def calc(x):  #把func当做参数传给了x,又返回了;不返回pass也是高阶函数
    return x
f = calc(func)
print(f(5,9)) //14; 上一步执行calc这个函数的时候把x返回了,也就是把func这个函数给返回了,返回给外部使用;相当于执行的是func(5,9)

def func2(x,y):
    return abs,x,y  #返回另外一个函数
res = func2(3,-10)
print(res)

  只需要满足以下任意一个条件,即是高阶函数:1.接受一个或多个函数作为输入,2.return返回另一个函数

def func(x,y):
    return x+y

def calc(x):
    return x

f = calc(func)
print(f(5,9))  //14

def func2(x,y):
    return abs,x,y

res = func2(3,-10)
print(res)

  递归

  在函数内部,可以调用其他函数。如果一个函数在内部调用自身本身,这个函数就是递归函数。有最大递归深度限制,递归调用的次数过多,会导致栈溢出,所以限制。

def calc(n):
    print(n) #10 5 2 1
    if int(n/2) ==0: #加一个判断条件就不用再往下递归了
        return n
    return calc(int(n/2))
calc(10)

def calc(n):
    v = int(n/2)
    print(v)  #5 2 1
    if v > 0:
        calc(v)
    print(n)#0 1 2 5 10   它会一层层再出来,从内到外
calc(10)

递归执行过程

  递归特性:

  1. 必须有一个明确的结束条件
  2. 每次进入更深一层递归时,问题规模相比上次递归都应有所减少
  3. 递归效率不高,递归层次过多会导致栈溢出(在计算机中,函数调用是通过栈(stack)这种数据结构实现的,每当进入一个函数调用,栈就会加一层栈帧,每当函数返回,栈就会减一层栈帧。由于栈的大小不是无限的,所以,递归调用的次数过多,会导致栈溢出)

  二分查找

data_set = [1,3,4,6,7,8,9,10,11,13,14,16,18,19,21]

def mid_search(n,low,high,data_set):
    mid = int((low+high)/2)
    if low == high:
        print(‘错误‘)
        return
    elif data_set[mid] > n:
        print(‘从左侧找‘,n,low,high,data_set[mid])
        return mid_search(n,low,mid,data_set)
    elif data_set[mid] < n:
        print(‘从右侧找‘,n,low,high,data_set[mid])
        return mid_search(n,mid+1,high,data_set)
    else:
        print(‘找到‘,data_set[mid],mid)

mid_search(21,0,len(data_set),data_set)

  函数进阶

  

命名空间

又名name space, 顾名思义就是存放名字的地方,存什么名字呢?举例说明,若变量x=1,1存放于内存中,那名字x存放在哪里呢?名称空间正是存放名字x与1绑定关系的地方

名称空间共3种,分别如下

  • locals: 是函数内的名称空间,包括局部变量和形参
  • globals: 全局变量,函数定义所在模块的名字空间
  • builtins: 内置模块的名字空间

不同变量的作用域不同就是由这个变量所在的命名空间决定的。

作用域即范围

  • 全局范围:全局存活,全局有效
  • 局部范围:临时存活,局部有效

查看作用域方法 globals(),locals()

作用域查找顺序

LEGB:

L:locals  ; E:enclosing相邻的 ; G:globls  ; B:builtins

n = 10
def func():
    n = 20
    print(‘func:‘ ,n)  #func:20
    def func2():
        n = 30
        print(‘ func2‘ ,n) #func2:30

        def func3():
            print(‘func3:‘ , n) #func3:30
        func3()
    func2()
func()

LEGB 代表名字查找顺序: locals -> enclosing function -> globals -> __builtins__

  • locals 是函数内的名字空间,包括局部变量和形参
  • enclosing 外部嵌套函数的名字空间
  • globals 全局变量,函数定义所在模块的名字空间
  • builtins 内置模块的名字空间

闭包

  在函数里边又套了一层子函数,在子函数被返回了,就是当外层函数执行的时候子函数被返回了返回了内存地址;然后在外边执行这个子函数的时候它又引用了外边函数的这个变量,相当于这个子函数跟外层函数有某种扯不清的关系,这种关系就叫闭包。

  关于闭包,即函数定义和函数表达式位于另一个函数的函数体内(嵌套函数)。而且,这些内部函数可以访问它们所在的外部函数中声明的所有局部变量、参数。当其中一个这样的内部函数在包含它们的外部函数之外被调用时,就会形成闭包。也就是说,内部函数会在外部函数返回后被执行。而当这个内部函数执行时,它仍然必需访问其外部函数的局部变量、参数以及其他内部函数。这些局部变量、参数和函数声明(最初时)的值是外部函数返回时的值,但也会受到内部函数的影响。

装饰器

软件开发中的一个原则“开放-封闭”原则,简单来说,它规定已经实现的功能代码不允许被修改,但可以被扩展,即:

  • 封闭:已实现的功能代码块不应该被修改
  • 开放:对现有功能的扩展开放

#_*_coding:utf-8_*_

user_status = False #验证标识,用户登录成功了就把这个改成True

def login(func): #把要执行的模块从这里传进来

    def inner(*args,**kwargs):#再定义一层函数
        _username = "alex" #假装这是DB里存的用户信息
        _password = "abc!23" #假装这是DB里存的用户信息
        global user_status

        if user_status == False:
            username = input("user:")
            password = input("pasword:")

            if username == _username and password == _password:
                print("welcome login....")
                user_status = True
            else:
                print("wrong username or password!")

        if user_status == True:
            func(*args,**kwargs) # 看这里看这里,只要验证通过了,就调用相应功能

    return inner #用户调用login时,只会返回inner的内存地址,下次再调用时加上()才会执行inner函数

def home():
    print("---首页----")

@login
def america():
    #login() #执行前加上验证
    print("----欧美专区----")

def japan():
    print("----日韩专区----")

# @login
def henan(style):
    ‘‘‘
    :param style: 喜欢看什么类型的,就传进来
    :return:
    ‘‘‘
    #login() #执行前加上验证
    print("----河南专区----")

home()
# america = login(america) #你在这里相当于把america这个函数替换了
henan = login(henan)

# #那用户调用时依然写
america()

henan("3p")

#带参数的装饰器
#_*_coding:utf-8_*_
user_status = False #用户登录了就把这个改成True

def login(auth_type): #把要执行的模块从这里传进来
    def auth(func):
        def inner(*args,**kwargs):#再定义一层函数
            if auth_type == "qq":
                _username = "alex" #假装这是DB里存的用户信息
                _password = "abc!23" #假装这是DB里存的用户信息
                global user_status

                if user_status == False:
                    username = input("user:")
                    password = input("pasword:")

                    if username == _username and password == _password:
                        print("welcome login....")
                        user_status = True
                    else:
                        print("wrong username or password!")

                if user_status == True:
                    return func(*args,**kwargs) # 看这里看这里,只要验证通过了,就调用相应功能
            else:
                print("only support qq ")
        return inner #用户调用login时,只会返回inner的内存地址,下次再调用时加上()才会执行inner函数

    return auth

def home():
    print("---首页----")

@login(‘qq‘)
def america():
    #login() #执行前加上验证
    print("----欧美专区----")

def japan():
    print("----日韩专区----")

@login(‘weibo‘)
def henan(style):
    ‘‘‘
    :param style: 喜欢看什么类型的,就传进来
    :return:
    ‘‘‘
    #login() #执行前加上验证
    print("----河南专区----")

home()
# america = login(america) #你在这里相当于把america这个函数替换了
#henan = login(henan)

# #那用户调用时依然写
america()

# henan("3p")

生成器

列表生成器

直接对列表里边的值修改

>>>a = [ i*i for i in range(10)]
>>>a
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

>>>a = list(range(10))
>>>a
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9,]
>>>a = [ i if i < 5 else i*i for i in a]
>>>a
[0, 1, 2, 3, 4, 25, 36, 49, 64, 81 ]

yield 语句可以让普通函数变成一个生成器,并且相应的 __next__() 方法返回的是 yield 后面的值。

一种更直观的解释是:程序执行到 yield 会返回值并暂停,再次调用 next() 时会从上次暂停的地方继续开始执行。

>>>a2 = (i for i in range(1000))
>>>a2
<generator  object  <genexpr>  at 0x1014a73b8>  ##生成了一个生成器
>>>next(a2)
>>>next(a2)
>>>next(a2)

用for循环
>>> g = (x * x for x in range(10))
>>> for n in g:
...     print(n)
...
1
9
25
49
81

斐波那切数列

def feibo(max):
    n,a,b = 0,0,1
    while n<max:
        print(b)
        a, b = b, a + b
        n = n + 1
    return ‘done’

>>> fib(10)

##用函数写生成器
def fib(max):
    n,a,b = 0,0,1

    while n < max:
        #print(b)
        yield  b
        a,b = b,a+b

        n += 1

    return ‘done‘

>>> f = fib(6)
>>> f
<generator object fib at 0x104feaaa0>

生成器调用方法

python2:  range = list           Python3: range = 生成器

xrange = 生成器                     xrange | 没有

生成器send方法

只要函数里边有yield就是生成器了;

迭代器

范围比生成器大

可以直接作用于for循环的数据类型有以下几种:

一类是集合数据类型,如listtupledictsetstr等;

一类是generator,包括生成器和带yield的generator function。

这些可以直接作用于for循环的对象统称为可迭代对象:Iterable

凡是可作用于for循环的对象都是Iterable(可迭代)类型;凡是可作用于next()函数的对象都是Iterator(迭代器)类型,它们表示一个惰性计算的序列;集合数据类型如listdictstr等是Iterable但不是Iterator,不过可以通过iter()函数获得一个Iterator对象。

可以使用isinstance()判断一个对象是否是Iterable对象:

>>> from collections import Iterable
>>> isinstance([], Iterable)
True
>>> isinstance({}, Iterable)
True
>>> isinstance(‘abc‘, Iterable)
True
>>> isinstance((x for x in range(10)), Iterable)
True
>>> isinstance(100, Iterable)
False

而生成器不但可以作用于for循环,还可以被next()函数不断调用并返回下一个值,直到最后抛出StopIteration错误表示无法继续返回下一个值了。

*可以被next()函数调用并不断返回下一个值的对象称为迭代器:Iterator。

可以使用isinstance()判断一个对象是否是Iterator对象:

>>> from collections import Iterator
>>> isinstance((x for x in range(10)), Iterator)
True
>>> isinstance([], Iterator)
False
>>> isinstance({}, Iterator)
False
>>> isinstance(‘abc‘, Iterator)
False

创建一个迭代器有3种方法,其中前两种分别是:

  1. 为容器对象添加 __iter__() 和 __next__() 方法(Python 2.7 中是 next());__iter__() 返回迭代器对象本身 self__next__() 则返回每次调用 next() 或迭代时的元素;
  2. 内置函数 iter() 将可迭代对象转化为迭代器;
  3. 生成器,生成器通过 yield语句快速生成迭代器,省略了复杂的 __iter__() & __next__() 方式。

创建迭代器对象的好处是当序列长度很大时,可以减少内存消耗,因为每次只需要记录一个值即可。

原文地址:https://www.cnblogs.com/bj-mr-li/p/9685075.html

时间: 2024-10-03 17:10:02

函数、装饰器、迭代器、内置方法的相关文章

Python 函数对象 命名空间与作用域 闭包函数 装饰器 迭代器 内置函数

一.函数对象 函数(Function)作为程序语言中不可或缺的一部分,但函数作为第一类对象(First-Class Object)却是 Python 函数的一大特性. 那到底什么是第一类对象(First-Class Object)呢? 在 Python 中万物皆为对象,函数也不例外,函数作为对象可以赋值给一个变量.可以作为元素添加到集合对象中.可作为参数值传递给其它函数,还可以当做函数的返回值,这些特性就是第一类对象所特有的. 1.函数身为一个对象,拥有对象模型的三个通用属性:id.类型.和值.

【Python 函数对象 命名空间与作用域 闭包函数 装饰器 迭代器 内置函数】

一.函数对象 函数(Function)作为程序语言中不可或缺的一部分,但函数作为第一类对象(First-Class Object)却是 Python 函数的一大特性. 那到底什么是第一类对象(First-Class Object)呢? 在 Python 中万物皆为对象,函数也不例外,函数作为对象可以赋值给一个变量.可以作为元素添加到集合对象中.可作为参数值传递给其它函数,还可以当做函数的返回值,这些特性就是第一类对象所特有的. 1.函数身为一个对象,拥有对象模型的三个通用属性:id.类型.和值.

函数对象,函数的嵌套,名称空间与作用域,闭包,装饰器,迭代器,内置函数

一,函数对象 函数对象:函数是第一类对象,即函数可以当做数据传递 1,可以被引用 2,可以做参数的传递 3,返回值可以是函数 4,可以当作容器类型的元素 二,函数嵌套 1,函数的嵌套调用 2,函数的嵌套定义 三,名称空间与作用域 名称空间:存放名字的地方叫名称空间,存放这些值与名字的绑定关系 查看内置名称的两种方法: 三种名称空间 1,内置名称空间:随着python解释器的启动而产生 2,全局名称空间:文件的执行会产生全局名称空间,指的是文件级别定义的名字都会放入该空间 3,局部名称空间:调用函

函数嵌套 ,名称空间与作用域 ,闭包函数 ,装饰器 ,迭代器, 生成器 三元表达式,列表解析,生成器表达式 递归与二分法, 内置函数

函数嵌套名称空间与作用域闭包函数装饰器迭代器生成器三元表达式,列表解析,生成器表达式递归与二分法内置函数--------------------------------------------函数的嵌套调用:在调用一个函数的过程中,又调用了其他函数函数的嵌套定义:在一个函数的内部,又定义另外一个函数def max(x,y): if x>y: return x else: return ydef max1(a,b,c,d): res=max(a,b) res2=max(res,c) res3=ma

函数+装饰器+迭代器+生成器

闭包函数 闭包:定义在内网函数,包含对外部作用域而非全局作用域 范围:一个函数套用1或n个函数 from urllib.request import urlopen #urlopen模块 作用:爬网页 #闭包函数,内部get函数调用外部page函数 def page(url): #调用url def get(): #下载 return urlopen(url).read() #爬网页 return get #返回url值 baidu=page("http://www.baidu.com"

13装饰器和内置函数

装饰器 # 1.装饰用的工具 # import time  #内置函数计算函数运行时间 # print(time.time()) # import time # def func(): # start_time = time.time() # 代码运行之前的时间 # print('这是一个func函数') # time.sleep(3) # 阻塞,睡一下, 1 是睡一秒 # print(time.time() - start_time) # 代码运行后的时间 # func() # import

python笔记5:装饰器、内置函数、json

装饰器 装饰器本质上是一个Python函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外功能,装饰器的返回值也是一个函数对象. 先看简单例子: def run(): time.sleep(1) print('run....') 现有一个新的需求,希望可以记录下函数的运行时间,需要在代码中计算时间的代码: def run(): start_time = time.time() time.sleep(1) print('run....') end_time = time.time() pr

五、python函数、装饰器、内置函数、json及模块

一.递归调用 1.一个函数自己调用自己就是递归调用,最多一个函数递归调用自己999次,超过就会出错2.递归必须有一个明确的结束条件3.每次进入更深一层递归时,问题规模相比上次递归都应有所减少4.递归效率不高,少用递归 eg:def test1(): num = int(input('please enter a number:')) if num%2==0:#判断输入的数字是不是偶数 return True #如果是偶数的话,程序就退出了,返回true print('不是偶数请重新输入!') r

函数篇 ---&gt; 装饰器与内置函数

装饰器: 从名字上来看,装饰器就是用来装饰内容的一个工具.本质上是一个闭包 在开发中,装饰器必须要遵守开放封闭原则:对扩展开放,对修改源代码封闭. 在装饰器中,有一个很重要的工具就是@,称之为语法糖,语法糖的本质就是:被装饰的函数名 = 装饰器的名字(被装饰的函数名) 在装饰器的应用上,有一个很简单的例子 计算简易的函数运行时间 import time # 导入time模块 print(time.time()) # 获取时间戳 start_time = time.time() # 开始时间 de

&lt;04day&gt;_函数嵌套--闭包函数--装饰器--迭代器--生成器

一.函数的嵌套定义 1.python函数支持嵌套 def f1(): #f1函数的定义 def f2(): #f2函数的定义 print('from f2') def f3(): #f3函数的定义 print('from f3') f2() f1() 嵌套函数--运行结果说明: 1首先调用f1()结果,f1函数为空.担保函f2函数,f2函数有内容打印并且有调用,f2函数包含f3函数,但f3函数无调用. 运行结果: 列子:多个数据之间的大小比较. #!/usr/bin/python # -*- c