最近想整一整数据分析,在看一本关于数据分析的书中提到了(1)if __name__ == '__main__' (2)列表解析式 (3)装饰器。

先简单描述一下前两点,再详细解说Python初级的函数装饰器。

进入正题:

一、if __name__ == '__main__'

  1. 首先,__name__是一个程序名变量,而这个变量的值是根据程序的运行方式决定的。如果程序是被当作主程序运行的,那__name__将会被赋值为__main__;当程序是作为模块被其他文件调用的,那它会自动被赋值为模块所在(程序)的文件名。
  2. 一般这句代码以这种形式出现:
    1. def printHello():
    2. print("Hello World!")
    3. print(__name__)
    4. if __name__ == '__main__':
    5. printHello()

    其输出如下:

    1. Hello World!
    2. __main__

    因为此时这个文件是以主程序的方式运行的,故它的__name__为__main__。

  3. 这个 if 判断语句存在的意义在于当程序被作为模块引入其他文件时,一句import会使得这个模块自动运行一次。
  4. 故当 printHello 函数被作为模块调入其他程序文件时,即:
    1. from name_main import printHello
    2. printHello()

    我们只会得到 printHello 运行一次的结果。这一次结果是 import 语句的效果,真正的 printHello 函数被 if 语句拦住了(因为它的__name__变成了自己的文件名而非__main__)。

二、列表解析式

  • 列表解析式其实就是一种根据已有列表,高效创建新列表的方式。
  • 通常形式如:a = [ i for i in list1 if i%2==0 ]
  • 学会使用,可以简洁化代码。

三、装饰器

  • 装饰器器如其名,起到了“装饰”的作用。体现在代码中就是给原程序添加“装饰”,添加新的东西。装饰器的本质是函数。
  • 装饰器一般用于装饰函数和类。
  • 有人问既然装饰器起到的是装饰的作用,那为什么不在函数中就添加这些“装饰”?当然可以,这确实可行。但设想我们需要每个函数打印自己的运行时间,那我们就需要在每一个函数里记录开始与结束时间,再相减得到时间差(即运行时间)。这会使得函数非常的“臃肿”,而且如果有成百上千个函数都需要这个功能,那一个一个函数加代码的措施就显得十分“无意义”。
  • 但通过装饰器:我们简单地定义一个“装饰”函数去实现需要的功能,然后在执行函数的前面加上一句“@装饰函数”,就实现了对函数们的装饰和升级。
  • 举一个例子,我们现在有两个函数分别实现打印 hello 和 goodbye,我们需要每次打印时同时把这个函数名打印出来。我们就可以用装饰器来完成,上代码。
    1. #直接装饰@
    2. def printname(func): #装饰器:实质是一个函数,参数是需要装饰的函数名(非函数调用)
    3. def wrapper(*args, **kwargs): #可变参数*args和关键字参数**kwargs
    4. print(f"[DEBUG]: enter {func.__name__}()")
    5. return func(*args, **kwargs)
    6. return wrapper #装饰器函数返回的是装饰完的函数
    7.  
    8. @printname
    9. def say_hello():
    10. print("hello!")
    11.  
    12. @printname
    13. def say_goodbye():
    14. print("goodbye!")
    15.  
    16. if __name__ == '__main__':
    17. say_hello()
    18. say_goodbye()

    程序运行结果为:

    1. [DEBUG]: enter say_hello()
    2. hello!
    3. [DEBUG]: enter say_goodbye()
    4. goodbye!

    成功实现每次打印hello时打印出函数名称say_hello()。

  • 接下来是对装饰器的深层探讨。装饰器的本质是函数,那我们如果不用@的装饰方式,看看怎么样实现同样的功能。
    1. #间接装饰
    2. def printname(func): #装饰器:实质是一个函数,参数是需要装饰的函数名(非函数调用)
    3. def wrapper(*args, **kwargs): #可变参数*args和关键字参数**kwargs
    4. print(f"[DEBUG]: enter {func.__name__}()")
    5. return func(*args, **kwargs)
    6. return wrapper #装饰器函数返回的是装饰完的函数
    7.  
    8. def say_hello():
    9. print("hello!")
    10. #return 0 测试line:23
    11.  
    12. def say_goodbye():
    13. print("goodbye!")
    14.  
    15. if __name__ == '__main__':
    16. decorator = printname(say_hello)
    17.  
    18. '''
    19. 不能使用decoratot = printname(say_hello());
    20. 可能是因为调用函数的名称是用func.__name__,而非func().__name__
    21. 用了func().name会报错'NoneType'对象没有'__name__'属性。
    22.  
    23. 因为say_hello()函数没有return,故执行结果为NoneType无。
    24. '''
    25.  
    26. decorator()
    27.  
    28. '''
    29.  
    30. 接上绿色注释:
    31. >>> type(say_hello())
    32. hello!
    33. <class 'NoneType'>
    34. >>> type(say_hello)
    35. <class 'function'>
    36.  
    37. '''
    38. #func,函数不带括号时,调用的是这个函数本身。是一整个函数体,不须等函数执行完成。
    39.  
    40. #func(),函数带括号时,调用的是函数的执行结果,需要等待函数执行完成的结果。

    和@方法的区别主要在于如何使用装饰器函数。我们需要在调用时把执行函数传入给装饰函数,return 的结果返回给新函数;再运行新函数,就实行了这一效果。

  • 最后对装饰函数的代码做一个解读。(应该在前面解读的)
  1. printname(func)是装饰函数,它的参数是func(一个函数,即执行函数),它的return是wrapper函数。
  2. 在printname里定义一个wrapper函数(参数、关键字可变),把装饰器的内容包装在wrapper里。wrapper返回的是func(执行函数)。
  3. 相当于是这一段代码执行了wrapper函数
    1. def printname(func):
    2. def wrapper(*args, **kwargs):
    3. print(f"[DEBUG]: enter {func.__name__}()")
    4. return func(*args, **kwargs)
    5. return wrapper

    实现了:print(装饰)+  func(执行函数),即成功装饰。

  • 还有一个很有趣的例子,在https://www.cnblogs.com/cicaday/p/python-decorator.html#4027718046,感谢作者的点拨。
  • 装饰器总结:

    实质: 是一个函数

    参数:是你要装饰的函数名(并非函数调用)

    返回:是装饰完的函数名(也非函数调用)

    作用:为已经存在的对象添加额外的功能

    特点:不需要对对象做任何的代码上的变动

