首页 > 其他分享 >22:函数作用域、匿名函数、高阶函数、尾调用优化

22:函数作用域、匿名函数、高阶函数、尾调用优化

时间:2024-08-12 21:54:10浏览次数:13  
标签:调用 函数 22 作用域 编程 foo def name

def test1():
    print('in the test1')
def test():
    print('in the test')
    return test1
res=test()
print(res())

  


# 1.函数的定义:
# 1.test1是一个函数,当它被调用时,会打印出'in the test1'。
# 2.test是另一个函数,当它被调用时,会先打印出'in the test',然后返回test1函数对象本身,而不是调用test1函数。
# 2.函数的调用:
# 1.当你执行res = test()时,你实际上是在调用test函数。test函数执行了其体内的打印语句,并返回了test1函数对象。这个对象被赋值给了变量res。
# 3.返回值:
# 1.test函数的返回值是test1函数对象。这意味着res变量现在引用的是test1函数,而不是test1函数的执行结果。
# 4.通过res调用test1函数:
# 1.最后,当你执行print(res())时,你实际上是在调用res所引用的test1函数。因为res是test1的引用,所以res()等同于test1(),这会打印出'in the test1'。
# 这段代码展示了函数的高阶用法,即函数可以作为其他函数的返回值。这在Python中是非常有用的,因为它允许你创建可重用的代码块,这些代码块可以在需要时以函数的形式传递和调用。
#这段代码展示了函数的高阶用法,即函数可以作为其他函数的返回值。这在Python中是非常有用的,因为它允许你创建可重用的代码块,这些代码块可以在需要时以函数的形式传递和调用。

# name ='alex'
# def foo():
# name='zhugeliang'
# def bar():
# print(name)
# bar()
# foo()

name ='alex'
def foo():
    name='zhugeliang'
    def bar():
        name='guanyunchang'
        print(name)
    return bar
a=foo()
print(a)
a()

  



# 作用域在定义函数时就已经固定住了,不会随着调用位置的改变而改变
# 例一:
name='alex'
def foo():
    name='lhf'
    def bar():
        print(name)
    return bar
func=foo()
func()


# 例二:
name='alex'
def foo():
    name='lhf'
    def bar():
        name='guozixin'
        def tt():
            print(name)
        return tt
    return bar
func=foo()
func()()

  



# 匿名函数
# 匿名函数就是不需要显式的指定函数
def calc(x):
    return x+1
res=calc(10)
print(calc(10))

func=lambda x:x+1  #匿名函数
print(func(10))

#输出alex_gae
name='alex'
def change_name(x):
    return name+"_age"
res=change_name(name)
print(res)

fucn=lambda x:name+'_age'
res=fucn(name)
print('匿名函数的运行结果',res)

lambda x:name+'_age'  #和其他函数一起使用

func=lambda x,y,z:x+y+z
print(func(1,2,3))

lambda x,y,z:(x+1,y+1,z+1)
print(func(1,2,3))

  




#编程的方法论:
# 1.面向过程:
# 2.函数式
# 3.面向对象

# 一、函数式编程
# 函数的参数传入,是函数吃进去的食物,而函数return的返回值,是函数拉出来的结果,面向过程的思路就是,
# 把程序的执行当做一串首尾相连的函数,一个函数吃,拉出的东西给另外一个函数吃,另外一个函数吃了再继续拉给下一个函数吃。
# 例如:
# 用户登录流程:前端接收处理用户请求-》将用户信息传给逻辑层,逻辑词处理用户信息-》将用户信息写入数据库
# 验证用户登录流程:数据库查询/处理用户信息-》交给逻辑层,逻辑层处理用户信息-》用户信息交给前端,前端显示用户信息


# 二、什么是面向过程
# 面向过程是一种思维方式。当试图通过面向过程解决问题时,我们的关注点在于问题解决的流程,重在这个过程的控制,
# 需要用大量的模块(模块化的思想源自于硬件,在C语言中是函数)将大问题拆解,程序员通过控制模块的执行顺序以解决问题。
# 举个例子,当我们解决一个“如何将大象装入冰箱?”的问题时,最简单的解决思路是面向过程解决: 
# 1、关注过程,将大问题拆解为小问题,实现每个小问题的解决方法 
# a、打开冰箱门 
# b、将大象装入冰箱 
# c、关闭冰箱门 
# 2、通过控制代码,控制模块执行,执行顺序为a->b->c,问题解决。
# 在日常生活或者说日常编程中,简单的问题用面向过程的思路解决,更加直接有效,但是当问题的规模稍大时,
# 如要描述三万个人吃饭的问题,或者要构建一个航空母舰模型的时候,用面向过程的思想是远远不够的。
# 而且面向过程程序的代码复用性、可扩展性、可移植性、灵活性、健壮性都会在处理大规模问题中出现问题。

