面向过程 & 面向对象(oop: object oriented programming)
面向过程:—侧重于怎么做?
1.把完成某一个需求的 所有步骤 从头到尾 逐步实现
2.根据开发要求,将某些功能独立的代码封装成一个又一个函数
3.最后完成的代码,就是顺序的调用不同的函数
特点:
1.注重步骤和过程,不注重职责分工
2.如果需求复杂,代码变得非常复杂
3.开发复杂的项目的时候,没有固定的套路,开发难度很大
面向对象:----侧重于谁来做?
相比较函数,面向对象是更大的封装,根据职责在一个对象中封装多个方法
1.在完成某一个需求前,首先确定职责–要做的事(方法)
2.根据职责确定不同的对象,在对象内部封装不同的方法(多个)
3.最后完成代码,就是顺序的让不同的对象调用不同的方法
特点:
1.注重对象和职责,不同的对象承担不同的职责
2.更加适合对复杂的需求变化,是专门应对复杂项目的开发,提供固定的套路
3.需要在面向过程的基础上,再学习一些面向对象的语法
面向对象所用到的技术简介:
(1)类(class):用来描述具有相同的属性和方法的对象的集合。它定义了该集合中每个对象所共有的属性和方法。对象是类的实例。
(2)对象:通过类定义的数据结构实例。对象包括两个数据成员(类变量和实例变量)和方法,对象可以包含任意数量和类型的数据。
(3)方法:类中定义的函数
(4)类变量:类变量在整个实例化的对象中是公用的。类变量定义在类中且在函数体之外。类变量通常不作为实例变量使用。
(5)实例变量:在类的声明中,属性是用变量来表示的。这种变量就称为实例变量,是在类声明的内部但是在类的其他成员方法之外声明的。
(6)数据成员:类变量或者实例变量用于处理类及其实例对象的相关的数据。
(7)方法重写:如果从父类继承的方法不能满足子类的需求,可以对其进行改写,这个过程叫方法的覆盖(override),也称为方法的重写。
(8) 局部变量:定义在方法中的变量,只作用于当前实例的类。
(9)继承:即一个派生类(derived class)继承基类(base class)的字段和方法。继承也允许把一个派生类的对象作为一个基类对象对待。
(10)实例化:创建一个类的实例,类的具体对象。
面向对象的三大特征
**封装:**根据职责将属性和方法封装到一个抽象的类中
**继承:**实现代码的复用,相同的代码不需要重复的编写
**多态:**不同的子类对象调用相同的父类方法,会产生不同的执行结果
面向对象的两个核心
类:是一类具有相同特征或行为的事物的一个统称
对象:由类创建出来的一个具体的存在
类和对象的关系:先有类再有对象
类是模板 对象是根据这个模板创建出来的
类只需要有一个 对象可以有多个
类:属性(这一类事务的共同信息) 和 方法(你能完成的动作)
1.类名:这类事物的名字(大驼峰命名法)(类命名时不能有下划线)
大驼峰命名法:a.每个单词的首字母大写,b.单词与单词之间没有下划线
2.属性:这个类创建出来的对象有什么特征(相当于变量)
3.方法:这个类创建出来的对象有什么行为(相当于要执行的函数)
属性和方法的确定
对 对象的特征描述,通常可以定义成属性
对象具有的行为(动词),通常可以定义为方法
提示:需求中没有涉及的属性或方法在设计类时,不需要考虑
类的调用
self:
哪一个对象调用的方法,self就是哪一个对象的引用(指向对象的内存地址空间)
在调用方法的时候,程序员不需要传递self参数(定义的时候 第一个参数必须是self)
类的封装(可以认为是定义类)
# 定义一个猫类
class Cat:
# 属性
name = 'tom'
age = '10'
# 方法
def eat(self):
print('%s 吃鱼' %(self.name))
def drink(self):
print('猫要喝水')
# 定义一个猫类
class Cat:
# 属性
name = 'tom'
age = '10'
# 方法
def eat(self):
print('%s 爱吃鱼' %(self.name))
def drink(self):
print('猫要喝水')
类的继承
class Animal:
def eat(self):
print('吃~~~Animal')
def drink(self):
print('喝~~~Animal')
def run(self):
print('跑~~~Animal')
class Cat(Animal):
# 父类有,覆盖父类中的方法
def run(self):
print('跑~~~Cat')
# 父类无,添加方法
def sleep(self):
print('睡~~~Cat')
def call(self):
print('Cat喵喵')
class HelloKitty(Cat):
def sepak(self):
print('HelloKitty可以说日语!!')
def call(self):
# 调用原本在父类中封装的方法
super().call()
# Cat.call(self) python2.x
print('HelloKitty$#%$#%$#')
kt = HelloKitty()
kt.eat()
kt.drink()
kt.run()
kt.call()
kt.sepak()
初始化函数__init__
init 是初始化函数,用来定义一些对象默认的属性
class Car:
def __init__(self,name):
self.name = name
self.color = '白色'
self.num = '2019'
def move(self):
print('%s移动' %self.name)
car1 = Car('宝马')
print(car1.color)
print(car1.num)
car1.move()
car2 = Car('法拉利')
print(car2.color)
print(car2.num)
car2.move()
__str__函数
python中 使用print输出对象变量时候,默认情况下
会输出这个变量引用的对象是由哪一个类创建的对象以及在内存中的地址
如果在开发中,希望使用print输出变量的时候,能够打印自定义内容
就可以利用__str__这个内置的方法了
class person:
def __init__(self,name,age,weight):
self.name = name
self.age = age
self.weight = weight
def __str__(self):
return '%s %s %s' %(self.name,self.age,self.weight)
ll = person('lilei',20,50)
print(ll)
__del__函数
如果希望在对象被销毁之前,再做一些事情,可以考虑一下__del__
当一个对象被从内存中销毁前(把这个对象从内存中删除掉),会自动调用__del__函数
class Car:
def __init__(self,name):
self.name = name
self.color = '白色'
self.num = '2019'
def move(self):
print('%s移动' %self.name)
def __str__(self):
return '%s %s %s ' %(self.name,self.color,self.num)
def __del__(self):
print('%s 已经被删除' %self.name)
car1 = Car('宝马')
print(car1)
car2 = Car('法拉利')
print(car2)
多态
不同的子类对象调用相同的父类方法,会产生不同的执行结果
class cat:
def __init__(self,name):
self.name = name
def game(self):
print('%s play happily' %self.name)
class tom(cat):
def game(self):
print('%s play sad' %self.name)
class person(object):
def __init__(self,name):
self.name = name
def game_with_cat(self,cat):
print('%s %s palyed' %(self.name,cat.name))
c1 = cat('lalala')
c2 = tom('hehehe')
xiaoming = person('小明')
c1.game()
xiaoming.game_with_cat(c1)
c2.game()
xiaoming.game_with_cat(c2)
类属性,类方法
类属性:针对类对象定义的属性 使用赋值语句在class关键字下可以定义类属性
类方法:针对类对象定义的方法 在类方法内部可以直接访问类属性或调用其他的类方法
class Toy(object):
# 使用赋值语句定义类属性 记录所有的玩具数量
count = 0
def __init__(self,name):
self.name = name
# 让类属性+1
Toy.count += 1
@classmethod
def show_toy_count(cls):
print('玩具对象的数量 %d' %(cls.count))
#创建玩具对象
Toy.show_toy_count()
toy1 = Toy('乐高')
Toy.show_toy_count()
toy2 = Toy('泰迪熊')
Toy.show_toy_count()
通过类名.方法名直接调用
class Cat(object):
@staticmethod
def call():
print('喵喵')
# 通过 类名.方法名 调用静态方法
Cat.call()
# 不需要创建对象 直接就可以调用
单例设计模式
设计模式
设计模式是前人工作的总结和提炼,通常,被人们广泛流传的设计模式都
是针对某一特定问题的成熟解决方案
使用设计模式是为了可重用代码,让代码更容易被他人理解,
保证代码可靠性
单例设计模式
目的:让类创建对象,在系统中只有唯一的一个实例(对象)
每一次执行类名()返回的对象
内存地址是相同的
#怎么保证 这些对象只有一个?
__new__方法:
我们用 类名. 的方式创建对象的时候,python解释器会帮我们做两件事情,是哪两件事情呢?
1.为对象分配空间 2.对象初始化
使用类名()创建对象时,python的解释器首先会调用__new__方法为对象分配空间
__new__是一个由object基类提供的内置的静态方法,主要有两个作用:
在内存中为对象分配空间
返回对象的引用
python的解释器获得对象的引用后,将引用作为第一个参数,传递给__init__方法
#new:负责给对象分配空间 init(初始化方法)负责给对象初始化
我们要重写new方法,使用类名()创建对象的时候,返回的都是同一个地址
重写__new__方法的代码非常固定:
继承自父类方法
返回父类方法调用_new__方法的结果
重写__new__方法一定要return object.new(cls)
否则python的解释器得不到分配了空间的对象引用,就不会调用对象的初始化方法
class MusicPlayer(object):
instance = None
def __new__(cls, *args, **kwargs):
print('创建对象 分配空间')
# 1.创建对象的时候,new方法会被自动调用
# instance = object.__new__(cls)
# return instance # 返回的就是对象的引用
# 判断类属性是否为空
if cls.instance is None:
# 调用父类方法 为第一个对象分配空间
cls.instance = object.__new__(cls)
return cls.instance
player1 = MusicPlayer()
player2 = MusicPlayer()
player3 = MusicPlayer()
print(player1)
print(player2)
print(player3)
类的私有方法
两个下划线开头,声明该方法为私有方法,只能在类的内部调用 ,不能在类的外部调用
class Student(object):
def __init__(self, name, score):
# 前面带两个下划线表示对变量进行私有化
# 外部不能随便访问和更改
self.__name = name
self.__score = score
def get_grand(self):
print('my name is %s,my'
'grand is %d' % (self.__name, self.__score))
def __get_name(self):
return self.__name
def get_score(self):
return self.__score