Date: 2019-05-18
Author: SunnyChou
面向过程:面向处理,更多的是从计算机角度思考,注重计算每一个步骤,程序更像是一本cpu操作手册。
面向对象:以日常生活的角度思考问题的解决,更接近人的思维方式,让人可以从更高的层面考虑系统的构建
以你请朋友吃饭
面向过程 | 面向对象 |
---|---|
自己买菜 | 和朋友一块到饭店 |
自己摘菜 | 叫服务员点菜 |
自己洗菜 | 和朋友一块吃 |
自己做菜 | |
和朋友一块吃 |
面向对象的优点:
? 面向对象是一种思维方式,它认为万事万物皆对象,程序是由多个对象协作共同完成功能的,所以以后我们要从面向过程转向面向对象。以面向对象的方式考虑程序的构建。面向对象的核心是:类和对象
? 类是抽象的,在使用的时候通常会找到这个类的一个具体的存在,使用这个具体的存在。一个类可以找到多个对象。
? 对象是类的行为属性和数据属性进行具体化后的实例。
生活角度
? 类: 汽车 超级英雄 电脑 杯子
? 对象: 红色的宝马 美国队长 桌上的mac pro 老王的黑色杯子
? 类就相当于制造飞机时的图纸,用它来进行创建的飞机就相当于对象
程序角度
类:
成员属性(成员变量) 描述对象的静态特征,诸如,名字、身高体重
成员方法 描述对象的动态特征,例如:吃饭、睡觉、打豆豆
总之,类就是创建对象的模板
类(Class) 由3个部分构成
1)人类设计,只关心3样东西:
2)狗类的设计
#语法:
class 类名:
类体
注意:
(1) 定义一个Car类
# 定义类
class Car: #经典定义类,如果是Car(object)则为新式类
# 方法
def getCarInfo(self):
print(f'车轮子个数:{self.wheelNum}, 颜色:{self.color}')
def move(self):
print("车正在移动...")
(2) 成员方法
成员方法其实就是函数,作用域在类内,成员方法的第一个参数必须是self,self代表当前对象,也就是调用这个方法的对象,这个参数有系统传递。
class Dog(object):
def bark(self): #成员方法,第一个参数必须是self,代表当前调用对象
print('我是小可爱--丁丁')
dingding = Dog() #实例化一个对象
#调用方法,不需要传参数,self是系统传递的
#调用形式: 对象.方法([实参])
dingding.bark() #等价调用形式:bark(dingding)
注意:
? 上节2.3中定义了一个Car类;就好比有车一个张图纸,那么接下来就应该把图纸交给生成工人们去生成了。
python中,可以根据已经定义的类去创建出一个个对象。
创建对象的格式为:
对象名 = 类名()
创建对象:
# 定义类
class Car:
# 移动
def move(self):
print('车在奔跑...')
# 鸣笛
def toot(self):
print("车在鸣笛...嘟嘟..")
# 创建一个对象,并用变量BMW来保存它的引用
BMW = Car()
BMW.color = '黑色'
BMW.wheelNum = 4 #轮子数量
BMW.move()
BMW.toot()
print(BMW.color)
print(BMW.wheelNum)
说明:
另外说明:
#语法: 对象 = 类名([实参])
dingding = Dog() #实例化一个对象
print(dingding) #<__main__.Dog object at 0x00000000023F40B8>
print(type(dingding)) #<class '__main__.Dog'>
#查看对象的类名
print(dingding.__class__)
成员属性描述的是对象的静态特征,比如说狗名字、品种等,其实就是一个变量,作用域属于类,不会和类外的全局变量冲突。python中成员属性可以动态添加,也可以在构造函数中添加。成员属性属于对象,每个对象的成员属性都不同
理解self
python中__slots__
作用?
? 当一个类需要创建大量实例时,可以通过__slots__
声明实例所需要的属性,如果超过了此属性范围进行对象属性赋值,就会限制,起到保护数据作用。
例如,
class Foo(object):
? __slots__ = [‘foo‘]
这样做带来以下优点:
__dict__
的使用减少内存消耗? Python内置的字典本质是一个哈希表,它是一种用空间换时间的数据结构。为了解决冲突的问题,当字典使用量超过2/3时,Python会根据情况进行2-4倍的扩容。由此可预见,取消__dict__
的使用可以大幅减少实例的空间消耗。
#添加属性语法:
对象.成员属性 = 值
#引用方式:对象.成员属性
class Dog(object):
__slots__ = ('gender','name','age','kind') #这个类的对象这能有这些属性,同时也限制了采用__dict__属性可以用来查看实例属性
def __init__(self,name,kind,age):
self.name = name
self.kind = kind
self.age = age
def bark(tmp):
print('我是小可爱--丁丁')
dingding = Dog('丁丁','泰迪',3)
print('我是可爱的%s犬,%s,我今年%d岁了' % (dingding.kind, dingding.name, dingding.age))
dingding.gender = '公' #动态添加的属性
#dingding.weight = 8 #不能添加这个属性,语法错误
#查看实例属性
print(dingding.__dict__) #__dict__属性可以用来查看实例属性
print(dir(dingding)) #查看Dog的属性,包括实例属性
说明:
? python中类如何来保护成员属性和成员方法呢?
? 采用self.__xxx方式来定义类的成员。(两个下划线, 见 保护对象的属性)
目的:构造方法用于初始化对象,可以在构造方法中添加成员属性
时机:实例化对象的时候自动调用
参数:第一个参数必须是self,其它参数根据需要自己定义
返回值:不返回值,或者说返回None,不应该返回任何其他值
语法:
def __init__(self,arg1,arg2....):
函数体
#参数:arg1,agr2...根据需要自己定义
#如果自己不定义构造方法,系统自动生成一个构造函数
def __init__(self):
pass
注意:
如果没有定义构造方法,系统会生成一个无参构造方法,如果自己定义了构造方法,则系统不会自动生成
class 类名:
def __init__(self):
pass
一个类只能有一个构造方法,如果定义多个,后面的会覆盖前面的
构造函数由系统在实例化对象时自动调用,不要自己调用
class Dog(object):
def __init__(self,name,kind,age):
self.name = name #定义对象属性,这个类所有的对象都具有该属性
self.kind = kind #成员属性必须通过self.引用,否则是普通变量
self.age = age
def bark(tmp):
print('我是小可爱--丁丁')
dingding = Dog('丁丁','泰迪',3)
print('我是可爱的%s犬,%s,我今年%d岁了' % (dingding.kind, dingding.name, dingding.age))
目的:对象销毁时,释放资源
时机:对象销毁时由系统自动调用
参数:除了self外,没有其他参数
返回值:不返回值,或者说返回None。
语法:
def __del__(self):
#to do
案例
class Dog(object):
#构造
def __init__(self,name,kind,age):
self.name = name
self.kind = kind
self.age = age
#析构
def __del__(self):
print('拜拜了,二十年后又是一条好汉')
def bark(tmp):
print('我是小可爱--丁丁')
dingding = Dog('丁丁','泰迪',3)
print('我是可爱的%s犬,%s,我今年%d岁了' % (dingding.kind, dingding.name, dingding.age))
del dingding #销毁对象,自动调用析构方法
? 当删除一个对象时,python解释器也会默认调用一个方法,这个方法为__del__()
方法
如果有一个对象,当需要对其进行修改属性时,有2种方法
为了更好的保存属性安全,即不能随意修改,一般的处理方式为
class People(object):
def __init__(self, name):
self.__name = name
def getName(self):
return self.__name
def setName(self, newName):
if len(newName) >= 5:
self.__name = newName
else:
print("error:名字长度需要大于或者等于5")
xiaoming = People("dongGe")
print(xiaoming.__name)
此时就会出现错误。
class People(object):
name = 'Tom' #公有的类属性
__age = 12 #私有的类属性
p = People()
print(p.name) #正确
print(People.name) #正确
print(p.__age) #错误,不能在类外通过实例对象访问私有的类属性
print(People.__age) #错误,不能在类外通过类对象访问私有的类属性
Python中有一个被称为属性函数(property)的小概念,它可以做一些有用的事情。
- 将类方法转换为只读属性
- 重新实现一个类的属性的setter和getter方法
? Python内置的@property装饰器就是负责把一个方法变成属性调用的,特别在对属性数据进行校验的时候。
# -*- coding: utf-8 -*-
__author__ = 'sun'
__date__ = '2019/5/28 16:23'
class Student(object):
@property
def score(self):
return self._score
@score.setter
def score(self, value):
if not isinstance(value, int):
raise ValueError('score must be an integer!')
if value < 0 or value > 100:
raise ValueError('score must between 0 ~ 100!')
self._score = value
@score.deleter
def score(self):
if not hasattr(self, '_score'):
raise AttributeError('Student object has no attribute "_score"')
del self._score
s = Student()
s.score =99
print(s.score)
del s.score
? @property广泛应用在类的定义中,可以让调用者写出简短的代码,同时保证对参数进行必要的检查,这样程序运行时就减少了出错的可能性。
(1)id() 方法
? 获取对象在内存中的地址
创建对象,并打印对象地址
dingding2 = Dog('丁丁', '泰迪', 3)
print(id(dingding2))
(2) __str__()
方法
? 自定义打印对象内容,以字符串形式打印出来
案例:
class Car:
def __init__(self, newWheelNum, newColor):
self.wheelNum = newWheelNum
self.color = newColor
def __str__(self):
msg = "嘿。。。我的颜色是" + self.color + "我有" + int(self.wheelNum) + "个轮胎..."
return msg
def move(self):
print('车在跑,目标:夏威夷')
BMW = Car(4, "白色")
print(BMW)
? 是类对象所拥有的方法,需要用修饰器@classmethod
来标识其为类方法,对于类方法,第一个参数必须是类对象,一般以cls
作为第一个参数(当然可以用其他名称的变量作为其第一个参数,但是大部分人都习惯以‘cls‘作为第一个参数的名字,就最好用‘cls‘了),能够通过实例对象和类对象去访问。
class People(object):
country = 'china'
#类方法,用classmethod来进行修饰
@classmethod
def getCountry(cls):
return cls.country
p = People()
print p.getCountry() #可以用过实例对象引用
print People.getCountry() #可以通过类对象引用
需要通过修饰器@staticmethod
来进行修饰,静态方法不需要多定义参数
class People(object):
country = 'china'
@staticmethod
#静态方法
def getCountry():
return People.country
print People.getCountry()
综上:
? 从类方法和实例方法以及静态方法的定义形式就可以看出来,类方法的第一个参数是类对象cls,那么通过cls引用的必定是类对象的属性和方法;而实例方法的第一个参数是实例对象self,那么通过self引用的可能是类属性、也有可能是实例属性(这个需要具体分析),不过在存在相同名称的类属性和实例属性的情况下,实例属性优先级更高。静态方法中不需要额外定义参数,因此在静态方法中引用类属性的话,必须通过类对象来引用
在现实生活中,继承一般指的是子女继承父辈的财产
在程序中,继承描述的是事物之间的所属关系,例如猫和狗都属于动物,程序中便可以描述为猫和狗继承自动物
# 定义一个父类,如下:
class Cat(object):
def __init__(self, name, color="白色"):
self.name = name
self.color = color
def run(self):
print("%s--在跑"%self.name)
# 定义一个子类,继承Cat类如下:
class Bosi(Cat):
def setNewName(self, newName):
self.name = newName
def eat(self):
print("%s--在吃"%self.name)
bs = Bosi("印度猫")
print('bs的名字为:%s'%bs.name)
print('bs的颜色为:%s'%bs.color)
bs.eat()
bs.setNewName('波斯')
bs.run()
说明:
多重继承
class base(object):
def test(self):
print('----base test----')
class A(base):
def test(self):
print('----A test----')
# 定义一个父类
class B(base):
def test(self):
print('----B test----')
# 定义一个子类,继承自A、B
class C(A,B):
pass
obj_C = C()
obj_C.test()
print(C.__mro__) #可以查看C类的对象搜索方法时的先后顺序
? 所谓重写,就是子类中,有一个和父类相同名字的方法,在子类中的方法会覆盖掉父类中同名的方法
class Cat(object):
def sayHello(self):
print("halou-----1")
class Bosi(Cat):
def sayHello(self):
print("halou-----2")
bosi = Bosi()
bosi.sayHello()
调用父类的方法
class Cat(object):
def __init__(self,name):
self.__id = id #私有的,不被继承到子类
self.name = name
self.color = 'yellow'
class Bosi(Cat):
def __init__(self,name):
# 调用父类的__init__方法1(python2)
#Cat.__init__(self,name)
# 调用父类的__init__方法2
#super(Bosi,self).__init__(name)
# 调用父类的__init__方法3
super().__init__(name)
def getName(self):
return self.name
bosi = Bosi('xiaohua')
print(bosi.name)
print(bosi.color)
多态的概念是应用于Java和C#这一类强类型语言中,而Python崇尚“鸭子类型”。
所谓多态:定义时的类型和运行时的类型不一样,此时就成为多态
Python “鸭子类型”
class F1(object):
def show(self):
print 'F1.show'
class S1(F1):
def show(self):
print 'S1.show'
class S2(F1):
def show(self):
print 'S2.show'
def Func(obj):
print obj.show()
s1_obj = S1()
Func(s1_obj)
s2_obj = S2()
Func(s2_obj)
python3的面向对象编程其实还有一些高级应用,大部分工作中不会用到
敬请期待后续课程
原文:https://www.cnblogs.com/sunBinary/p/10940936.html