Decorator——Python初级函数装饰器的更多相关文章

  1. python基础—函数装饰器

    python基础-函数装饰器 1.什么是装饰器 装饰器本质上是一个python函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外功能. 装饰器的返回值是也是一个函数对象. 装饰器经常用于有切 ...

  2. python基础-----函数/装饰器

    函数 在Python中,定义一个函数要使用def语句,依次写出函数名.括号.括号中的参数和冒号:,然后,在缩进块中编写函数体,函数的返回值用return语句返回. 函数的优点之一是,可以将代码块与主程 ...

  3. python 复习函数 装饰器

    # 函数 —— 2天 # 函数的定义和调用 # def 函数名(形参): #函数体 #return 返回值 #调用 函数名(实参) # 站在形参的角度上 : 位置参数,*args,默认参数(陷阱),* ...

  4. python 匿名函数&装饰器

    匿名函数 关键字lambda表示匿名函数,冒号前面的x表示函数参数匿名函数有个限制,就是只能有一个表达式,不用写return,返回值就是该表达式的结果. >>> list(map(l ...

  5. day11 python之函数装饰器

    一,什么是装饰器? 装饰器本质上就是一个python函数,他可以让其他函数在不需要做任何代码变动的前提下,增加额外的功能,装饰器的返回值也是一个函数对象. 装饰器的应用场景:比如插入日志,性能测试,事 ...

  6. python闭包函数&装饰器

    一.函数引用 函数可以被引用 函数可以被赋值给一个变量 def hogwarts(): print("hogwarts") # hogwarts() # 函数调用 print(ho ...

  7. Python之函数装饰器

    在实际中,我们可能需要在不改变函数源代码和调用方式的情况下,为函数添加一些新的附加功能,能够实现这种功能的函数我们将其称之为装饰器.装饰器本质上其实还是是一个函数,用来装饰其它函数,为函数添加一些附加 ...

  8. python 之 函数 装饰器

    5.8 装饰器 1 开放封闭原则 软件一旦上线后,就应该遵循开放封闭原则,即对修改源代码是封闭的,对功能的扩展是开放的 也就是说我们必须找到一种解决方案: 能够在不修改一个功能源代码以及调用方式的前提 ...

  9. Python中函数装饰器及练习

    )])   ,,],)

随机推荐

  1. poj3728The merchant树剖+线段树

    如果直接在一条直线上,那么就建线段树 考虑每一个区间维护最小值和最大值和答案,就符合了合并的条件,一个log轻松做 那么在树上只要套一个树剖就搞定了,多一个log也不是问题 注意考虑在树上的话每一条链 ...

  2. PHP&Java 调用C#的WCF

    步骤一:用C#声明WCF [ServiceContract] public interface IService1 { [OperationContract] void DoWork(); [Oper ...

  3. 关于一次性的数据输入,excel字符串连接保存到服务器还是CRUD?

    一 开发中遇到个问题,线下一个紧急的活动,给一个excel的文件,要把里面的一次性的数据放进活动里面,说真的几百几千个数据啊,手写进数据库不是更麻烦了吗? 于是,备份方法就是写一个crud,让线下的人 ...

  4. MVC的viewPage 通用属性运用。

    试想下在MVC的前端页面JS或者html中需要使用多语言,而后端的多语言是维护在资源文件中的,前端如果使用的话需要使用AJAX频繁的获取,一个页面中可能会存在大量的需要语言转换的地方,频繁使用AJAX ...

  5. 字符串和byte数组的相互转化

    关于byte[]数组转十六进制字符串: public static String getHexString(byte[] b) throws Exception { String result = & ...

  6. springboot 学习笔记(二)

    springboot 学习笔记(二) 快速创建一个springboot工程,并引入所需要的依赖 1.利用Spring initializr 来创建一个springboot项目,登陆http://sta ...

  7. Spring 设计原则

    Spring 框架有四大原则(Spring所有的功能和设计和实现都基于四大原则): 1. 使用POJO进行轻量级和最小侵入式开发. 2. 通过依赖注入和基本接口编程实现松耦合. 3. 通过AOP和基于 ...

  8. Bot Framework:Activity类简明指南

    Bot Framework相关文档:https://docs.botframework.com/en-us/csharp/builder/sdkreference/attachments.html B ...

  9. 如果不需要,建议移除net standard类库中的Microsoft.NETCore.Portable.Compatibility

    使用Microsoft.NETCore.Portable.Compatibility会破坏该类库在Mono和Xamarin平台的兼容性 可能导致的问题 provides a compile-time ...

  10. UVALive 3026 Period (KMP算法简介)

    kmp的代码很短,但是不太容易理解,还是先说明一下这个算法过程吧. 朴素的字符串匹配大家都懂,但是效率不高,原因在哪里? 匹配过程没有充分利用已经匹配好的模版的信息,比如说, i是文本串当前字符的下标 ...