有点意思的 Python 系列一 数学函数和导数计算

该系列旨在收集整理一些很有意思的 Python 代码,这些代码有些是通过简洁的代码实现了很牛逼的功能,有些则是通过花里胡哨的技巧代码眼花缭乱。

虽然很多代码并不适合日常的使用,但是研究一下相关的机制还是对提升能力有很大的帮助。

本期作为第一期,先来个开胃小菜

以下代码很有意思,它实现了常规数学上的函数表示。并且还能计算当前的函数值和计算对应变量的导数值。

#!/usr/bin/python
# -*- coding: utf-8 -*-

def product(items):
res = 1
for i in items:
res = res * i
return res


class Node:

def __init__(self, name, value=0):
self.name = name
self.value = value

def __add__(self, other):
return wrapper_opt("add", self, other)

def __mul__(self, other):
return wrapper_opt("mul", self, other)

def __truediv__(self, other):
return wrapper_opt("div", self, other)

def __pow__(self, other):
return wrapper_opt("pow", self, other)

def __sub__(self, other):
return wrapper_opt("add", self, wrapper_opt("mul", Constant(-1), other))

def __radd__(self, other):
return wrapper_opt("add", self, other, r=True)

def __rmul__(self, other):
return wrapper_opt("mul", self, other, r=True)

def __rtruediv__(self, other):
return wrapper_opt("div", self, other, r=True)

def __eq__(self, other):
return self.name == other.name

def __str__(self):
return str(self.name)

__repr__ = __str__


class Constant(Node):

def __init__(self, value):
super().__init__(value, value)

def calculate(self):
return self.value

@staticmethod
def derivative(variable):
return 0


class Variable(Node):

def calculate(self):
return self.value

def derivative(self, variable):
return 1 if variable.name == self.name else 0


class Operator(Node):

def __init__(self, inputs, name):
super().__init__(name)
self.inputs = inputs
self.name = f"Opt {name} of {inputs}"

def __str__(self):
opt2str = {"Add": "+", "Power": "^", "Multiply": "*", "Divide": "/"}
return opt2str[self.name.split(" ")[1]].join(map(str, self.inputs))


class Add(Operator):

def __init__(self, inputs):
super().__init__(inputs, name="Add")

def calculate(self):
return sum(inp.calculate() for inp in self.inputs)

def derivative(self, variable):
return sum(inp.derivative(variable) for inp in self.inputs)


class Multiply(Operator):

def __init__(self, inputs):
super().__init__(inputs, name="Multiply")

def calculate(self):
return product(inp.calculate() for inp in self.inputs)

def derivative(self, variable):
return sum(
inp.derivative(variable)
* product(
other_inp.calculate()
for other_inp in self.inputs
if other_inp != inp
)
for inp in self.inputs
)


class Divide(Operator):

def __init__(self, inputs):
super().__init__(inputs, name="Divide")

def calculate(self):
a, b = [inp.calculate() for inp in self.inputs]
return a / b

def derivative(self, variable):
a, b = [inp.calculate() for inp in self.inputs]
da, db = [inp.derivative(variable) for inp in self.inputs]
return (da * b - db * a) / (b ** 2)


class Power(Operator):

def __init__(self, inputs):
super().__init__(inputs, name="Power")

def calculate(self):
_x, n = self.inputs
n = n.value
return _x.calculate() ** n

def derivative(self, variable):
_x, n = self.inputs
n = n.value
return n * (_x.calculate() ** (n - 1)) * _x.derivative(variable)


def wrapper_opt(opt, self, other, r=False):
opt2class = {"add": Add, "mul": Multiply, "pow": Power, "div": Divide}
if not isinstance(other, Node):
other = Constant(other)
inputs = [other, self] if r else [self, other]
node = opt2class[opt](inputs=inputs)
return node
x = Variable("x", 2)        # 定义变量 x 默认值 2
y = Variable("y", 3) # 定义变量 y 默认值 3
f = 3 * x ** 2 + 4 * y - 5 # 定义函数 f(x)=3x²+4y−5
print(f) # 3*x^2+4*y+-1*5
print(f.calculate()) # 19 根据默认值 x=2 y=3 计算 f(x)
print(f.derivative(x)) # 12 根据默认值 x=2 计算 f'(x)=6x
x.value = 3 # x=3
y.value = -5 # y=-5
print(f.calculate()) # 2 根据默认值 x=3 y=-5 计算 f(x)
print(f.derivative(y)) # 4 根据默认值 y=4 计算 f 对 y 求导 = 4