三天速成Python之Day2——高阶函数的使用

0xFF 前言

  • 随着Python的学习,渐渐的掌握python的各种特性以及语法糖。

  • 本文将初步的列举高阶函数的用法。

  • 本文笔记见:语雀


Ox01 全局变量

# 全局变量: 定义在所有函数之外的变量
g_number = 0


# 局部变量: 定义在任何一个函数之内的变量
def function1():
    global g_number
    l_number = 1
    # 分别用于输出当前的全局变量以及所在作用域的局部变量
    print(globals(), locals())

Ox02 模块三大类四种导入方法

# 任何一个以 .py 结尾的文件,都被成为模块,可以使用 import 语句导入
# 导入的时候首先需要找到目标模块,接下来将目标模块转换成字节码,使用
# PVM执行字节码,由于这是一个十分消耗性能的事情,所以 python 只允许
# 我们对一个模块直接进行一次导入
import module
import module

# 如果一定想要代码被执行多遍,可以使用内置模块 importlib
import importlib
importlib.reload(module)

# 如何使用模块中的内容(概念类似C++中的头文件和命名空间)
import module                       # 类似于 #include <iostream>
print(module.module_value1)

from module import module_value2    # 类似于在包含头文件的基础上 using std::name
print(module_value2)

from module import *                # 在包含头文件的基础上 using namespace std
print(module_value3)

# 单下划线开头的模块全局变量只能使用命名空间访问
print(module._module_private_value)

# 通过函数导入
Mysql = __import__('06 数据库操作')

Ox03 类的定义

# class 开头后面紧跟类名,类名的首字母应该大写,后面的括号中是父类
# python3 定义的类称之为新式类,无论是否显式说明父类的 object,默
# 认都继承自 object,并且继承下来了一些内置的方法
class Student(object):
    # 类内直接定义了一些变量,被称为[类]属性,所有的类属性
    # 归类所有,能够被任何一个实例访问到,类似于静态变量
    count = 0
    books = []

    # 构造访问,任何一个类都拥有名称为 __init__ 的构造方法,
    # 当一个实例被创建之后,会被自动的调用
    def __init__(self, name, age):
        # 所有使用 self 以及实例名创建的变量都成为实例属性
        # 每一个实例都拥有自己的实例属性,可以动态添加
        self.name = name
        self.age = age
        print('这是一个构造方法')

    # 任何一个类都拥有名称为 __del__ 的析构方法
    def __del__(self):
        print('这是一个析构方法')


# 如果存在构造方法,那么创建实例的时候,必须提供除
# self 以外的其它所有参数,self 类似于 this,表示
# 调用方法的是哪一个实例
objStudent1 = Student("xiaoming", 19)

Ox04 类的属性

# 定义一个类,类内添加了类属性
class Demo(object):
    # 一个类属性
    class_value = 0


demo = Demo()
# 想要访问类属性,可以使用类名以及实例名(不推荐)
print(demo.class_value)
print(Demo.class_value)

# 对于类属性的修改,
demo.class_value = 100          # 创建了一个同名的实例属性
print(Demo.class_value)
Demo.class_value = 200          # 修改类属性只能使用类名
print(Demo.class_value)

# 动态增减类属性的方式
#   增加: 通过类名或类方法中的 cls 关键字可以动态添加
Demo.class_value2 = 1000
print(Demo.__dict__)        # 包含类内所有的属性组合的键值对
#   删除: 通过关键字 del 进行删除
del Demo.class_value
print(Demo.__dict__)

Ox05 实例属性

# 一个类,包含了实例属性的使用
class Demo(object):

    # 如果在构造方法内添加实例属性,可以保证每一个实例都拥有
    def __init__(self, value):
        self.value = value

    # 一个实例方法,其中使用了 self 关键字添加实例属性
    def add_value(self):
        self.value1 = 0


# 创建一个实例(每个实例都有自己的属性)
demo1 = Demo(1000)
demo2 = Demo(2000)

# 输出两个实例中的所有元素
print(demo1.__dict__)
print(demo2.__dict__)

# 通过 self 以及实例名动态的添加属性
demo1.add_value()
demo2.value2 = 1000
print(demo1.__dict__)
print(demo2.__dict__)

Ox06 内置属性

# 定义一个空类,用于测试内部属性
class Demo(object):
    pass

