面向对象和面向过程
是指编程思想 。这两个概念在语法上不存在充分条件,比如没有说法说使用了类和对象就是面向对象,它们的充分条件只有代码整体是按照现实参与对象组织,还是描述过程。但是它们有必要条件。必须使用了一些东西才可能是面向对象。有状态函数和多态。但即使有了这些也不能说这就是面向对象。封装是面向对象的必要非充分条件。如果看不懂没事,有一点印象结尾会去讲。
面向对象的必要条件
单纯的函数
一个单纯的函数是无状态的。即函数的每次的输出或执行的操作都只取决于它的输入和逻辑。
比如最简单的加法函数,当输入相同时输出必定相同。
def add(a,b):
return a+b
很明显这样的函数无法解决现实中复杂的问题。
比如同样执行写博客这个动作。
我在高兴时和伤心时,写这个动作的执行并不一样。
如果我们想让程序做复杂的事情必须需要有状态的函数。
面向过程
为了解决这个问题,我们先看一下面向过程是怎么做的。
def write(state):
if state == "sad":
print("写的很慢")
elif state == "happy":
print("写的很快")
def be_criticized(state):
"""
被批评了
"""
state = "sad"
return state
def eat(state):
state = "happy"
return state
state = "sad"
state = eat(state)
write(state)
state = be_criticized(state)
write(state)
我们使用无状态的函数,将状态写成参数,实现了不同状态下的写作行为。
但是我们可以发现,我们把state传来传去。
一旦我们忘记更新状态就会出错。又比如我调用其它人写的方法。我必须要看注释,我需要不需要获取状态。这种写法就是面向过程的写法。
这里埋个点,看完后再回来,思考为什么这段代码是面向过程。它没有面向对象的必要条件。所以我们不可能去把它当面向对象。如果看不懂,可以先跳过,看完再试试。
有没有办法让函数拥有状态呢?
闭包
def avg():
s = 0
i = 0
def inner(n):
nonlocal s, i
s += n
i += 1
return s / i
return inner
a = avg()
print(a(10))
print(a(20))
print(a(20))
我们发现对于同一个输入20,函数输出不同了。函数有状态了。
但是闭包函数并没有完全解决我们的问题。 因为我们发现只有一个函数会对状态进行操作,而我们想要的效果时其它函数更新了状态也会影响到我这个函数的执行。
但不要慌,闭包函数虽然没有解决问题,但给了我们灵感如何解决这个问题,必须把状态和行为封装在一起。
按照这个思想。我们解决多个函数对属性的引用,就是对象。
对象
class person:
def __init__(self):
self.state="sad"
def eat(self):
self.state="happy"
def be_criticized(self):
self.state="sad"
def write(self):
if self.state=="happy":
print("写的很快")
else:
print("写的很慢")
p=person()
p.eat()
p.write()
p.be_criticized()
p.write()
所以面向对象,就是一系列的有状态函数。
类
既然对象有状态了,我们就会想到,是否需要不同对象有不同的状态。类是创建对象的模板。但本质目的是让不同对象同时有不同的状态。即实例化。
有状态函数
有状态的函数是面向对象的核心概念。理解了状态函数,我们可以解决很多问题。尤其是何时使用类。
类中可以有无状态函数吗。
不推荐,这是毫无意义的。
面向对象的本质就是有状态的函数的集合。类中的方法。必须对对象属性,读或写其中至少一个操作。
比如这样,pycharm会警告你。当你让pycharm修改,他会把这个函数给你拉到外面。
所以当你看到类中一个函数体里没任何self.属性。你可以很肯定,这个人没领会对象是什么意思。
pycharm提示我们把函数写到外面。这又引出一个问题。java中至少有一个类,但python不同,它可以把函数写到模块中的。
那么如何抉择呢。就根据函数的性质来。
当多个函数共享状态,且不同对象表现不同时就用对象。 这两个都需要时用类,其它情况也可以用但会有其它替代品。
多状态
多状态有必要仔细讲一下。不同对象。什么叫不同对象。一只胖狗和瘦狗一定是不同对象吗。不一定,这个狗可能吃胖了。一个狗坐着,一只狗站着可能是一个对象吗?可能它站起来了。但是如果这些动作同时发生,那绝对是两只狗。还有一只泰迪和金毛肯定不是同一只。所以我们可以知道程序中何时需要不同对象。同时,同时,同时。这个同时是重点,需要同时属性不同,行为不同。或不可变属性不同,否则无需使用多态。也无需使用类的概念。直接将函数写到模块里。
这叫单例。
python中模块即是单例。
何时用类。
我们提到了当多个函数共享状态,且不同对象表现不同时就用对象。 这两个都需要时用类,其它情况也可以用但会有其它替代品。有哪些替代呢?
无状态: 函数无状态时,无需讨论单函数无状态,还是多函数。需不需多态。直接写到模块里。
单函数 有状态,不多状态 。1 函数+全局变量 2闭包,但人为的不多次实例化。
单函数 有状态, 多状态 1闭包函数
多函数 有状态 不多状态 1全局变量
多函数 有状态 多状态 类。
c 是面向过程的语言???
面向对象是个思想,只要符合上诉条件,都可以面向对象编程。c中有结构体。封装属性和方法,它也可以面向对象。只比较麻烦。
什么叫必要非充分
当使用了全局变量,我们也可让函数,同一个输入表现不同如。
state=""
def write():
if state == "sad":
print("写的很慢")
elif state == "happy":
print("写的很快")
def be_criticized():
"""
被批评了
"""
global state
state = "sad"
return state
def eat():
global state
state = "happy"
return state
eat()
write()
be_criticized()
write()
使用了全局变量。
此时函数也有状态。但这是面向过程还是对象。看你的想法。一般的我们认为这是面向过程但是真的吗?
import client
client.write()
client.be_criticized()
client.write()
有没有感觉这和对象很像。我们导入那个模块,按对象那样用,只是模块是单例,无法多态。那能不能面向对象呢
使用了类就是面向对象了,不一定。比如单例类,我这个类就一个对象,你会发现它和使用全局变量差不多,我们可以完全用类来面向过程,而不完全使用类的性质。为什么要这样。因为类可以继承,可以实现特殊方法。快速实现某个功能。但在思想上,我就是只调用函数。描述个过程。比如
class person:
def __init__(self):
self.state="sad"
def eat(self):
self.state="happy"
def be_criticized(self):
self.state="sad"
def write(self):
if self.state=="happy":
print("写的很快")
else:
print("写的很慢")
p=person()
p.eat()
p.write()
p.be_criticized()
p.write()
如果整体代码中,我不把它当做对象,就看作我描述了一个过程,写吃东西写博客了,被批评了写博客。而且仔细对比,他和我们使用全局变量的区别就是全局变量不能多态。但如果在代码逻辑里我们不使用多状态,就一个对象,它和我们全局变量有什么区别呢。
如果一个函数没有状态函数,他绝对不可能是面向对象,想想现实中什么东西,没有状态或没有任何行为去用状态和改状态。一个我们能想到最简单的对象一个物体小方块。它都有位置这个状态。他收到的重力需要他位置这个状态。但如果一个函数有状态了。可以当作面向对象也可以是面向过程,充分条件是你的思想,描述过程还是对象。