daya0576 / comments.daya0576.github.io

0 stars 0 forks source link

blog/20220911/how-to-write-maintainable-python-code/ #121

Open utterances-bot opened 1 year ago

utterances-bot commented 1 year ago

如何编写低耦合可维护的 Python 代码 | Henry Z's blog~

经常听到一个论调:设计模式本质为弥补编程语言自身的缺陷,例如单例模式的存在,是因为 Java 本身不提供单例对象创建,而 Python 中原生的 import 就是 singleton 的天然实现。 但个人观点这句话仅看到了表象,设计模式初衷还是帮助我们编写更加优雅的代

https://changchen.me/blog/20220911/how-to-write-maintainable-python-code/

yuchenyang1994 commented 1 year ago

这简直是把Java的糟粕引入进来了😆

yuchenyang1994 commented 1 year ago

观察者模式倒不是什么问题,但实际上pipeline这种模式对python这种函数为第一公民的语言里没有这么复杂,Java由于历史原因,或者说对OOP这种病态的实现不得已而为之。偏偏要将数据与行为绑定在一起,其实不是一个高明的方案。典型的如装饰器模式,你的实现就是典型的生拉硬套Java的模版代码,这其实算是有点弄巧成拙了。

@xxx()
def func():
    xxxxx

上面的装饰器不比Java的高明多了?

pipeline也是一样的,Java这种强制数据与行为绑定,造成了搞这么多设计模式。意义不大真的

reduce(map(filter(lambda x: x[xx] == "123", data), lambda: x: x*2), lambda: ....)

什么你说这套来套去的谁看的懂啊

l = filter(lambda x: x[xxx] == "123", data)
l = map(l, lambda x: x *2 )
.....

上面都是伪代码哈,但是思想是这样的,不需要这些oop糟粕。

还有一些Java的糟粕,比如说继承之类的。近些年来,关于OOP的三大特性中,继承其实是遭到诟病的。无论新来的Go和后劲更足的Rust,都开始诠释,组合>继承。Python虽然保留了继承。我们更应该关注类的行为而不是类绑定的数据。这样才能更好满足开闭原则。那句广泛流传的那句话,如果一个东西,走起来像鸭子,叫起来像鸭子,那么他就是鸭子。这就是所谓的鸭子类型 如:

class Duck:
    def fly():
        print('fly')
    def call():
        print("gagaga")
class Fish:
    def call():
        print("pupupu")

def call(animal):
       animal.call()

call(Duck())
call(Fish())
yuchenyang1994 commented 1 year ago

有空可以看看这个教程sicp python,提升抽象能力跟设计模式没有太大关系,设计模式就是一帮Java狗咬文嚼字的八股文。如果不能抓住核心表达能力只会把自己限制在这样或那样的套路里

yuchenyang1994 commented 1 year ago

@daya0576 另外请教一下你们动态阈值告警是怎么做的呢?我们这边简单做了一个原理是这样的

  1. z-score 检测
  2. 移动加权平均检测
  3. 同比检测
  4. 环比检测
  5. 孤立森林检测 然后上面5个检测算法都发现有异常才告警
daya0576 commented 1 year ago

@yuchenyang1994

关于装饰器模式,确实你说的有道理,有点生拉硬套,用原生的装饰器可能更加 pythonic 一些。 但这个 case 本质想表达的意思也是通过“组合”来解耦代码,增加可维护性。

关于鸭子类型,有个顾虑是类型注解的缺失(没有基类继承的约束),部分问题无法在编译阶段发现,代码量增加后维护的困难度可能会指数上升。

daya0576 commented 1 year ago

@yuchenyang1994

有空可以参考这两篇文章:

个人理解,告警规则的本质是如何管理or转化用户的预期。

过去我们也尝试通过各种黑魔法检测异常,但投递的告警事件用户难以理解(算法的不可解释性),最终导致无法持续提升优化准确/召回。

所以最新的思路:输入用户预期告警量后,根据历史 7 天数据,自动清洗用户可理解的静态告警规则(依据抽象好的规则模版),最终通过用户打标反馈自动调节进化。

yuchenyang1994 commented 1 year ago

@daya0576 知道你希望通过类型在编译前对类型进行约束和检查,其实大可不必,Python也能做到的 举个例子

class Animal:
    def say():
        pass
    def run():
        pass

class Fly:
    def fly():
        pass

class Duck(Animal, Fly):
 # 省略实现
    ....
def call(animal: Animal|Fly):
       animal.say()

动态语言就要有动态语言的样子嘛! 不过这些其实都是编程范式的问题,倒也不能说谁的好谁的坏了。但我还是觉得Java足够啰嗦和繁琐(当然现在java19已经没这些问题了,但迂腐的Java狗依然抱着java8不动摇,他们要用Java8一百年不动摇)

daya0576 commented 1 year ago

@yuchenyang1994 PEP 544: Protocols: Structural subtyping (static duck typing)

感觉可以用 Protocols 来定义 Fly 类型,达到类型的约束与检查。