# 如果想看到一个类提供了哪些属性,就使用 dir
print(dir(Demo))

# 可以使用 help 查找某一个类的帮助信息
print(help(list))

# 可以通过内置的一些属性,输出想要的内容
print(Demo.__dict__)

Ox07 成员方法

# 在类内测试python提供的三种成员方法
class Demo(object):

    # 实例方法: 第一个参数表示的是调用当前方法的实例,类似 this,通常名称为
    #   self,也可以换做其它名称(不推荐),通过 self 可以动态操作实例属性
    def member_function(self):
        print('member_function')

    # 类方法: 第一个参数表示当前方法所在的类,类似类名,通常名称为 cls,类
    #   方法常用于需要访问类属性但是不访问实例属性的情况
    @classmethod
    def class_function(cls):
        print('class_function')

    # 静态方法: 对方法名没有任何的要求,如果方法没有访问任何的属性,就可以设为静态的
    @staticmethod
    def static_method():
        print('static_method')

Ox08 属性限制

  • 如果将要创建则会报错
class Demo(object):
    # 仅双下划线开头表示这是私有的
    __private_value = 1000

    # __slots__ 可以限定我们能够创建什么样的属性
    __slots__ = ('value1', 'value2')

    # 通常双下划线开头表示私有,双下划线开头结尾表示解释器提供
    # 单下划线开头约定俗称是私有的,但实际没有任何控制

# 通过 __dict__ 属性查看当前类内的所有类属性
print(Demo.__dict__)

# python 中的私有实际只是以一定的方式为属性修改了名称: _类名+属性名
print(Demo._Demo__private_value)

# 创建实例并使用实例动态添加属性
demo = Demo()
demo.value1 = 1000
demo.value2 = 1000
demo.value3 = 1000      #会报错


class Demo2(object):
    def __init__(self, name: int, age: int):
        self._name = name
        self._age = age

# 类魔术方法的重定义: __add__ __truediv__ __init__ __str__

Ox09 类的继承

# 创建一个父类,提供了自己的属性和方法
class Parent(object):
    # 父类提供的类属性
    parent_value = 1000

    # 构造方法,父类的构造方法
    def __init__(self, name):
        print(f'Parent.__init__({name})')


class Parent2(object):
    parent_value = 2000

    def __init__(self):
        print(f'Parent2.__init__()')


# 创建一个子类,继承自 Parent
class Child(Parent, Parent2):

    # 如果子类没有提供构造方法,就会使用父类的构造方法
    def __init__(self):
        print('Child.__init__()')
        # 不会自动调用父类的构造方法
        Parent.__init__(self, 'xiaoming')
        # 使用 super 调用父类的构造方法
        super().__init__('xiaoming')

        # 如果对 super 进行传参,那么实际调用的将是参数
        # 一在 mro(继承) 链中的下一个类的方法
        Parent2.__init__(self)
        super(Parent, self).__init__()
        super(Child, self).__init__('xiaoming')


    # 在子类中访问父类是属性
    def visit_value(self):
        # 直接以类名进行访问,访问父类的属性
        print(Parent.parent_value)

child = Child()
child.visit_value()
print(Child.__mro__)


#                          object(1)
#               parent1(3)         parent2(2)
#                child(parent1, parent2)(4)


# python 中继承的核心就是 mro

Ox0A 异常处理

try:
    # 包含的是可能产生异常的语句
    print(10 / 1)
except ZeroDivisionError:
    # 如果产生了异常,就跳转到这个位置执行
    print('产生了异常')
else:
    # 正常情况下,所执行的代码
    print('没有产生异常')


# 如果接收的异常类型和实际产生的不一致,就接收不了异常
try:
    print(10 / 0)
except ZeroDivisionError: #NameError:
    print('产生了名称异常')


# 在 python 中,产生任何一个异常都会抛出一个异常对象,
# 通过 except type as name 的方式可以接收到异常对象
try:
    l = []
    print(l[0])
    # 接收到了 IndexError 异常对象并取名为 e
except IndexError as e:
    print(e)


# 通常为了节省时间和精力会直接使用精简写法
try:
    pass
# Exception 是通用异常(语法\网络\文件)的基类,通过这个类型
# 就可以接收到大多数的异常了
except Exception as e:
    pass


import sys


# 通过 finally 可以保证程序无论以何种方式正常退出,其中的代码都被执行
#   例如这些语句: return continue break sys.exit(0)
try:
    if True:
        # sys.exit(0)
        pass
