前几篇的笔记都是一值在推导神经网络, BP算法, 反复推, 一直在求导, 多变量求偏导, 引入中间变量求偏导... 连续推导了 2遍, 感觉头都大了, 觉得, 缓一波, 看看编程的东西, 比如来整个 Python 的语言特性.
近两年很流行 Python, 都说, 简单易懂, 上手快, 3个月就能精通.... 我也用了好几年了其实, 我感觉, 这些话语, 真的是在瞎扯, 主要是混淆了概念, 将 语法 与 语言 弄混淆了. 然后在工作中, 就看到了太多的烂代码, 当然, 我自己也还烂, 都是些, 一来就写, 随意命名变量, 不写关键注释, 函数互相调, 没有模块化, 基本语法不熟, 以为定义了个类, 就是面向对象... 实在是无力吐槽 ... 就很难看到一些, 简单易懂, 容易维护, 的高质量代码, 导致现在我都已经有 严重的代码洁癖和工作洁癖, 就是, 除非必须如此, 坚决不接别人的烂代码, 宁愿全部推倒重来或重构...
感觉说偏题了, 怎么变成了吐槽, 哈哈. 就趁着放假吗, 看看编程基础, 语言特性这些东西, 还是蛮重要的, 感觉. 当然, 我自己感觉也很菜, 假如笔误了, 也没关系, 笔记, 毕竟, 发现了, 改过来就行, 重在学习, 认知的过程.
在 Python 中很流行一句话, 说 万物皆对象. 细聊就要要从 类 (Class) 讲起来, 本篇就算了, 结论是, Python 中的整数, 浮动数, 字符串, 列表, 元组, 字典 ...这些东西, 其实都是 某一个类的实例而已. 因此, 这也意味着, 可以重写 或自定义类. 来构造自己的一套法则.
能自定义啥意思, 就真的可以为所欲为呀, 比如你可以重新定义 "+", 让 1 + 1 == 3 也是可以的哦.
那作为语言最基本的元素 , Python 中的 变量, 到底是什么呢?
是一个对象地址的引用, 即 Python 中的变量, 就是 C 语言 中的 指针, 变量不存储实值, 而是存一个地址. 当创建一个变量, 如 a = 123; a = [1,2,3] , 这其实说在说, 将 变量 a 指向 实例对象123 的地址. 其变量的类型, 完全取决于它 指向的 实例对象的类型. 这就是 Python 代码中不需要事先声明变量类型的原因 , 理解这一点很关键, 跟 Java, C, R, JavaScript, 这些语言是不一样的. Python 变量存储的就是指针地址而已, 根本就不存储实例对象的值. 只是一个指向关系而已.
说明 Python 变量的本质是一个指针, 最直观的方式, 我用一个 单链表的, 头部插元素 的案例, 觉得非常形象
case1 - Pointer
class Node:
"""节点类, 包含数据区, 和指针区"""
def __init__(self, data):
self.data = data
self.next = None
class LinkList:
"""单链表类, 由一个头部, 和很多节点组成"""
def __init__(self)
self.head = None
# head -> None
# 现在要将节点 node1, node2, node3, 依次从链表的head 插入
# head -> node3 -> node2 -> node1
def add(self, item):
"""头插法"""
node = Node(item)
# 实在不理解可以用纸笔画一下指向 和 断链的过程
node.next = self.head
self.head = node
如果能理解到 node.next = self.head ; self.head = node 这两句话, 则就真正理解, Python变量的本质是指针了.
case2 - Variable:
# Py 变量的本质是地址的引用呀
a = [1,2,3] # a -> id([1,2,3])
b = a # b -> a
c = a # c -> a
print('a_id:', id(a))
print('b_id:', id(b))
print('c_id:', id(c))
# output
a_id: 2827009387784
b_id: 2827009387784
c_id: 2827009387784
case3 - Function
def foo1():
return 'i am foo1'
# foo2 去引用 foo1 地址
foo2 = foo1
print('call foo1:', foo1())
print('foo1_id:', id(foo1))
print('call foo2:', foo2())
print('foo1_id:', id(foo2)))
# output
call foo1: i am foo1
foo1_id: 1745719143960
--------------------------------
call foo2: i am foo1
foo1_id: 1745719143960
case4 - Class
class CalcSales:
def __init__(self, price):
self.price = price
def __call__(self, number):
return self.price * number
calc_sales = CalcSales(6.6)
# 对象() --> 表示调用类的 __call__ 方法
print(calc_sales(100))
print(calc_sales(1000))
# oupput
660.0
6600.0
可以初步下个结论:
函数名和变量名都是一样的, 都只是 代码(内存) 空间的引用, 机制上其实就是递归调用栈
类等...亦是如此
在理解了Python 变量的本质是引用后, 理解闭包就会很容易.
闭包是一种函数嵌套函数 的写法, 其实工作中好像基本没用到过多, 主要是为了引出后面的装饰器而已. 闭包具有这样的特点:
真正的工作核心是 内函数, 外函数的作用, 好似给器, 增加了一个保护套, 或者说延长了内函数的生命周期.
case1
def 外函数(a):
def 内函数(b):
print('a=', a, 'b=', b)
return 内函数
# 内函数是可以拿到外函数的参数的
# 传参的话, 从外到里哦
外函数(1)(2)
# output
a= 1 b= 2
case2
# y = ax + b
def 直线方程(斜率, 偏置):
def 某点的预测值计算(位置):
return 位置 * 斜率 + 偏置
return 某点的预测值计算
直线方程 = 直线方程(3, 5)
print("当自变量为 20 时, 因变量为:", 直线方程(位置=20))
# output
当自变量为 20 时, 因变量为: 65
Python3 以后是支持中文变量的哈, 也主要是为了理解这闭包的概念以及用法, 感觉上, 外函数, 就只是返回了内函数的地址而已, 而内函数开始真正工作, 内函数是可以拿到外函数的参数的, 就相当于将 内函数的 作用空间扩大了.
装饰器是是闭包的一种特例, 特殊在于, 要求外函数, 只能传一个 "函数对象" 的参数
case1
def 装饰器_认证(被装饰函数):
def 内函数():
print("---颜值认证 通过---")
被装饰函数()
return 内函数
@装饰器_认证
def check():
print("小陈同学, 肩上责任很大呀")
# 效果是, 每次调用 check 函数, 则会在其上面打印 内函数里的话
check()
# out
---颜值认证 通过---
小陈同学, 肩上责任很大呀
不难看出, 装饰器的 实质 是, 在不改变原函数的前提下, 额外扩展原函数的功能
可能有小伙伴会很疑惑, 为啥要这么麻烦, 不能直接改源代码嘛? 是的 不能改. 如果有做个web程序的小伙伴就很明白, 一个地方改动, 会影响一大块改动的, 直接改源码, 我感觉会直接被同时拉黑, 那这种场景, 就可以用 写个装饰器了, 然后在改的地方, 给装饰一下, 带个套就好了. 就有点像打补丁.
更多的应用场景, 如 日志管理, 函数执行统计, 函数执行前, 后 的处理, 权限验证, 缓存处理等, 还是蛮多的, 也比较装逼, 写出来话, 当然不推荐为了炫技而写, 代码简洁优雅 和 能让别人看懂 这样的高效沟通才是最重要的.
case2 - 带参数
def check_nCov(func):
"""内函数接收参数"""
def inner(param):
print("... check...")
func(param)
return inner
@check_nCov
def check_2019_nCoV(user_name):
print(user_name, "is very healthy.")
check_2019_nCoV("youge")
# output
...check...
youge is very healthy.
case3 - args - kwargs
def out(func):
def inner(*args, **kwargs):
print("--- be decorated with the out function---")
func(*args, **kwargs) # 拆包 unpack
return inner
@out
def check_2019_nCoV(*args, **kwargs):
print(args)
print(kwargs)
print("ok, working now ...")
# output
--- be decorated with the out function---
(1, 2, 3)
{'user_name': 'youge', 'password': '123'}
ok, working now ...
这里的 * args 与 ** args 的参数组包 (一个 * 元组, 两个 * 是 字典) , 和 后面的 拆包 unpack 应用还是很多的, 我有的时候, 会用来做一个 异常处理 , 即有时不论接收的什么, 都接收, 但不处理 , 这样就能一定程度上保持程序的稳健性, 不至于突然崩溃.
其次, 调用函数, 参数的 组包, 拆包 也是蛮常见的, 个人很喜欢这种设计哦.
case4 - 参数unpack
def my_func(a, b=0, *hello, **world):
print(a, b)
print(hello)
print(world)
my_func(1,2,3,3,4,5, name='youge')
# 参数传递顺序: 位置-> 默认值-> *arg, **args
# 通常可用来作为参数传递的异常处理哦
# output
1 2
(3, 3, 4, 5)
{'name': 'youge'}
def my_func(*args):
"""参数组包拆包"""
for i, v in enumerate(args):
print(i, v)
lst = [1, 2, 3, "youge"]
my_func(*lst)
# out
0 1
1 2
2 3
3 youge
case5 - 返回值
def out(func):
def inner(*args, **kwargs):
print(args, kwargs)
# 被装饰的函数有返回值
return func(*args, **kwargs)
return inner
@out
def check_2019_nCoV(user_name):
return f"{user_name} is very healthy."
tmp = check_2019_nCov("youge")
print(tmp)
# output
('youge',) {}
youge is very healthy.
case6 - 类
# 应用 __call__ 方法, 当类被调用, 就会自动执行
# 即把 装饰的代码放 __call__ 里面就可以了.
class Out:
def __init__(self, func):
self.func = func
def __call__(self, *args, **kwargs):
print("--- be decorated with the out function---")
return self.func(*args, **kwargs)
@Out
def check_2019_nCoV(user_name):
return f"{user_name} is very healthy."
print(check_2019_nCoV('youge'))
# out
--- be decorated with the out function---
youge is very healthy.
case7 -multiple
def out1(func):
print('i am the decorator 01')
def inner(*args, **kwargs):
print("...check_01...")
return func(*args, **kwargs)
return inner
def out2(func):
print("i am the decorator 02")
def inner(*args, **kwargs):
print("...check_02...")
return func(*args, **kwargs)
return inner
@out1
@out2
def check_2019_nCoV(user_name):
print("okay~")
return f"{user_name} is very healthy"
# out
i am the decorator 02
i am the decorator 01
...check_01...
...check_02...
okay~
youge is very healthy
发现, 如果函数被 多个装饰器, 装饰时, 装饰的顺序跟咱期望一样, 但装饰器的函数, 执行的顺序却是逆序的哦
闭包与装饰器就到这吧, 差不多了. 尽可能多代码演示, 少文字叙述. 嗯, 装饰器感觉还是蛮有意思的, 感觉也算是Python的一个突出的语言特性了吧.
原文:https://www.cnblogs.com/chenjieyouge/p/12236618.html