一、面向对象的简介
1、面向对象(OO)
按人们认识客观世界的系统思维方式,采用基于对象(实体)的概念建立模型,模拟客观世界分析、设 计、实现软件的办法。
2、面向对象编程(OOP)
一种解决软件复用的设计和编程方法。 这种方法把软件系统中相似的操作逻辑和操作应用数据、状态,以类的型式描述出来,以对象实例的形式在软件系统中复用,以达到提高软件开发效率的作用。
3、类(Class) 由3个部分构成
- 类的名称:类名
- 类的属性:一组数据
- 类的方法:允许进行操作的方法 (行为)
二、类和对象
1、定义类与创建对象
# 定义类
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)
关键词:
- 第一次使用BMW.color = '黑色'表示给BMW对象添加属性,如果后面再次出现BMW.color = xxx表示对属性进行修改。(这是添加属性的一种方法,还有一种在__init()__中添加)
- 类中的方法定义,第一个参数是self,对象调用时代表着对象本身。
- 类的方法满足函数的特性:参数、返回值等。
2、self关键字
- 可以把self当做C++中类里面的this指针一样理解,就是对象自身的意思.
- 某个对象调用其方法时,python解释器会把这个对象作为第一个参数传递给self,所以开发者只需要传递后面的参数即可.
三、方法和属性
1、魔法方法(Python类的名称是__xxx__()
的方法有特殊的功能,叫做“魔法”方法)
-
__init()__方法
# 定义汽车类
class Car:
def __init__(self, newWheelNum, newColor):
self.wheelNum = newWheelNum
self.color = newColor
def move(self):
print('车在跑,目标:夏威夷')
# 创建对象
BMW = Car(4, 'green')
print('车的颜色为:%s'%BMW.color)
print('车轮子数量为:%d'%BMW.wheelNum)
关键词:
- 在创建对象时,
__init__()
方法会自动的执行,生成对象时,要将__init__()方法
的参数传进去(self不用) - 类的属性一般在该函数内添加及初始化
-
__str()__方法
该方法在使用print该对象时候会调用,如果没有重写的话会打印<__main__.Car object at 0x7f3c58b94b70>这种内存地址信息.如果改写该函数,会打印该函数的返回值.
-
__del()__方法
- 当有1个变量保存了对象的引用时,此对象的引用计数就会加1
- 当使用del删除变量指向的对象时,如果对象的引用计数不会1,比如3,此时只会让引用计数减1,即变为2,再次调用del时,变为1,再调用1次del,此时会真的把对象进行删除,概括一下就是该对象的全部引用被删除才会调用__del()__方法.
class Animal(object):
# 初始化方法
# 创建完对象后会自动被调用
def __init__(self, name):
print('__init__方法被调用')
self.__name = name
# 析构方法
# 当对象被删除时,会自动被调用
def __del__(self):
print("__del__方法被调用")
print("%s对象马上被干掉了..."%self.__name)
# 创建对象
dog = Animal("哈皮狗")
# 删除对象
del dog
cat = Animal("波斯猫")
cat2 = cat
cat3 = cat
print("---马上 删除cat对象")
del cat
print("---马上 删除cat2对象")
del cat2
print("---马上 删除cat3对象")
del cat3
print("程序2秒钟后结束")
time.sleep(2)
2、隐藏公有属性(直接访问不报错)
可以直接对属性修改,但是有时候最好通过方法简介修改,一则可以起到隐藏属性的作用,二则再发方法中可以同时对修改值进行合法判断。
3、封装之私有属性(程序隐藏,直接访问报错)
- Python中没有像C++中public和private这些关键字来区别公有属性和私有属性。
- 以属性命名方式来区分,在属性名前面加了2个下划线'_',则表明该属性是私有属性,否则为公有属性(方法也是一样,方法名前面加了2个下划线的话表示该方法是私有的,否则为公有的)。
- 方式:将属性定义为私有属性,添加一个可以调用的方法,供修改私有属性。
- 注意所谓的私有是在对象中不可用,在子类中也不能用,但是在该类中可以用。
四、继承
1、单继承
- 单继承语法:在定义类时,小括号()中为父类的名字
- 可继承的:父类的公有属性、公有方法,魔术方法会被继承给子类,
- 不可继承的:私有属性和私有方法不可继承。但可以通过继承来的公有方法访问父类中的私有属性和方法。
- 方法重写:子类中和父类重名的方法会覆盖掉继承来的方法
- 调用父类方法:如果想去调用父类方法,即使是同名方法,使用super().同名方法
- 尤其是重写了__init()__的话,父类的属性也会被覆盖无法继承,如果使用super().__init__()会可以继承下来.
2、多继承
- python中是可以多继承的,父类中的方法、属性,子类会继承
- 如果父类A和父类B中,有一个同名的方法,那么通过c子类去调用的时候,调用哪个:print(C.__mro__)可以看到内部的执行顺序。
五、多态
所谓多态:定义时的类型和运行时的类型不一样,此时就成为多态
程序说明:一个父类两个子类的同名方法与一个函数(形参为obj,功能调用同名方法)的故事,如下程序:
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)
关键词:Python多态和java不同,java作为强类型语言,函数的参数类型为父类类型
六、区别两个易混的概念
1、类属性和实例属性
什么是类属性?通过以下程序比对实例属性得出结论:
class People(object):
name = 'human' #公有的类属性
__age = 10000 #私有的类属性
def __init__(self, height, Color):
self.height = height #实例公有属性
self.__color = Color #实例私有属性
p = People(180,'黄种人')
print(p.name) #正确
print(People.name) #正确
print(p.height) #正确
print(p.__age) #错误,不能在类外通过实例对象访问私有的类属性
print(People.__age) #错误,不能在类外通过类对象访问私有的类属性
print(p.__color) #错误,不能在类外通过实例对象访问私有的实例属性
- 类属性的本质:类属性就是类对象所拥有的属性,它被所有类对象的实例对象所共有,在内存中只存在一个副本。
- 类属性和实例属性在定义上的不同:self.之后是实例属性,否则是类属性。
- 类属性和实例属性在使用上的易冲突点:如果需要在类外修改类属性,必须通过类对象去引用然后进行修改。如果通过实例对象去引用,会产生一个同名实例属性,这种方式修改的是实例属性,不会影响到类属性,并且之后如果通过实例对象去引用该名称的属性,实例属性会强制屏蔽掉类属性,即引用的是实例属性,除非删除了该实例属性。
2、类方法和静态方法
(1)类方法
定义:类对象所拥有的方法,需要用修饰器@classmethod
来标识其为类方法,对于类方法,第一个参数是类对象,一般以cls
作为第一个参数(当然可以用其他名称的变量作为其第一个参数)
访问:能够通过实例对象和类对象去访问。
作用:可以对类属性进行修改。
class People(object):
country = 'china'
#类方法,用classmethod来进行修饰
@classmethod
def getCountry(cls):
return cls.country
@classmethod
def setCountry(cls,country):
cls.country = country
p = People()
print p.getCountry() #可以用过实例对象引用
print People.getCountry() #可以通过类对象引用
p.setCountry('japan')
print p.getCountry()
print People.getCountry()
(2)静态方法
定义:需要通过修饰器@staticmethod
来进行修饰,静态方法不需要多定义参数。
class People(object):
country = 'china'
@staticmethod
#静态方法
def getCountry():
return People.country
print People.getCountry()
对比得结论:
从类方法和实例方法以及静态方法的定义形式就可以看出来:
- 类方法的第一个参数是类对象cls,那么通过cls引用的必定是类对象的属性和方法;
- 实例方法的第一个参数是实例对象self,那么通过self引用的可能是类属性、也可能是实例属性,不过在存在相同名称的类属性和实例属性的情况下,实例属性优先级更高;
- 静态方法中不需要额外定义参数,因此在静态方法中引用类属性的话,必须通过类对象来引用。