finally:
    # 用于执行清理操作
    print('finally')


# 主动抛出异常,如果想要自定义异常,可以实现一个自己的继承自 BaseException 的异常类
# 然后通过 raise 主动的抛出这个类型,并进行处理
password = input('password: ')
if len(password) < 8:
    raise Exception('密码长度过短')

Ox0B 高阶函数-过滤函数

# filer: 将参数二指定的序列中,每一个元素都传入到参数一指定的函数中
#   如果该函数返回为 true,就将元素保存到一个新的序列中,否则丢弃

# 该函数最少需要有一个参数,用于接收序列中的每一个元素
def filer_function(letter):
    # 如果是大写的,就保留,否则丢弃
    return letter.isupper()


def filer_function2(value):
    return True if value % 3 == 0 else False


print(list(filter(filer_function, 'AaBbCcDdEeFfGg')))
print(list(filter(filer_function2, range(1000))))

Ox0C 高阶函数-reduce累加器

  • 用于累加计算参数值,返回结果
import functools

# reduce: 第一个参数是一个函数,该函数一定要接收两个参数,在使用
#   reduce 时,第一次会将可迭代对象红的元素一和元素二传入到函数中,
#   计算出一个返回值,接下来每次都将函数的返回结果和下一个元素进行
#   计算,知道序列遍历结束
def add_value(left, right):
    return left + right

def mul_value(left, right):
    return left * right

# 首先将 1 和 2 放入函数,返回 3,再将 3 和 3 计算返回 6,再将 6 和 4
# 计算返回 10,最终一直加到 10,返回的是 10 到 1 相加的和
print(functools.reduce(add_value, range(1, 11)))
print(functools.reduce(mul_value, range(1, 11)))
from functools import reduce
def fn(x, y):
    return x * 10 + y
print(reduce(fn, [1, 3, 5, 7, 9]))

Ox0D 高阶函数-map叠加器

# map: 可以传入多个序列,参数一要求传入一个函数,函数接收的参数
#   个数必须和传入的序列个数相同,在使用 map 的时候,会分别将每
#   一个序列中的每一个元素传入函数,并且将函数的返回值组合成新
#   的序列
def function(left, right):
    return left * right

print(list(map(function, 'abcdefg', [1, 2, 3, 4, 5, 6, 7])))
def f(x):
    return str(x)

print(list(map(f, [1, 2, 3, 4, 5, 6, 7, 8, 9])))

Ox0E 高阶函数-sorted排序算法

https://www.liaoxuefeng.com/wiki/1016959663602400/1017408670135712

  • 普通排序
>>> sorted([36, 5, -12, 9, -21])
[-21, -12, 5, 9, 36]
  • 通过绝对值排序
>>> sorted([36, 5, -12, 9, -21], key=abs)
[5, 9, -12, -21, 36]
  • 通过首字母不区分大小写排序
>>> sorted(['bob', 'about', 'Zoo', 'Credit'], key=str.lower)
['about', 'bob', 'Credit', 'Zoo']
  • 反向排序
>>> sorted(['bob', 'about', 'Zoo', 'Credit'], key=str.lower, reverse=True)
['Zoo', 'Credit', 'bob', 'about']
  • 成绩的三种排序
# 成绩排序
from operator import itemgetter

L = ['bob', 'about', 'Zoo', 'Credit']

print(sorted(L))
print(sorted(L, key=str.lower))

students = [('Bob', 75), ('Adam', 92), ('Bart', 66), ('Lisa', 88)]

print(sorted(students, key=itemgetter(0)))
print(sorted(students, key=lambda t: t[1]))
print(sorted(students, key=itemgetter(1), reverse=True))

'''
['Credit', 'Zoo', 'about', 'bob']
['about', 'bob', 'Credit', 'Zoo']
[('Adam', 92), ('Bart', 66), ('Bob', 75), ('Lisa', 88)]
[('Bart', 66), ('Bob', 75), ('Lisa', 88), ('Adam', 92)]
[('Adam', 92), ('Lisa', 88), ('Bob', 75), ('Bart', 66)]

Process finished with exit code 0
'''
  • END

Ox0F lambda 表达式

# lambda 表达式的语法,表达式的结果是一个匿名函数
func = lambda letter, count: letter * count