# ‌函数式编程(Functional Programming)是一种编程范式,它将计算机运算视为数学上的函数计算,并避免使用程序状态以及易变对象。
# 这种编程范式强调函数作为一等公民,即函数可以赋值给变量、作为参数传入其他函数、或作为返回值返回。
# 函数式编程的基础是‌λ演算(lambda calculus),其中函数的函数可以作为输入和输出。
#
# 函数式编程的特点
# 无状态与数据不可变:函数式编程要求所有的数据都是不可变的,这意味着如果你想修改一个对象,
# 应该创建一个新的对象而不是修改已有的对象。这有助于简化程序的逻辑,减少错误的可能性。
# ‌高阶函数:高阶函数是指那些接受函数作为参数或返回函数的函数。这使得函数可以更加灵活地处理数据。
# 引用透明性:如果提供同样的输入,那么函数总是返回同样的结果,不依赖于外部状态的变化。这有助于验证程序的正确性。
# ‌惰性求值:惰性求值意味着表达式只在需要时才进行计算,这有助于节省计算资源。
# 函数式编程的应用
# ‌GUI编程:通过明确的时间模型来简化图形用户界面(GUI)的编程。
# ‌机器人学:在机器人编程中,函数式编程可以帮助简化复杂的控制逻辑。
# ‌音乐编程:在音乐创作和生成中,函数式编程可以用来生成复杂的音乐结构。
# ‌Web开发:在Web开发中,函数式编程可以帮助提高代码的可读性和可维护性。
# 函数式编程与命令式编程的区别
# 数据修改方式:函数式编程避免状态修改,而命令式编程允许修改数据状态。
# 错误处理:函数式编程通过纯函数减少错误的可能性,而命令式编程需要更多的错误处理机制。
# 代码结构:函数式编程倾向于使用更简洁的代码结构,而命令式编程可能包含更复杂的控制流程。
# 函数式编程的优点和缺点
# 优点:代码简洁、易于理解和维护,适合处理复杂的数据结构和算法。
# 缺点:可能不适合需要频繁修改状态的应用,且在某些情况下可能不如命令式编程高效。
# 通过了解函数式编程的基本概念、特点和应用场景,可以更好地理解这种编程范式的优势和局限性,从而在合适的场景中选择使用。
# Hashell clean erlang 学习方向

#三、面向对象编程
# 是把构成问题事务分解成各个对象,建立对象的目的不是为了完成一个步骤,而是为了描述某个事物在整个解决问题的步骤中的行为。
# 面向对象编程(Object - Oriented Programming,简称OOP)则是一种以对象为中心的编程范式。在面向对象编程中,程序被组织成一组对象,每个对象都有自己的状态(属性)和行为(方法)。
# 对象是类的实例,类是定义对象的模板。这种编程风格强调将问题分解为对象,并通过对象之间的交互来解决问题。对象可以封装数据和相关的操作,具有良好的模块化和重用性。

# 面向过程编程:
# 1.不可改变数据
# 2.第一类对象
# 3.尾调用优化(尾递归)
# 列1,不可变,不用变量保存状态,不修改变量

#非函数式
a=1
def incr_test1():
    global a
    a+=1
    return a
incr_test1()
print(a)

  



#函数式
n=1
def incr_test2(n):
    return n+1
print(incr_test2(2))
print(n)

  



#高阶函数:满足如下之一即可
#1.把函数当作参数传给另外一个函数
def foo(n):#n=bar
    print(n)
def bar(name):
    print('my name is %s' %name)
# foo(bar)    #把函数当作参数传给另外一个函数foo,
foo(bar('alex'))

#2.把函数自己返回给自己
def foo ():
    print('from foo')
    return foo     #把函数自己返回给自己
foo()

def bar():
    print('from bar')
def foo():
    print('from foo')
    return bar
n=foo()
n()

  



# 尾调用优化
# 尾调用的概念非常简单,一句话就能说清楚,就是指某个函数的最后一步是调用另一个函数。
# 尾调用之所以与其他调用不同,就在于它的特殊的调用位置。
# 我们知道,函数调用会在内存形成一个"调用记录",又称"调用帧"(call frame),
# 保存调用位置和内部变量等信息。如果在函数A的内部调用函数B,那么在A的调用记录上方,
# 还会形成一个B的调用记录。等到B运行结束,将结果返回到A,B的调用记录才会消失。
# 如果函数B内部还调用函数C,那就还有一个C的调用记录栈,以此类推。所有的调用记录,
# 就形成一个"调用栈"(call stack)。
# 尾调用由于是函数的最后一步操作,所以不需要保留外层函数的调用记录,因为调用位置、
# 内部变量等信息都不会再用到了,只要直接用内层函数的调用记录,取代外层函数的调用记录就可以了。

#函数bar在foo内味尾调用
def bar(n):
    return n
def foo(x):
    return bar(x)

