函数(01)

这一周都没有休, 陪着业务小姐姐, 导那些历史数据, 真的让我有点崩溃, 各种问题, 最后总结出一个问题, 就是数据的问题, 真的是经验教训. 首先是关系型数据库不能识别的特殊字符, 其次是数据空行, 数据库以为是 空值, 导致一直主键更新错误; 最后是数据编码, utf8 和 utf8_sig 有很大不同, 哇, 这一波坑踩得有点难受, 好在都就发现了, 不然又要凉了. 经验, 真的就是, 采的坑多了, 边累计为了经验. 这也是现在自己有事没事, 写的笔记, 一方面督促自己学而时习之和不求甚解, 另外就是记录踩个的坑...

不扯了, 回到正题, 零星地回顾一些函数基础, 虽然不怎写Python代码, 但我还是始终保持良好的状态, 毕竟是我现在的第二语言, 当然第一是 sql, 这两个老大哥, 都要安排上, 每天.

在 Python 语言中, 程序的最小单元, 是函数. 从我认知来看, 使用函数, 应该是所有编程语言的基础. 我人认为, 编程学习和编程思维的训练, 核心在于深刻理解两个关键点:

  • 控制流: IF - ELSE 和 循环 (FOR, WHILE)
  • 使用和编写函数

包括现在, 回过头一想, 我每天不论是抄的, 写的那些低质量代码, 始终围绕着, 函数 (封装功能), 控制流, 注入功能和数据处理逻辑这样, "不断堆砌", 俗称搬砖嘛, 很形象.

其实要以最为通俗的直观感来区分, 编程中的函数, 和数学中的函数的区别.

  • 数学函数, 表示映射关系, 比如 实数 -> 实数, 实数 -> 向量; 向量 -> 向量; 向量-> 矩阵; 矩阵 -> 实数 ....
  • 编程函数, 表示一段逻辑, 类似容器, 对一段代码的封装, 指向某个功能, "输入 -> 处理 -> 输出"

二者是有本质上的区别的.

接收任意个参数

需求

构造一个可接受任意数量参数的函数.

方案

首先这场景非常多, 我认为最为实用是, 异常处理, 有的时候追求程序的稳健性, 不知道用户到底会填几个, 或者过程中, 调用别的兄弟的函数, 接收的时候, 不知会有几个结果 .. 这类场景.

通过 * 参数来完美解决.

第一种是, 通过 *args 将任意 个 参数, package 为元组.

# * 对参数组包 package

def my_avg(first, *rest):
    """对输入参数求均值"""
    return (first + sum(rest)) / (1 + len(rest))

# test 
print(my_avg(1, 2)) 
print(my_avg(1,2,3,4,5))
1.5
3.0

通过 *args 的写法, 可将多个参数打包 package 为一个 元组 Tuple. 然后在代码中, 将其作为一个序列来进行各种骚操作.

第二种是, 通过 **kwargs 将任意 组 关键字参数, 以字典形式 组包 package

def any_args(a, b=123, *args, **kwargs):
    """完整且健壮的函数写法"""
    print(a)
    print(b)
    print(args)
    print(kwargs)
    
# test 
any_args(1,2, 3,4,5)
1
2
(3, 4, 5)
{}

只接收关键字参数

需求

希望函数的某些参数, 只能通过关键字参数传递

方案

通过 关键字参数, 放到某个 * 或者单个 * 后面即能实现这种效果.

# 强制要求用关键字传参 

def recv(maxize, *, block):
    'receives a message'
    pass 

# test 
recv(1024, block=True)  # 这个 ok
recv(1024, True)  # TyepError
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-22-f823bb78270b> in <module>
      5 # test
      6 recv(1024, block=True)
----> 7 recv(1024, True)

TypeError: recv() takes 1 positional argument but 2 were given

通过这种小 Tips, 我们还能实现, 在接收任意多个位置参数的函数中, 指定关键字参数.

def minimum(*values, clip=None):
    """返回参数序列中最小值"""
    m = min(values)
    if clip is not None:
        m = clip if clip  > m else m 
    return m 

# test
print(minimum(1, 2, -5, 4, 3)) 
print(minimum(1, 2, -9, 2, 3, clip=0))
-5
0

这种三元表达式的写法, 还是可以的, 以前我觉得有点难懂, 现在倒是觉得非常简洁优雅. 即, 如果 if 的内容为 True, 则返回左边; else 则返回右边.

  m = clip if clip  > m else m 
# 3 元表达式 

ret = '对' if  1 + 1 == 2 else '不对'

ret 
'对' 

返回多个值

需求

一个函数, 能返回多个值 , 对象

方案

通过 return 一个元组 (用逗号',' 隔开) 即可.

def my_func():
    return 1,2,3 

# test
a, b, c = my_func()

print(a, b, c)
1, 2, 3

当调一个返回元组的函数式, 通常会将结果赋值到多个变量, 也就是拆包 unpack. 当然也可以不拆, 用一个变量接收, 那这样, 这个变量就指向这个元组本身了.

x = my_func()

print(x)
(1, 2, 3)

先到这吧, 感觉今天有点不在状态, 不想再反复温习了....

posted @ 2020-07-05 23:31  致于数据科学家的小陈  阅读(177)  评论(0编辑  收藏  举报