# 1. 参数使用逗号隔开
# 2. 函数体使用冒号隔开
# 3. 函数体只能有一条语句
# 4. 函数体内的一条语句会被作为返回值
print(func('a', 10))

import functools

# 使用匿名函数可以在某些程度上,减少代码量
print(list(filter(lambda letter: letter.isupper(), "AaBbCcDdEeFfGg")))
print(functools.reduce(lambda left, right: left * right, range(1, 11)))
print(functools.reduce(lambda left, right: left + right, range(1, 11)))
print(list(map(lambda letter, count: letter * count, "abcdefg", [1, 2, 3, 4, 5, 6, 7])))

Ox10 闭包、装饰器

# python 中高阶函数的定义: 参数或返回值为函数的函数就是高阶函数

# 闭包: 内部函数使用了外部函数的局部变量
def outer(left):
    def inner(right):
        return left * right

    return inner


# 将做操作数传入给函数,实际上返回的是下列函数
"""
    def inner(right):
        return 10 * right 
"""
inner = outer(10)

# 可以调用返回的函数,传入右操作数并得到结果
print(inner(20))
print(outer(20)(10))


# 装饰器: 在闭包的基础上,使用了外部传入的函数
#   作用: 在不更改函数名称,参数个数和调用方式的前提下为某个函数添加新的功能

def w1(func):
    def inner():
        print('这里是新添加的内容')
        func()
        print('这里也是新添加的内容')
    return inner


# @w1
# f1 是需要被装饰的函数
def f1():
    print('f1')

f1()

# 装饰器实际上叫做语法糖,例如数组 arr[i][j] -> *(*(arr+i)+j)
"""
    def 新的f1():
        print('这里是新添加的内容')
        f1() -> 旧的
        print('这里也是新添加的内容')
"""
f1 = w1(f1)  # @w1  def f1(): ....
f1()

Ox11 time模块

import time

# 获取当前的时间戳(使用浮点数记录的秒数)
print(time.time())

# 将指定的时间戳转换为当前时区的元组
print(time.localtime())
print(time.gmtime())  # 标准时区

# 将时间元组转换为时间戳
print(time.mktime(time.localtime()))

# 睡眠一定的时间
time.sleep(0.500)

# 将时间元组转换成时间字符串
print(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()))

Ox12 random模块

import random

# randint 和 randrange
for i in range(10):
    # 生成 0<=value<=10 的一个随机数值
    print(random.randint(0, 10), end=' ')
    # 先生成一个 range 序列,从中获取一个随机值
    print(random.randrange(0, 10), end='|')
print()

# 创建一个字符串,用于保存验证码
tmp = ""
# 主要在于遍历的次数,循环 6 次
for i in range(6):
    # 生成一个满足 range 条件的随机值
    rad1 = random.randrange(4)
    # 有一半的概率进入下面的两个分支
    if rad1 == 1 or rad1 == 3:
        # 生成一个随机的整数并转换为字符串添加到末尾
        rad2 = random.randrange(0, 10)
        tmp += str(rad2)
    else:
        # 生成一个随机的大小字母添加到结尾
        rad3 = random.randrange(65, 91)
        tmp += chr(rad3)
print(tmp)

# 从指定序列中随机取出一个元素
print(random.choice(['饭', '粥', '面', '饿']))

# 打乱一个序列(洗牌)
l = [1, 2, 3, 4, 5, 6, 7]
random.shuffle(l)
print(l)

Ox13 hashlib模块

import hashlib

m = hashlib.md5()
m.update(b'ABC')
print(m.hexdigest())
print(hashlib.md5(b'ABC').hexdigest())

import base64

url = "https://www.cnblogs.com/songzhixue/"
bytes_url = url.encode("utf-8")
str_url = base64.b64encode(bytes_url)  # 被编码的参数必须是二进制数据
print(1,str_url)
str_url = base64.b64decode(str_url).decode('UTF-8')
print(2,str_url)

Ox 20 课后作业

Ox21 实现一个函数能够进行两个数的四则运算。

def fun(num1,num2,operator):
    if operator == '+':
        return num1 + num2
    elif operator == '-':
        return num1 - num2
    elif operator == '*':
        return num1 * num2
    elif operator == '/':
        return num1 / num2
    elif operator == '//':
        return num1 // num2
print(fun(2,3,'*'))