#函数bar1和bar2在foo内均为尾调用,二者在if判断条件不同的情况下都有可能作为函数的最后一步
def bar1(n):
    return n

def bar2(n):
    return n+1
def foo(x):
    if type(x) is str:
        return  bar1(x)
    elif type(x) is int:
        return bar2(x)

  



#函数bar 在foo 内尾非尾调用
def bar(n):
    return n
def foo(x):
    y=bar(x)
    return y

#调用bar在foo内味非尾调用
def bar(n):
    return n
def foo(x):
    return bar(x)+1

  





标签:调用,函数,22,作用域,编程,foo,def,name
From: https://www.cnblogs.com/liu-zhijun/p/18355818

相关文章

  • JS中关于为什么调用构造函数要使用new的详细解读
    在JavaScript中,使用new关键字调用构造函数是创建新对象的关键步骤。本文将从以下几个方面解释为什么要这样做:1.创建一个新的对象当你用new调用构造函数时,会自动创建一个新的空对象,这个对象会被赋值给this,即构造函数内部的this关键字会引用这个新创建的对象。fu......
  • [题解 hduoj-7522] 2024HDU 暑假多校7 - cats 的最小生成树
    原题链接题意有一个有重边的无向图,每次找到它的最小生成树,并删除生成树的边,直到不存在最小生成树,问被每条边在第几次被删除.思路考虑用类似Kruskal算法,但是是遍历一遍所有边,同时处理出来所有的生成树.具体这样做:如Kruskal一样,把所有边按边权排序,......
  • AutoCAD软件下载+安装+软件最新版2023中文版下载安装CAD2022
    纯净直装全版本(包含2023最新版)软件地址:rj.heihuyingyuan.comAutoCAD是美国Autodesk公司开发的一款computeraideddesign,即计算机辅助设计软件。它主要用于二维描绘和三维建模设计。AutoCAD的主要功能包括:1.二维绘图-可以绘制平面图形,进行几何构建和尺寸标注。......
  • 积性函数(莫比乌斯)
    一、莫比乌斯1、莫比乌斯函数:\(u(n)=\left\{\begin{array}{l}1\qquad\qquadn=1\\0\qquad\qquadn含有平方因子\\(-1)^{k}\qquadn里面所包含质因子数目\end{array}\right.\)令\(\varepsilon(n)=\sum_{d|n}^{n}u(d)=[n=1]\),那么我们有\(\varepsilon=u\*\1\)......
  • C++基础知识:友元是什么,友元(全局函数做友元)
    在程序里,有些私有属性也想让类外特殊的一些函数或者类进行访问,就需要用到友元的技术友元的目的就是让一个函数或者类访问另一个类中私有成员通俗一点说就是友元,就好比你的闺蜜,你可以让他了解你身上的特有的东西友元的关键字为friend全局函数做友元代码测试:#include......
  • 积性函数和狄利克雷卷积学习笔记
    积性函数和狄利克雷卷积学习笔记积性函数定义若函数\(f(x)\)满足\(f(ab)=f(a)f(b)\),其中\(a,b\)互质,我们称这个函数是积性函数。若\(a,b\)不互质则是完全积性函数。常见积性函数狄利克雷卷积定义也叫狄利克雷乘积。形如下式:\[h(n)=\sum_{ab=n,a>0,b>0}f(a)g(b)\]......
  • C++类和对象(中):构造函数、析构函数、拷贝构造、赋值运算符重载
    文章目录C++类和对象4、类的默认成员函数5、构造函数5.1构造函数的特点5.2实例分析6、析构函数6.1析构函数的特点6.2实例分析7、拷贝构造函数7.1拷贝构造函数的特点7.2实例分析7.3浅拷贝和深拷贝8、赋值运算符重载8.1运算符重载8.1.1运算符重载的特点8.1.2实例分析8.......
  • VS2022+QT6.7.2 子线程与主线程通信(详细)(注释)
    需求:主线程将需要计算的数据发送给子线程,子线程将计算后的结果返回给主线程。实现逻辑:(前提:子线程类已创建好,并使用start方法启动子线程)1、主线程的mysignal1信号触发子线程的myslot2槽函数方法:connect(this,&QtWidgetsApplication13::mysignal1,st,&mythread::myslot2);......
  • [题解]P2292 [HNOI2004] L 语言
    P2292[HNOI2004]L语言注:下文中,\(s[l\simr]\)表示截取字符串\(s\)的第\(l\)个字符到第\(r\)个字符。文字描述的字符串下标从\(1\)开始,但代码实现从\(0\)开始。我们建出AC自动机后,有一个比较暴力的思路。我么用\(f[i]\)表示待查找字符串\(t\)的长度为\(i\)前缀是否满足......
  • [oeasy]python029_ until_直接跳转到_unt_breakpoint_断点函数
     029调试中的跳转与断点228播放·0赞同视频​until_直接跳转到_unt_breakpoint_断点函数......