Skip to content

Commit 9b2e60d

Browse files
committedOct 10, 2019
no message
1 parent d19d676 commit 9b2e60d

12 files changed

+735
-1
lines changed
 

‎.gitignore

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,4 @@ nohup.out
1414
apidoc/
1515
node_modules/
1616
hotelApi/
17-
忘掉设计模式,使用最强最稳定最有套路的万能编程思维-python oop四步转化公式/*
17+
忘掉设计模式,使用最强最稳定最有套路的万能编程思维-python oop四步转化公式/*
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
## 列举出4种编程方式,并介绍万能的oop 四步转化公式。
2+
```
3+
包含4种编程写法
4+
1)模块级 全局变量 + 函数
5+
2)在一组函数中无限频繁传参 和return
6+
3)无效废物滑稽类伪oop
7+
4) 正宗oop
8+
使用4种编程方式来实现男生、女生吃喝拉撒长身体,并说明缺点。
9+
10+
总结oop 四步转化公式。oop转化公式能够做到万能通用,适用一切任意编程场景,能够大幅度减少编程难度和减少代码行数。
11+
只要按照这个公式写代码,就不需要死记硬背套设计模式。
12+
此种编程方式,可以使任意极端纯面向过程代码的文件和项目减少50%行至95%行,写法更直观,并达到流程级可复用。
13+
```
14+
15+
## oop转化公式
16+
```
17+
一、针对全局变量加函数无限复制粘贴扣字的写法,
18+
1) 模块级降级为类名
19+
2) 全局变量改成实例属性
20+
3) 函数改为方法
21+
22+
23+
二、针对在一组函数中频繁return和大量重复传参的写法
24+
1、转化公式1 (先在脑袋中把代码形式转化为全局变量加函数的写法,在使用公式一)
25+
0)在脑袋中重构,把写法形式改成全局变量加函数的写法,此时不用担心全局变量是唯一的,
26+
不用大量重复传参和return,所有需要传参和return的都想象成使用全局变量和操作全局变量。
27+
1) 模块级降级为类名
28+
2) 全局变量改成实例属性
29+
3) 函数改为方法
30+
后面三个步骤是一样的。全局变量变为实例属性后,每次实例化后每个对象的实例属性都是互不干扰的。
31+
每个对象可以看作为一个模块级写法的 模块文件的无限深拷贝。
32+
33+
2、转化公式2 (直接转化,比较熟悉了之后)
34+
1) 新增一个类
35+
2)把重复传参和return的形参,全都去掉,抽取为改成实例属性
36+
3) 函数改为方法。
37+
38+
对任何面向过程写法,使用转化公式,一定就可以修改成oop,然来的代码思维不需要做任何改变,只要按这个公式就可以改造。(前提是满足需要使用oop的两个条件,才需要改造)
39+
对新写的代码,也可以按然来的想法写,说的是在脑袋里面那么写(不然真那么写,再修改,浪费花时间),然后按照此公式转化后写在ide里面。
40+
```
41+
42+
## oop转化公式的重要本质需要理解的方面
43+
```
44+
最重要是理解: 命名空间 全局变量 实例属性 多实例需求 函数和方法 的关系,搞清楚了,
45+
写oop十分之简单,不会造成极端面向过程的曲折写法。
46+
在word文档中会写更详细的解释。
47+
```
48+
49+
## 常见问题解答
50+
```
51+
1、是不是所有代码都要用oop?
52+
答:不是,按照上面的方式判断用那种方式好,再用oop转化公式,使用真正得oo编程。
53+
如果只是对现有代码直接在函数上套个类名,函数改成方法,99%的情况下弄出来的只会是废物滑稽类,伪oop,
54+
不能有写类就高大上能吓唬人装逼了这种想法。
55+
56+
2、函数和类上面区别?
57+
没有区别,就像问人和走路有什么区别,猪和吃饭有什么区别,问得牛头不对马嘴的伪问题,函数和方法才可以比较。
58+
类(对象)和模块才有可比性,必须要搞清楚原因,不然脑袋中有这个比较的想法那就不可能写得了oop。
59+
60+
面向过程是 文件模块名.eat(狗的名字,shit)
61+
oop是 狗.eat(shit)
62+
```
63+
64+
65+
```
66+
编程范式
67+
1.1 方式一,平铺指令。 从上往下叠加指令,适合简单的独立脚本。不需要和没机会被别的模块导入。
68+
1.2 方式二,面向过程函数式编程。适合实现独立的转化功能,基本原理是要实现转化 y = f(x),
69+
适合函数无依赖状态(不需要在多个函数中频繁的传入和return相同意义的参数)。
70+
1.3 方式三,oop编程.适合多个函数间需要使用同一个变量,并且需要多实例(如果使在使用面向过程时候需要使用函数频繁的return各
71+
种状态/变量由类外使用多个参数来保存这些值和传入这些值,那就是也判断为需要多实例),必须同时满足这两个条件,才使用oop好,
72+
否则不需要oop。(但单例模式为了控制灵活的初始化传参,一般也用类的方式)
73+
1.4 网上说的简单用面向过程,复杂的用面向对象,这简直是错误的废话。简单和复杂界定不了,即使是一个简单的查询价格,经过大量
74+
平台的重写对比,oop都能比面向过程减少70%行以上的代码,所以用网上这句话来判断用什么方式来写代码是错误的。只要严格使用上面
75+
描述的判断方式,就能很容易知道在什么场景什么时候使用哪种方式好了,不需要oop嗨写成类就是没理解好oop能更好地解决什么。
76+
1.5 要多使用oop,但不要写成纯静态或者半静态的无效废物类。 面向过程一定可以搞定一切,但是实现麻烦、调用更麻烦,那就不适合
77+
面向过程了。比如猴子补丁可以搞定继承,闭包可以搞定封装,但是没什么好处,实现麻烦。先要转oop,只有放弃极端面向过程,不对面
78+
向过程过分的偏执和喜欢,才能开始学习更多设计模式。
79+
```
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
# -*- coding: utf-8 -*-
2+
# @Author : ydf
3+
4+
"""
5+
实现一个人的 长身体 小便 的功能。
6+
模拟常见的价格解析,n多个辅助函数,然后暴露一个公有函数供外部调用,这样无需在调用处写好几行调用各种证件辅助方法和保存各种证件变量。但是当某个辅助函数需要改变时候,除了全盘复制粘贴扣字,还有什么办法?
7+
如果没办法,那就是又会变成使用无限复制粘贴low模式了。
8+
9+
"""
10+
11+
12+
def _show_weight(name, weight):
13+
print(f'{name} 的体重是: {weight} 千克')
14+
15+
16+
def _show_height(xingmin, height): # xingmin: xingmin也是代表姓名,故意弄成形参不是name,面向过程就会有这种搞不清楚一个参数在不同函数中是不是同一个意义的大缺点。
17+
print(f'{xingmin} 的身高是: {height} 厘米')
18+
19+
20+
def _grow_weight(name, weight, growing_weight):
21+
weight += growing_weight
22+
print(f'{name} 的体重增加 {growing_weight} 千克')
23+
return weight # 必须把结果return到外部保存
24+
25+
26+
def _grow_height(xinmin, height, growing_height):
27+
print(f'{xinmin} 的身高增加 {growing_height} 厘米')
28+
height += growing_height
29+
return height # 必须把结果return到外部保存
30+
31+
32+
def _pee(name, weight):
33+
"""
34+
因为小便会导致体重发生变化,必须把原来的体重传进来。
35+
"""
36+
print(f'{name} 站着小便') # REMIND 如果是女得,这个函数需要修改成 蹲着小便。
37+
return __reduce_weight_because_of_pee(name, weight) # 必须把结果return到外部保存
38+
39+
40+
def __reduce_weight_because_of_pee(name, tizhong):
41+
# 小便后会导致体重减少。
42+
tizhong = _grow_weight(name, tizhong, growing_weight=-0.1) # 体重的别名tizhong和weight是一样的,面向过程不使用实例属性,在很多函数中大量重复传参,形参就会可能不一致,导致看不懂代码。
43+
return tizhong
44+
45+
46+
def public_main_function(name, weight, height): # 写一个公有入口函数,自己调用身高增加函数 体重增加函数 上卫生间小便的函数,一般现在的代码都是这样弄得,这样在外部调用时候调用入口函数就可以了。
47+
height = _grow_height(name, height, 5)
48+
weight = _grow_weight(name, weight, 1)
49+
weight = _pee(name, weight) # 如果要实现pee函数不同之处,面向过程时候这里也要改。
50+
_show_height(name, height)
51+
_show_weight(name, weight)
52+
return weight, height
53+
54+
55+
if __name__ == '__main__':
56+
result = public_main_function('小明', 30, 120)
57+
print(result)
58+
"""
59+
这样可以不在外部写很多行来调用辅助函数,和写很多中间变量在外部给多个辅助函数传来传去的。但有三个大毛病是
60+
1.写法曲折,虽然提供了一个入口函数,但还是在入口函数里面内部反复return和传参,思路不直观。没有在一组函数中操纵全局变量的那种写法思路清晰。
61+
2、现在要使用小红怎么办?增加一个女孩的_pee函数 (_pee_girl),还要增加一个调用女孩pee函数的 public_main_function函数(public_main_function_girl)。这样会导致函数名不一致,调用不一致,又增加调用难度。
62+
3、如果不新增和修改函数名,假设此模块名字是person1.py那就只能新增能一个模块person2.py,然后全盘复制粘贴person1.py,然后将_pee函数里面扣字,这样调用 person1.public_main_function() 就和 person2.public_main_function()
63+
具有调用方式上有一致性,也实现了男女的小便不同之处,但为了一个小的不同,而去复制粘贴全流程,然后扣字,这样简直不要太low,每当需要修改某个地方时候,这两个文件都需要去修改一下。复制粘贴扣字两三次还好,要是复制粘贴扣字几百次,那就很伤心了。酒店里面调度不同函数比价的文件夹里面连续重复20多个文件,所有文件代码布局外观一眼看起来具有99%相似性,就是这种原因导致写成那样的。
64+
只有使用oop才能很好解决这几个弊端。写代码慢,写代码复杂难懂,写得无限重复相似 就是排斥oop和过分喜爱极端面向过程写法导致的。
65+
"""
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
# -*- coding: utf-8 -*-
2+
# @Author : ydf
3+
"""
4+
模拟无限复制粘贴扣字low模式
5+
全局变量加函数写法,可以做到少传参 少return,看起来也很简洁,实现简单清晰。
6+
但模块是唯一的,全局变量在模块也是唯一的,无法进行多实例方面的需求,一般都很少这样写,但有不用oop,所以会造成一般喜欢使用频繁return和大量重复传参的写法。
7+
"""
8+
9+
name = '小红'
10+
height = 100
11+
weight = 28
12+
13+
14+
def show_weight():
15+
print(f'{name} 的体重是: {weight} 千克')
16+
17+
18+
def show_height():
19+
print(f'{name} 的身高是: {height} 厘米')
20+
21+
22+
def grow_weight(growing_weight):
23+
global weight
24+
print(f'{name} 的体重增加 {growing_weight} 千克')
25+
weight += growing_weight
26+
27+
28+
def grow_height(growing_height):
29+
global height
30+
print(f'{name} 的身高增加 {growing_height} 厘米')
31+
height += growing_height
32+
33+
34+
def pee():
35+
"""
36+
举个影响属性的例子,上卫生间小便,会导致体重减少。
37+
:return:
38+
"""
39+
# REMIND 女得不同,需要复制粘贴扣字整个流程。
40+
print(f'{name} 蹲着小便')
41+
_reduce_weight_because_of_pee()
42+
43+
44+
def _reduce_weight_because_of_pee():
45+
global weight
46+
weight = weight - 0.1
47+
48+
49+
if __name__ == '__main__':
50+
show_height()
51+
show_weight()
52+
grow_height(5)
53+
grow_weight(1)
54+
show_height()
55+
show_weight()
56+
pee()
57+
show_weight()
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
# -*- coding: utf-8 -*-
2+
# @Author : ydf
3+
4+
"""
5+
模拟无限复制粘贴扣字low模式
6+
全局变量加函数写法,可以做到少传参 少return,看起来也很简洁,实现简单清晰。
7+
但模块是唯一的,全局变量在模块也是唯一的,无法进行多实例方面的需求,一般都很少这样写,但有不用oop,所以会造成一般喜欢使用频繁return和大量重复传参的写法。
8+
9+
"""
10+
11+
name = '小明'
12+
height = 130
13+
weight = 30
14+
15+
16+
def show_weight():
17+
print(f'{name} 的体重是: {weight} 千克')
18+
19+
20+
def show_height():
21+
print(f'{name} 的身高是: {height} 厘米')
22+
23+
24+
def grow_weight(growing_weight):
25+
global weight
26+
print(f'{name} 的体重增加 {growing_weight} 千克')
27+
weight += growing_weight
28+
29+
30+
def grow_height(growing_height):
31+
global height
32+
print(f'{name} 的身高增加 {growing_height} 厘米')
33+
height += growing_height
34+
35+
36+
def pee():
37+
"""
38+
举个影响属性的例子,上卫生间小便,会导致体重减少。
39+
:return:
40+
"""
41+
print(f'{name} 站着小便')
42+
_reduce_weight_because_of_pee()
43+
44+
45+
def _reduce_weight_because_of_pee():
46+
global weight
47+
weight = weight - 0.1
48+
49+
50+
if __name__ == '__main__':
51+
show_height()
52+
show_weight()
53+
grow_height(5)
54+
grow_weight(1)
55+
show_height()
56+
show_weight()
57+
pee()
58+
show_weight()
59+
60+
# REMIND 由于是使用的全局变量,只能完成一个单例的情况,只能完成小明这一个人,无法同时完成小明和小王,如果需要使用小王,必须复制粘贴扣字。
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
# -*- coding: utf-8 -*-
2+
# @Author : ydf
3+
"""
4+
模拟无限复制粘贴扣字low模式
5+
全局变量加函数写法,可以做到少传参 少return,看起来也很简洁,实现简单清晰。
6+
但模块是唯一的,全局变量在模块也是唯一的,无法进行多实例方面的需求,一般都很少这样写,但有不用oop,所以会造成一般喜欢使用频繁return和大量重复传参的写法。
7+
8+
"""
9+
10+
name = '小王'
11+
height = 140
12+
weight = 32
13+
14+
15+
def show_weight():
16+
print(f'{name} 的体重是: {weight} 千克')
17+
18+
19+
def show_height():
20+
print(f'{name} 的身高是: {height} 厘米')
21+
22+
23+
def grow_weight(growing_weight):
24+
global weight
25+
print(f'{name} 的体重增加 {growing_weight} 千克')
26+
weight += growing_weight
27+
28+
29+
def grow_height(growing_height):
30+
global height
31+
print(f'{name} 的身高增加 {growing_height} 厘米')
32+
height += growing_height
33+
34+
35+
def pee():
36+
"""
37+
举个影响属性的例子,上卫生间小便,会导致体重减少。
38+
:return:
39+
"""
40+
print(f'{name} 站着小便')
41+
_reduce_weight_because_of_pee()
42+
43+
44+
def _reduce_weight_because_of_pee():
45+
global weight
46+
weight = weight - 0.1
47+
48+
49+
if __name__ == '__main__':
50+
show_height()
51+
show_weight()
52+
grow_height(5)
53+
grow_weight(1)
54+
show_height()
55+
show_weight()
56+
pee()
57+
show_weight()
58+
59+
# REMIND 由于是使用的全局变量,只能完成一个单例的情况,只能完成小明这一个人,无法同时完成小明和小王,如果需要使用小王,必须复制粘贴扣字。
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
# -*- coding: utf-8 -*-
2+
# @Author : ydf
3+
"""
4+
面向过程写得无效废物类,没有封装,大量rentun,这样写的类没有任何作用。
5+
和person_f文件的写法是一样的。
6+
"""
7+
8+
9+
class Person:
10+
def show_weight(self, name, weight):
11+
print(f'{name} 的体重是: {weight} 千克')
12+
13+
def show_height(self, xingmin, height): # xingmin: xingmin也是代表姓名,故意弄成形参不是name,面向过程就会有这种搞不清楚一个参数在不同函数中是不是同一个意义的大缺点。
14+
print(f'{xingmin} 的身高是: {height} 厘米')
15+
16+
def grow_weight(self, name, weight, growing_weight):
17+
weight += growing_weight
18+
print(f'{name} 的体重增加 {growing_weight} 千克')
19+
return weight # 必须把结果return到外部保存
20+
21+
def grow_height(self, xinmin, height, growing_height):
22+
print(f'{xinmin} 的身高增加 {growing_height} 厘米')
23+
height += growing_height
24+
return height # 必须把结果return到外部保存
25+
26+
def pee(self, name, weight):
27+
"""
28+
因为小便会导致体重发生变化,必须把原来的体重传进来。
29+
"""
30+
print(f'{name} 蹲着小便')
31+
return self._reduce_weight_because_of_pee(weight) # 必须把结果return到外部保存
32+
33+
def _reduce_weight_because_of_pee(self, tizhong):
34+
tizhong = tizhong - 0.1 # 体重的别名tizhong和weight是一样的,面向过程不使用实例属性,在很多函数中大量重复传参,形参就会可能不一致,导致看不懂代码。
35+
return tizhong
36+
37+
38+
class Person2:
39+
@classmethod
40+
def show_weight(cls, name, weight):
41+
print(f'{name} 的体重是: {weight} 千克')
42+
43+
@classmethod
44+
def show_height(cls, xingmin, height): # xingmin: xingmin也是代表姓名,故意弄成形参不是name,面向过程就会有这种搞不清楚一个参数在不同函数中是不是同一个意义的大缺点。
45+
print(f'{xingmin} 的身高是: {height} 厘米')
46+
47+
@classmethod
48+
def grow_weight(cls, name, weight, growing_weight):
49+
weight += growing_weight
50+
print(f'{name} 的体重增加 {growing_weight} 千克')
51+
return weight # 必须把结果return到外部保存
52+
53+
@classmethod
54+
def grow_height(cls, xinmin, height, growing_height):
55+
print(f'{xinmin} 的身高增加 {growing_height} 厘米')
56+
height += growing_height
57+
return height # 必须把结果return到外部保存
58+
59+
@classmethod
60+
def pee(cls, name, weight):
61+
"""
62+
因为小便会导致体重发生变化,必须把原来的体重传进来。
63+
"""
64+
print(f'{name} 蹲着小便')
65+
return cls._reduce_weight_because_of_pee(weight) # 必须把结果return到外部保存
66+
67+
@classmethod
68+
def _reduce_weight_because_of_pee(cls, tizhong):
69+
tizhong = tizhong - 0.1 # 体重的别名tizhong和weight是一样的,面向过程不使用实例属性,在很多函数中大量重复传参,形参就会可能不一致,导致看不懂代码。
70+
return tizhong
71+
72+
73+
class Person3:
74+
@staticmethod
75+
def show_weight(name, weight):
76+
print(f'{name} 的体重是: {weight} 千克')
77+
78+
@staticmethod
79+
def show_height(xingmin, height): # xingmin: xingmin也是代表姓名,故意弄成形参不是name,面向过程就会有这种搞不清楚一个参数在不同函数中是不是同一个意义的大缺点。
80+
print(f'{xingmin} 的身高是: {height} 厘米')
81+
82+
@staticmethod
83+
def grow_weight(name, weight, growing_weight):
84+
weight += growing_weight
85+
print(f'{name} 的体重增加 {growing_weight} 千克')
86+
return weight # 必须把结果return到外部保存
87+
88+
@staticmethod
89+
def grow_height(xinmin, height, growing_height):
90+
print(f'{xinmin} 的身高增加 {growing_height} 厘米')
91+
height += growing_height
92+
return height # 必须把结果return到外部保存
93+
94+
@staticmethod
95+
def pee(name, weight):
96+
"""
97+
因为小便会导致体重发生变化,必须把原来的体重传进来。
98+
"""
99+
print(f'{name} 蹲着小便')
100+
return Person3._reduce_weight_because_of_pee(weight) # 必须把结果return到外部保存
101+
102+
@staticmethod
103+
def _reduce_weight_because_of_pee(tizhong):
104+
tizhong = tizhong - 0.1 # 体重的别名tizhong和weight是一样的,面向过程不使用实例属性,在很多函数中大量重复传参,形参就会可能不一致,导致看不懂代码。
105+
return tizhong
106+
107+
108+
if __name__ == '__main__':
109+
"""
110+
person1是无效废物类,因为他改成 person2 person3,下面的调用还能正常运行,所以是个废物类。
111+
"""
112+
xiaohong = Person3()
113+
xiaohong_name = '小红'
114+
xiaohong_height = 110
115+
xiaohong_weight = 25
116+
xiaohong.show_height(xiaohong_name, xiaohong_height)
117+
xiaohong.show_weight(xiaohong_name, xiaohong_weight)
118+
xiaohong_height = xiaohong.grow_height(xiaohong_name, xiaohong_height, 5)
119+
xiaohong_weight = xiaohong.grow_weight(xiaohong_name, xiaohong_weight, 1) # 体重发生了变化,必须把结果return出来保存
120+
xiaohong.show_height(xiaohong_name, xiaohong_height)
121+
xiaohong.show_weight(xiaohong_name, xiaohong_weight) # 展示体重,需要把变化后的体重传进来
122+
xiaohong_weight = xiaohong.pee(xiaohong_name, xiaohong_weight) # 连上个厕所都需要把体重参数传进来,然后还要保存新结果,这样大量传参简直不要太low
123+
xiaohong.show_weight(xiaohong_name, xiaohong_weight)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# -*- coding: utf-8 -*-
2+
# @Author : ydf
3+
"""
4+
封装的工具类没有发明非常实用的好功能,全都是自己取个新的方法名字调用官方的方法,没什么卵用,还要新记忆各种新的名字。还不如直接调用官方的算了。
5+
比如套上享元模式 单例模式或者缓存模式来控制创建,或者在官方基础上增加个自动聚合数据库命令的,这样才可以,这样才有作用。
6+
"""
7+
from redis import Redis
8+
class CustomRedis():
9+
def __init__(self,host,port):
10+
self._r = Redis(host,port)
11+
12+
def my_exists(self,name):
13+
return self._r.exists(name)
14+
15+
def my_hget(self,name,key):
16+
return self._r.hget(name,key)
17+
18+
def my_sadd(self,name,value):
19+
return self._r.sadd(name,value)
20+
21+
def my_lpush(self,name,value):
22+
return self._r.sadd(name,value)
23+
24+
# 。。。。。。。。。。。。。。。。。。
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
# coding=utf8
2+
"""
3+
1、实现人的功能。oop写法,使用类/对象 加 方法。
4+
2、重要是要理解面向对象里面的封装,封装是最重要的特点,写出没有体现出封装特点的类就是无效废物类就是面向过程的类。
5+
3、这种写法清晰明了,类/对象 加 方法 的写法 几乎和模块文件加全局变量加函数的写法思路是一模一样的,只是把命名空间下沉了一级,就能毫无曲折的实现了多实例的要求。继不继承都是次要的,最最最重要是看封装,不要把注意力重点放在这里面的继承了,只是顺便演示一个继承是如何减少代码实现不同点而已。继承不是面向对象必须的,封装才是。
6+
4、使用oop时候,在实现时候更为简单,几乎行云流水,不需要考虑频繁的考虑传参和return
7+
出状态(变量)给外部。在调用时候也更具备一致性,在调用处只需要一个实例化出一个对象,类的外部只需要一个变量代表此实例即可。否则使用面向过程还需要模拟多实例,在调用处最少需要保存 名字 体重 身高三个变量,并且每次调用函数都需要传入和保存return出来的值,这样调用起来反复传参和return修改外部变量,调用起来复杂和看起来乱七八糟的调用形式不具备一致性。
8+
"""
9+
10+
"""
11+
得出转化公式的规律:
12+
一、针对全局变量加函数无限复制粘贴扣字的写法,
13+
1) 模块级降级为类名
14+
2) 全局变量改成实例属性
15+
3) 函数改为方法
16+
17+
二、针对频繁return和大量重复传参的写法
18+
1、转化公式1
19+
0)在脑袋中重构,把写法形式改成全局变量加函数的写法,此时不用担心全局变量是唯一的,不用大量重复传参和return,所有需要传参和return的都想象成使用全局变量和操作全局变量。
20+
1) 模块级降级为类名
21+
2) 全局变量改成实例属性
22+
3) 函数改为方法
23+
后面三个步骤是一样的。全局变量变为实例属性后,每次实例化后每个对象的实例属性都是互不干扰的。每个对象可以看作为一个模块级写法的 模块文件的无限深拷贝。
24+
25+
2、转化公式2
26+
1) 新增一个类
27+
2)把重复传参和return的形参,全都去掉,改成实例属性
28+
3) 函数改为方法。
29+
30+
对任何面向过程写法,使用转化公式,一定就可以修改成oop,然来的代码思维不需要做任何改变,只要按这个公式就可以改造。(前提是满足需要使用oop的两个条件,才需要改造)
31+
对新写的代码,也可以按然来的想法写,说的是在脑袋里面那么写(不然真那么写,再修改,浪费花时间),然后按照此公式转化后写在ide里面。
32+
"""
33+
34+
"""
35+
最重要是理解: 命名空间 全局变量 实例属性 多实例需求 函数和方法 的关系,搞清楚了,写oop十分之简单,不会造成极端面向过程的曲折写法。
36+
在word文档中会写更详细的解释。
37+
"""
38+
39+
"""
40+
常见问题解答
41+
1、是不是所有代码都要用oop?
42+
答:不是,按照上面的方式判断用那种方式好,目的是要简单代码少就可以,便于维护扩展就好。
43+
2、函数和类上面区别?
44+
没有区别,就像问人和走路有什么区别,猪和吃饭有什么区别,问得牛头不对马嘴的伪问题,函数和方法才可以比较。类(对象)和模块才有可比性,必须要搞清楚原因,不然脑袋中有这个比较的想法那就不可能写得了oop。
45+
面向过程是 文件模块名.eat(狗的名字,shit)
46+
oop是 狗.eat(shit)
47+
"""
48+
49+
50+
"""
51+
编程范式
52+
1.1 方式一,平铺指令。 从上往下叠加指令,适合简单的独立脚本。不需要和没机会被别的模块导入。
53+
1.2 方式二,面向过程函数式编程。适合实现独立的转化功能,基本原理是要实现转化 y = f(x),适合函数无依赖状态(不需要在多个函数中频繁的传入和return相同意义的参数)。
54+
1.3 方式三,oop编程.适合多个函数间需要使用同一个变量,并且需要多实例(如果使在使用面向过程时候需要使用函数频繁的return各种状态/变量由类外使用多个参数来保存这些值和传入这些值,那就是也判断为需要多实例),必须同时满足这两个条件,才使用oop好,否则不需要oop。(但单例模式为了控制灵活的初始化传参,一般也用类的方式)
55+
1.4 网上说的简单用面向过程,复杂的用面向对象,这简直是错误的废话。简单和复杂界定不了,即使是一个简单的查询价格,经过大量平台的重写对比,oop都能比面向过程减少70%行以上的代码,所以用网上这句话来判断用什么方式来写代码是错误的。只要严格使用上面描述的判断方式,就能很容易知道在什么场景什么时候使用哪种方式好了,不需要oop嗨写成类就是没理解好oop能更好地解决什么。
56+
1.5 要多使用oop,但不要写成纯静态或者半静态的无效废物类。 面向过程一定可以搞定一切,但是实现麻烦、调用更麻烦,那就不适合面向过程了。比如猴子补丁可以搞定继承,闭包可以搞定封装,但是没什么好处,实现麻烦。先要转oop,只有放弃极端面向过程,不对面向过程过分的偏执和喜欢,才能开始学习更多设计模式。
57+
"""
58+
59+
60+
class Person(object):
61+
62+
def __init__(self, name, height, weight):
63+
self.name = name
64+
self.height = height
65+
self.weight = weight
66+
67+
def show_weight(self):
68+
print(f'{self.name} 的体重是: {self.weight} 千克')
69+
70+
def show_height(self):
71+
print(f'{self.name} 的身高是: {self.height} 厘米')
72+
73+
def grow_weight(self, growing_weight): # 增加的体重是可变的外界传来的,需要作为方法的参数传进来,不可避免。
74+
print(f'{self.name} 的体重增加 {growing_weight} 千克')
75+
self.weight += growing_weight
76+
77+
def grow_height(self, growing_height):
78+
print(f'{self.name} 的身高增加 {growing_height} 厘米')
79+
self.height += growing_height
80+
81+
def pee(self):
82+
"""
83+
举个影响属性的例子,上卫生间小便,会导致体重减少。
84+
:return:
85+
"""
86+
self._reduce_weight_because_of_pee()
87+
88+
def _reduce_weight_because_of_pee(self):
89+
self.weight = self.weight - 0.1
90+
91+
92+
class Boy(Person):
93+
# REMIND 需要实现不同之处
94+
def pee(self):
95+
print(f'{self.name} 站着小便')
96+
super(Boy, self).pee()
97+
98+
99+
class Girl(Person):
100+
# REMIND 需要实现不同之处
101+
def pee(self):
102+
print(f'{self.name} 蹲着小便')
103+
super(Girl, self).pee()
104+
105+
106+
if __name__ == "__main__":
107+
# 在调用处只需要实例化一个对象,不需要学极端面向过程编程,保存很多个变量。
108+
xiaomin = Boy('小明', 120, 30)
109+
xiaowang = Boy('小王', 130, 32)
110+
xiaomin.grow_height(5)
111+
xiaomin.grow_weight(1)
112+
xiaomin.show_height()
113+
xiaomin.show_weight()
114+
xiaomin.pee()
115+
xiaomin.show_weight()
116+
# REMIND 这里实例化两个男孩,原因是模拟需要多实例,模拟每个对象的属性是互不干扰的,小明增长体重不会影响到小王的体重。
117+
# REMIND 如果是使用全局变量 + 函数 或者类名加静态属性(类属性),则会发生互相干扰,正因为这样行不通再加上不使用oop面向对象,就会造成需要写成在一组函数中频繁return和传参,实现上复杂曲折,也不好读懂。这种写法现象在可预订平台的酒店价格解析里面体现得十分之严重,由于多个函数中频繁传参和return,有的参数命名是同一个东西,但是在各个函数中形参的名字取得又不一样,不仅在维护代码时候难以搞懂,在实现的时候也是麻烦曲折很多。
118+
print('— ' * 30)
119+
xiaowang.show_height()
120+
xiaowang.show_weight()
121+
xiaowang.grow_height(6)
122+
xiaowang.grow_weight(2)
123+
xiaowang.show_height()
124+
xiaowang.show_weight()
125+
xiaowang.pee()
126+
xiaowang.show_weight()
127+
128+
print('* ' * 30)
129+
xiaohong = Boy('小红', 110, 25)
130+
xiaohong.grow_height(3)
131+
xiaohong.grow_weight(0.5)
132+
xiaohong.show_height()
133+
xiaohong.show_weight()
134+
xiaohong.pee()
135+
xiaohong.show_weight()
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
# -*- coding: utf-8 -*-
2+
# @Author : ydf
3+
4+
"""
5+
演示使用极端面向过程来写,由于没有封装,没有成员变量和全局变量,所以造成需要在多个函数中频繁重复传参和return
6+
无论是实现还是调用都更为复杂。
7+
"""
8+
9+
10+
def show_weight(name, weight):
11+
print(f'{name} 的体重是: {weight} 千克')
12+
13+
14+
def show_height(xingmin, height): # xingmin: xingmin也是代表姓名,故意弄成形参不是name,面向过程就会有这种搞不清楚一个参数在不同函数中是不是同一个意义的大缺点。
15+
print(f'{xingmin} 的身高是: {height} 厘米')
16+
17+
18+
def grow_weight(name, weight, growing_weight):
19+
weight += growing_weight
20+
print(f'{name} 的体重增加 {growing_weight} 千克')
21+
return weight # 必须把结果return到外部保存
22+
23+
24+
def grow_height(xinmin, height, growing_height):
25+
print(f'{xinmin} 的身高增加 {growing_height} 厘米')
26+
height += growing_height
27+
return height # 必须把结果return到外部保存
28+
29+
30+
31+
def pee(name, weight):
32+
"""
33+
因为小便会导致体重发生变化,必须把原来的体重传进来。
34+
"""
35+
print(f'{name} 站着小便')
36+
return _reduce_weight_because_of_pee(weight) # 必须把结果return到外部保存
37+
38+
39+
def _reduce_weight_because_of_pee(tizhong):
40+
tizhong = tizhong - 0.1 # 体重的别名tizhong和weight是一样的,面向过程不使用实例属性,在很多函数中大量重复传参,形参就会可能不一致,导致看不懂代码。
41+
return tizhong
42+
43+
44+
if __name__ == '__main__':
45+
# 极端面向过程不仅需要导致频繁传参和return,还要在调用时候设置很多个外部变量来保存状态,如果属性/状态越多,需要外部保存的变量就越多。
46+
xiaomin_name = '小明'
47+
xioamin_height = 120
48+
xiaomin_weight = 30
49+
show_height(xiaomin_name, xioamin_height)
50+
show_weight(xiaomin_name, xiaomin_weight)
51+
xioamin_height = grow_height(xiaomin_name, xioamin_height, 5)
52+
xiaomin_weight = grow_weight(xiaomin_name, xiaomin_weight, 1) # 体重发生了变化,必须把结果return出来保存
53+
show_height(xiaomin_name, xioamin_height)
54+
show_weight(xiaomin_name, xiaomin_weight) # 展示体重,需要把变化后的体重传进来
55+
xiaomin_weight = pee(xiaomin_name, xiaomin_weight) # 连上个厕所都需要把体重参数传进来,这样大量传参简直不要太low
56+
show_weight(xiaomin_name, xiaomin_weight)
57+
58+
print('& ' * 100)
59+
60+
# 频繁重复传参和retutn主要是为了多实例,不然全局变量加函数就搞定了。演示面向过程实现多实例的需求,由于各种变量都是在调用地方传入和保存,所以这种面向过程的地方可以实现多实例,为了实现多实例导致重复传参和频繁return,导致代码无论在本身实现写法还是调用上,都极为复杂。例如演示这种方式实现多实例小王
61+
62+
# xiaowang_name = '小王'
63+
# xioamin_height = 130
64+
# xiaowang_weight = 35
65+
# show_height(xiaowang_name, xioamin_height)
66+
# show_weight(xiaowang_name, xiaowang_weight)
67+
# xioamin_height = grow_height(xiaowang_name, xioamin_height, 6)
68+
# xiaowang_weight = grow_weight(xiaowang_name, xiaowang_weight, 2)
69+
# show_height(xiaowang_name, xioamin_height)
70+
# show_weight(xiaowang_name, xiaowang_weight)
71+
# xiaowang_weight = pee(xiaowang_name, xiaowang_weight)
72+
# show_weight(xiaowang_name, xiaowang_weight)
73+
74+
# 这样的写法,如果要实现小红,那就十分麻烦了,因为小红的pee函数肯定不能这么运行。如果直接在此处修改函数,那代码就不能兼容小明 小王。导致又要全盘复制文件,庵后扣字,来重写pee函数。
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
# -*- coding: utf-8 -*-
2+
# @Author : ydf
3+
4+
"""
5+
复制粘贴扣字实现不同之处
6+
演示使用极端面向过程来写,由于没有封装,没有成员变量和全局变量,所以造成需要频繁传参和return.对于实现不同点全盘容易陷入复制文件全流程。
7+
女得有的函数不同。
8+
9+
"""
10+
11+
12+
def show_weight(name, weight):
13+
print(f'{name} 的体重是: {weight} 千克')
14+
15+
16+
def show_height(xingmin, height): # xingmin: xingmin也是代表姓名,故意弄成形参不是name,面向过程就会有这种搞不清楚一个参数在不同函数中是不是同一个意义的大缺点。
17+
print(f'{xingmin} 的身高是: {height} 厘米')
18+
19+
20+
def grow_weight(name, weight, growing_weight):
21+
weight += growing_weight
22+
print(f'{name} 的体重增加 {growing_weight} 千克')
23+
return weight # 必须把结果return到外部保存
24+
25+
26+
def grow_height(xinmin, height, growing_height):
27+
print(f'{xinmin} 的身高增加 {growing_height} 厘米')
28+
height += growing_height
29+
return height # 必须把结果return到外部保存
30+
31+
32+
def pee(name, weight):
33+
"""
34+
因为小便会导致体重发生变化,必须把原来的体重传进来。
35+
"""
36+
print(f'{name} 蹲着小便')
37+
return _reduce_weight_because_of_pee(weight) # 必须把结果return到外部保存
38+
39+
40+
def _reduce_weight_because_of_pee(tizhong):
41+
tizhong = tizhong - 0.001 # 体重的别名tizhong和weight是一样的,面向过程不使用实例属性,在很多函数中大量重复传参,形参就会可能不一致,导致看不懂代码。
42+
return tizhong
43+
44+
45+
if __name__ == '__main__':
46+
xiaohong_name = '小红'
47+
xiaohong_height = 110
48+
xiaohong_weight = 25
49+
show_height(xiaohong_name, xiaohong_height)
50+
show_weight(xiaohong_name, xiaohong_weight)
51+
xiaohong_height = grow_height(xiaohong_name, xiaohong_height, 5)
52+
xiaohong_weight = grow_weight(xiaohong_name, xiaohong_weight, 1) # 体重发生了变化,必须把结果return出来保存
53+
show_height(xiaohong_name, xiaohong_height)
54+
show_weight(xiaohong_name, xiaohong_weight) # 展示体重,需要把变化后的体重传进来
55+
xiaohong_weight = pee(xiaohong_name, xiaohong_weight) # 连上个厕所都需要把体重参数传进来,然后还要保存新结果,这样大量传参简直不要太low
56+
show_weight(xiaohong_name, xiaohong_weight)
57+
58+

0 commit comments

Comments
 (0)
Please sign in to comment.