Ox22 map,filter,reduce函数分别有什么用?运行流程是什么

他们三个的格式都是一样的,map/filter/reduce(处理函数,可迭代对象)

Map:将对象中的每一个元素当作处理函数的参数,执行一次处理函数,把结果留下存储到另一个可迭代对象中。

Filter:将对象中的每一个元素当作处理函数的参数,执行一次处理函数,根据处理函数的返回值真假,来过滤结果,如果为真就留下存储到另一个可迭代对象中,否则丢弃

Reduce:他的处理函数必须接收两个参数,将对象中的元素前两个传到处理函数中,将处理结果与后面的每一个元素继续传到处理函数中

例如:def fun(x,y):

​ Return x+ y

​ R = reduce( fun,[1,2,3,4,5])

​ 最终R = 15

过程:先把1,2传进去,得到结果3,然后将这个3和后面的一个3传到函数中,得到结果6,再将6和后面的4传进去,得到结果10,将10和最后一个5传进去得到最终结果15.

18.1.2 什么是lambda表达式?下面的式子会得到什么?

L = [1,2,3,4]

print(list(map(lambda x: x+10,L)))

答:lambda是匿名函数,例如题目中,x是参数,x+10是返回值

会将lambda x:x+10作为一个函数传入map,结果如下。


Ox23 什么是闭包?

参考答案:

闭包是词法闭包的简称,是引用了自由变量的函数,这个被引用的自由变量将和函数一同存在,即使已经离开了创造他的环境也不例外。所以,有另一种说法认为闭包是由函数和与其相关的引用环境组合而成的实体。

例如:

def  fun(num):
    def  fun2():
        return  num*2
    return  fun2

当调用fun函数,得到返回值是一个函数对象,num会随着函数对象一同返回,这种现象叫做闭包。


Ox24 函数装饰器有什么作用?

参考答案:

给某个函数添加格外的功能

例如:

def add(fun):
    def inerFun( n ):
        print('添加新功能')
        return fun( n )  #这里要加括号,把参数放到里面,参数名字可以不同
    return inerFun 
@add
def fun( n ):
    print( n )

Ox25 在文件操作中open函数,‘w+’,‘r+’,‘a+’有什么区别?

‘w+’:可读,可写,如果文件不存在,就创建

‘r+’ :可读,可写,如果文件不存在,不创建,会触发FileNotFoundError异常

‘a+’ :可读,可写,如果文件不存在,就创建


Ox30 课外补充

高阶函数使用

Ox31 map

  • 利用map()函数,把用户输入的不规范的英文名字,变为首字母大写,其他小写的规范名字。输入:['adam', 'LISA', 'barT'],输出:['Adam', 'Lisa', 'Bart']
lv = ['adam', 'LISA', 'barT']
lv = list(map(lambda x: x.title(), lv))
print(lv)

Ox32 filter/reduce

  • Python提供的sum()函数可以接受一个list并求和,请编写一个prod()函数,可以接受一个list并利用reduce()求积:
lv = [3, 5, 7, 9]
sum = functools.reduce(lambda x, y: x * y, lv)
print(sum)
  • 利用mapreduce编写一个str2float函数,把字符串'123.456'转换成浮点数123.456
  • 第一版通过原始小数点分割为前后,先计算小数部分及小数位,再计算整数
  • 第二版在分割基础上直接计算整数部分+小数部分
  • 第三版通过filter过滤小数点,再通过累加器计算整数,最后除以小数位
# 字符串转小数
def str2float(s):
    sum1, sum2 = 1, 0
    str_s = s.split('.')
    for s in str_s[1]:
        sum2 = sum2 * 10 + int(s)
        sum1 *= 10
    sum2, sum1 = sum2 / sum1, 0
    for s in str_s[0]:
        sum1 = sum1 * 10 + int(s)
    return sum1 + sum2


def str2float2(s):
    num1, num2 = s.split('.')
    return int(num1) + int(num2) / 10 ** len(num2)


def str2float3(s):
    lv = list(filter(lambda ch: ch.isdigit(), s))
    sum = functools.reduce(lambda x, y: int(x) * 10 + int(y), lv)
    return sum / 10 ** (len(s) - s.find('.') - 1)


print('str2float(\'123.456\') =', str2float('1230.4560'))
print('str2float2 =', str2float2('100.0405600000'))
print('str2float3 =', str2float3('100.0405600000'))