我们都知道Python是一门灵活度很高的语言,它可以面向过程,面向对象,那我们今天说说Python中的面向对象设计和面向对象编程的区别
面向对象设计和面向对象编程都提到了“面向对象”, 那么首先我们要搞清楚什么是对象
对象:我们可以简单的理解为我们见到的每个实际存在的事物就是一个对象,如果一个人,一座房子,一只小猫等。
那么我们想想,我们怎么面向对象,那就是以对象为中心,去描述这个对象,这个对象有什么特点,什么属性,什么功能等,想想假如你要去向别人描述一个丢失的小猫(一个对象),你要怎么描述呢?小够的品种,大小,毛色,等等。 当你把着一些特征或者属性描述清楚之后,一个对象就被定义下来了。
知道对象的概念之后,我们进入主题
1.面向对象设计
说到设计,我们可以理解为是一种想法,思路,就是把对象的属性,功能(python里用函数表达)糅合在一起形成一个对象,这种思想可以简单的理解为面向对象设计,不是说必须用CLASS这种,才叫面向对象设计,下面我们举个例子
def cat(name,gender,type):
# 猫的的动作或者叫功能
def cry(cat):
print('一条小猫[%s],喵喵' % cat['name'])
def run(cat):
print('一条[%s]小猫正在跑' % cat['type'])
def init(name,gender,type):
cat = {
'name':name,
'gender': gender,
'type': type,
'cry':cry,
'run':run,
}
return cat
return init(name,gender,type)
cat=cat('毛球','公','波斯猫')
print(cat)
cat['cry'](cat)
结果
{'name': '毛球', 'gender': '公', 'type': '波斯猫', 'cry': <function cat.<locals>.cry at 0x0000022C6C9B71E0>, 'run': <function cat.<locals>.run at 0x0000022C6C9B7158>}
一条小猫[毛球],喵喵
上面我们用纯函数的方式去描述了一只小猫,但是我们也可以把上面这张方式理解为面向对象设计,因为上面我们把猫的属性和功能函数结合在一起,形式了一个对象。
我们用
cat=cat('毛球','公','波斯猫')
来生成一个对象,我们可以调用对象的属性和函数等等,这些都是我们熟悉的面向对象设计,但是我们不能说这种方式叫面向对象编程。
2.面向对象编程,
这个在很多语言中都在大量使用,简单的说使用Class来描述对象的方式就是面向对象编程。Python中当然也可以使用面向对象编程,但是不强求,如JAVA之类的编程语言就强制要求使用面向对象编程,个人认为不太友好。下面我们把上面的例子改成面向对象编程的方式来看看
class Cat:
def __init__(self,name,gender,type):
self.name = name
self.gender = gender
self.type = type
def cry(self):
print('一条小猫[%s],喵喵' % self.name)
def run(self):
print('一条[%s]小猫正在跑' % self.type)
cat = Cat('毛球','公','波斯猫')
print(Cat)
cat.cry()
上面我们改成了个class的方式来编程,可以说就是使用面向对象编程的方式。也是我们熟悉的类方式。
3.面向对象编程的基础知识点拨
3.1类和函数的属性分类
类属性包含:数据属性和函数属性
对象属性包括:数据属性,对象如果向调用函数属性,其实是调用的类的函数属性
类的数据属性是所有对象共享的
类的函数属性是绑定给对象用的
怎么理解呢?我们可以使用__dict__方法来看属性
class Cat:
weight = 5; #新定义了一个类的数据属性
def __init__(self,name,gender,type): #实例属性
self.name = name
self.gender = gender
self.type = type
def cry(self): #类的函数属性
print('一条小猫[%s],喵喵' % self.name)
def run(self): #类的函数属性
print('一条[%s]小猫正在跑' % self.type)
cat = Cat('毛球','公','波斯猫')
print(Cat.__dict__)
print(cat.__dict__)
结果
{'__module__': '__main__', 'weight': 5, '__init__': <function Cat.__init__ at 0x0000021E5DC671E0>, 'cry': <function Cat.cry at 0x0000021E5DC67158>, 'run': <function Cat.run at 0x0000021E5DC67268>, '__dict__': <attribute '__dict__' of 'Cat' objects>, '__weakref__': <attribute '__weakref__' of 'Cat' objects>, '__doc__': None}
{'name': '毛球', 'gender': '公', 'type': '波斯猫'}
上面一行是类的属性,我们可以看到我们定义的weight,'cry','run'等类的数据和函数属性
下面一行是对象的属性,只有init里面定义的数据属性,没有函数属性
当函数想调用方法时,是先从自己的属性里面找,如果没有就去上层类的__dict__里面去寻找,执行,所以我们说对象执行方法其实执行的是类的函数属性。
我们看到上面__dict__里面还有一些其他自带属性解释如下
#python为类内置的特殊属性
类名.__name__# 类的名字(字符串)
类名.__doc__# 类的文档字符串
类名.__base__# 类的第一个父类(在讲继承时会讲)
类名.__bases__# 类所有父类构成的元组(在讲继承时会讲)
类名.__dict__# 类的字典属性
类名.__module__# 类定义所在的模块
类名.__class__# 实例对应的类(仅新式类中)
3.2 self到底什么意思,什么时候使用
self我们可以理解为实例对象自己,那为什么在面向对象编程的时候,类的每个函数都要在第一个参数放self呢? 我的理解一方面是面向对象编程的语法需要,二深层次的说是把类的数据属性和函数属性糅合在一起,满足面向对象设计的思想
self在对象实例化的时候,会自动传入,如果函数属性里面不定义self会报错
class Cat:
weight = 5;
def __init__(self,name,gender,type):
self.name = name
self.gender = gender
self.type = type
def cry(): #没有写self
print('一条小猫喵喵')
def run(self):
print('一条[%s]小猫正在跑' % self.type)
cat = Cat('毛球','公','波斯猫')
cat.cry() #对象调用类的函数属性时候,会自己传入self也就是实例自己,作为第一个参数
结果报错
Traceback (most recent call last):
File "C:/Users/aryin/Desktop/mysite2/面向对象.py", line 14, in
cat.cry()
TypeError: cry() takes 0 positional arguments but 1 was given
仔细看报错,cry() takes 0 positional arguments but 1 was given,说我们给它传了一个参数,但是上面的代码里,我们什么也没传,所以这是python自己给我们默认传了一个self参数
那我们看看我们直接用类自己来调用它的函数属性,看看会不会自己传入self参数
class Cat:
weight = 5;
def __init__(self,name,gender,type):
self.name = name
self.gender = gender
self.type = type
def cry(self): #没有写self
print('一条小猫喵喵')
def run(self):
print('一条[%s]小猫正在跑' % self.type)
cat = Cat('毛球','公','波斯猫')
Cat.cry() #类调用自己的函数属性,不传入参数
结果报错
Traceback (most recent call last):
File "C:/Users/aryin/Desktop/mysite2/面向对象.py", line 15, in
Cat.cry()
TypeError: cry() missing 1 required positional argument: 'self'
看错误是少了一个参数,说明当类自己调用函数属性的时候,不会自己传入self,cry函数需要一个参数self,所以报错了,所以正确的使用是
class Cat:
weight = 5;
def __init__(self,name,gender,type):
self.name = name
self.gender = gender
self.type = type
def cry(self): #没有写self
print('一条小猫喵喵')
def run(self):
print('一条[%s]小猫正在跑' % self.type)
cat = Cat('毛球','公','波斯猫')
Cat.cry(cat) #类调用自己的函数属性,不传入参数
所以只有当对象去调用类的函数属性或者说方法的时候才会自动传入self属性,类自己调用时候不会,要自己传入实例。
当然我们一般不这么使用类来调用自己的函数属性,我们可以使用类方法来实现调用
class Cat:
weight = 5;
def __init__(self,name,gender,type):
self.name = name
self.gender = gender
self.type = type
@classmethod
def cry(cls): #没有写self print('一条小猫喵喵')
def run(self):
print('一条[%s]小猫正在跑' % self.type)
Cat.cry()
结果:
一条小猫喵喵
这里看到改动的地方,是传入的cls, 就是类自己,classmethod类静态方法实现类调用自己的函数属性时候不需要显示传入cls参数,而是自动传入,classmethod类静态方法实际就是绑定了类和自己的函数属性。
3.3 实例化到底做了什么(__init__方法)
当对象实例化的时候,会先去执行__init__函数,对象会去__init__里面找到自己的数据属性
class Cat:
weight = 5;
def __init__(self,name,gender,type):
print('开始初始化')
self.name = name
self.gender = gender
self.type = type
print('结束初始化')
def cry(self): #没有写self
print('一条小猫喵喵')
def run(self):
print('一条[%s]小猫正在跑' % self.type)
cat=Cat('毛球','公','波斯猫') #实例化
print(cat.__dict__)
结果:
开始初始化
结束初始化
{'name': '毛球', 'gender': '公', 'type': '波斯猫'}
看到__init__函数里面已经执行了,对象的数据属性也得到了。
今天说到这里,个人意见,望指教。
更多源代码文章请关注:pythonislover