1.面向对象(上)
1.1定义
- 面向对象编程:oop [object oriented programming] 是一种python的编程思路;
- 面向过程:就是我们一开始学习的,按照解决问题的步骤去写代码 【根据业务逻辑去写代码】,在思考问题的时候, 首先分析'怎么按照步骤去实现' 然后将问题解决拆解成若干个步骤,并将这些步骤对应成方法一步一步的 最终完成功能。
- 面向对象:关注的是设计思维【找洗车店 给钱洗车】
1.2类和对象
类和对象
类:类是具有一组 相同或者相似特征【属性】和行为【方法】的一系列[多个]对象组合
现实世界 计算机世界
行为---------> 方法
特征---------->属性
对象: 对象是实实在在的一个东西,类的实例化,具象化
类是对象的抽象化 而对象是类的一个实例
1.3定义类和创建对象、实例方法和属性、init方法
实例方法:在类的内部,使用def 关键字来定义 第一个参数默认是 self
【名字标识可以是其他的名字,但是这个位置必须被占用】
实例方法是归于 类的实例所有
属性:类属性 实例属性
在类的内部定义的变量【类属性】
在方法内部定义的【通过类似于self.变量名】 变量,是实例属性
# 定义类和对象
# 类结构 类名 属性 方法
# class 类名:
# 属性
# 方法
class Person:
'''
对应人的特征
'''
# name='小明' #类属性
age=20 #类属性
'''
对应人的行为 实例方法
'''
def __init__(self):
self.name='小明' #实例属性
pass
def eat(parms):
print("大口的吃饭")
pass
def run(self): #实例方法
print('飞快的跑')
pass
pass
def printInfo():
'''
普通方法
:return:
'''
pass
# 创建一个对象【类的实例化】
# 规则格式 对象名=类名()
xm=Person()
xm.eat() #调用函数
xm.run()
print("{}的年龄是:{}".format(xm.name,xm.age))
# 创建另外一个实例对象
xw=Person()
xw.eat() #实例方法
1.4 init方法
# init传递参数 改进
class Pepole:
def __init__(self,name,sex,age):
'''
实例属性的声明
'''
self.name=name
self.sex=sex
self.age=age
pass
def eat(self,food):
'''
吃的行为
:return:
'''
print(self.name+'喜欢吃'+food)
pass
zp=Pepole('张鹏','男生',18)
print(zp.name,zp.age)
zp.eat('香蕉')
lh=Pepole('李辉','男生',28)
lh.eat('苹果')
print(lh.name,lh.age)
xh=Pepole('小花','女生',20)
xh.eat('橘子')
print(xh.name,xh.age)
# 总结 __init__
# 1. python 自带的内置函数 具有特殊的函数 使用双下划线 包起来的【魔术方法】
# 2. 是一个初始化的方法 用来定义实例属性 和初始化数据的,在创建对象的时候自动调用 不用手动去调用
# 3. 利用传参的机制可以让我们定义功能更加强大并且方便的 类
1.5 self理解
小结 self特点
self只有在类中定义 实例方法的时候才有意义,在调用时候不必传入相应的参数 而是由解释器 自动去指向;![在这里插入图片描述](/i/ll/?i=6021b15274424412930d9e9cfee67965.png)
self的名字是可以更改的 可以定义成其他的名字,只是约定俗成的定义成了 self
self 指的是 类实例对象本身, 相当于java中 this
class Person:
def __init__(self,pro,name,food):
'''
:param pro: 专业
:param name: 姓名
:param food: 食物
'''
self.pro=pro #实例属性的定义
self.name=name
self.food=food
print('----init-----函数执行')
pass
'''
定义类
'''
def eat(self,name,food):
'''
实例方法
:return:
'''
# print('self=%s',id(self))
print('%s 喜欢吃 %s 修的专业是:%s'%(self.name,self.food,self.pro))
pass
pass
# xw是一个新的实例化对象
xw=Person('心理学','小王','榴莲')
# print('xw=%s',id(xw))
# xw.eat('小王','榴莲')
print(xw) #直接输出对象
1.6 魔术方法
- 定义:
class Person:
def __init__(self,pro,name,food):
'''
:param pro: 专业
:param name: 姓名
:param food: 食物
'''
self.pro=pro #实例属性的定义
self.name=name
self.food=food
print('----init-----函数执行')
pass
'''
定义类
'''
def eat(self,name,food):
'''
实例方法
:return:
'''
# print('self=%s',id(self))
print('%s 喜欢吃 %s 修的专业是:%s'%(self.name,self.food,self.pro))
pass
def __str__(self):
'''
打印对象 自定义对象 是内容格式的
:return:
'''
return '%s 喜欢吃 %s 修的专业是:%s'%(self.name,self.food,self.pro)
pass
def __new__(cls, *args, **kwargs):
'''
创建对象实例的方法 每调用一次 就会生成一个新的对象 cls 就是class的缩写
场景:可以控制创建对象的一些属性限定 经常用来做单例模式的时候来使用
:param args:
:param kwargs:
'''
print('----new-----函数的执行')
return object.__new__(cls) #在这里是真正创建对象实例的
pass
pass
# xw是一个新的实例化对象
xw=Person('心理学','小王','榴莲')
# print('xw=%s',id(xw))
# xw.eat('小王','榴莲')
print(xw) #直接输出对象
# 小结 self特点
# self只有在类中定义 实例方法的时候才有意义,在调用时候不必传入相应的参数 而是由解释器 自动去指向
# self的名字是可以更改的 可以定义成其他的名字,只是约定俗成的定义成了 self
# self 指的是 类实例对象本身, 相当于java中 this
# __new__和__init___函数的区别
# __new__ 类的实例化方法 必须要返回该实例 否则对象就创建不成功
# __init___ 用来做数据属性的初始化工作 也可以认为是实例的构造方法 接受类的实例 self 并对其进行构造
# __new__ 至少有一个参数是 cls 代表要实例化的类 ,此参数在实例化时由python解释器自动提供
# __new__ 函数 执行要早于 __init___ 函数
2.面向对象(中)
2.1析构方法
class Animal:
def __init__(self,name):
self.name=name
print('这是构造初始化方法')
pass
def __del__(self):
# 主要的应用就是来操作 对象的释放 一旦释放完毕 对象便不能在使用
print('当在某个作用域下面 没有被使用【引用】的情况下 解析器会自动的调用此函数 来释放内存空间')
print('这是析构方法')
print('%s 这个对象 被彻底清理了 内存空间也释放了'%self.name)
pass
cat=Animal('小花猫')
# del cat #手动的去清理删除对象 会指定__del__函数
print(cat.name)
input('程序等待中.....')
# print('*'*40)
# dog=Animal('柯基小狗')
2.2单继承
class Animal:
def eat(self):
'''
吃
:return:
'''
print('吃饭了')
pass
def drink(self):
'''
喝
:return:
'''
pass
class Dog(Animal): #继承了Animal 父类 此时dog就是子类
def wwj(self):
'''
子类独有的实现
:return:
'''
print('小狗汪汪叫')
pass
class Cat(Animal):
def mmj(self):
'''
子类独有的实现
:return:
'''
print('小猫喵喵叫')
pass
d1=Dog()
d1.eat() #具备了吃的行为 是继承了父类的行为
d1.wwj()
print('**************cat 的行为**********************')
c1=Cat()
c1.eat()
c1.mmj()
2.3多继承
注:# 问题是 当多个父类当中存在相同方法的时候 应该去调用哪一个呢? 答:广度优先/(print(A.mro) #可以显示类的依次继承关系)
class shenxian:
def fly(self):
print("神仙都会飞")
pass
class Monkey:
def chitao(self):
print('猴子喜欢吃桃')
pass
class Sunwukong(shenxian,Monkey): #即使神仙 同时也是猴子
pass
# swk=Sunwukong()
# swk.chitao()
# swk.fly()
####################################################
# 问题是 当多个父类当中存在相同方法的时候 应该去调用哪一个呢
class D(object):
def eat(self):
print('D.eat')
pass
pass
class C(D):
def eat(self):
print('C.eat')
pass
pass
class B(D):
pass
class A(B,C):
pass
a=A()
a.eat()
print(A.__mro__) #可以显示类的依次继承关系
#在执行eat的方法时 查找方法的顺序是
# 首先到A里面去查找 如果A中没有 则继续的去B类中去查找 如果B中没有
# 则去C中查找 如果C类中没有 则去D类中去查找,如果还是没有找到 就会报错
# A-B-C-D 也是继承的顺序
2.4间接继承
class GrandFather:
def eat(self):
print('吃的 方法')
pass
pass
class Father(GrandFather):
pass
class Son(Father):
pass
son=Son()
print(Son.__mro__)
son.eat() #此方法 是从GrandFather继承过来的
2.5重写和调用父类方法
- 所谓重写,就是子类中,有一个和父类相同名字的方法,在子类中的方法会覆盖掉父类中同名的方法
- 为什么要重写, 父类的方法已经不满足子类的需要,那么子类就可以重写父类或者完善父类的方法
class Dog:
def __init__(self,name,color):
self.name=name
self.color=color
def bark(self):
print('汪汪叫....')
pass
pass
class kejiquan(Dog):
def __init__(self,name,color):#属于重写父类的方法
# 针对这种需求 我们就需要去调用父类的函数了
# Dog.__init__(self,name,color) #手动调用 调用父类的方法了 执行完毕就可以具备name,color这两个实例属性了\
super().__init__(name,color) #super是自动找到父类 进而调用方法, 假设继承了多个父类,那么会按照顺序逐个去找 然后在调用
# 拓展其他的属性
self.height=90
self.weight=20
pass
def __str__(self):
return '{}的颜色会{} 它的身高是{}cm 体重是:{}'.format(self.name,self.color,self.height,self.weight
)
def bark(self): #属于重写类的方法
super().bark() #调用父类的方法
print('叫的跟神一样')
print(self.name)
pass
kj=kejiquan('柯基犬','红色')
kj.bark()
print(kj)
注: super是自动找到父类 进而调用方法
2.6 类属性和实例属性
注: 类属性 就是类对象所拥有的属性(类对象不同于实例对象,这里和java有点不同,这里所说的类对象应该就是java里面的元对象)
- 小结
- 类属性是可以 被类对象和实例对象共同访问使用的
- 实例属性只能由实例对象所访问
class Student:
name='李明' #属于类属性 就是student类对象所拥有的
def __init__(self,age):
self.age=age #实例属性
pass
@staticmethod
def aaa(x,y):
print(x+y)
pass
Student.name='李易峰' #通过类对象去修改数据 可以修改的 因为name的所拥有的权利属于类对象
lm=Student(18)
print(lm.name) #通过实例对象去访问类属性
# lm.name='刘德华' #通过实例对象 对类属性进行修改 可以吗? 不可以的
print(lm.name)
print(lm.age)
Student.aaa(4,6)
print('---------xh的数据---------------')
xh=Student(28)
print(xh.name)
print(xh.age)
print('---------通过类对象 student 去访问name---------------')
# print(Student.name) 如 类名.属性名 形式去访问
# print(Student.age)
# 小结
# 类属性是可以 被类对象和实例对象共同访问使用的
# 实例属性只能由实例对象所访问
分析:
2.7类方法和静态方法
- 类方法是类所拥有的,可以访问类变量,可以通过类对象和实例对象访问。必须传参数。
- 静态方法和类方法差不多,但是不必须传参数。
- 为什么要使用静态方法呢?1. 由于静态方法主要来存放逻辑性的代码,本身和类以及实例对象没有交互;2.也就是说,在静态方法中,不会涉及到类中方法和属性的操作;3.数据资源能够得到有效的充分利用。
class People:
country='china'
#类方法 用 classmethod 来进行修饰
@classmethod
def get_country(cls):
return cls.country #访问类属性
pass
@classmethod
def change_country(cls,data):
cls.country=data #修改类属性的值 在类方法中
pass
@staticmethod
def getData():
return People.country #通过类对象去引用
pass
@staticmethod
def add(x,y):
return x+y
pass
print(People.add(10,56)) #带有参数的静态方法
# print(People.getData())
# print(People.get_country()) #通过类对象去引用
p=People()
print(p.getData()) #注意 一般情况下 我们不会通过实例对象去访问静态方法
# print('实例对象访问 %s'%p.get_country())
# print('-----------------修改之后---------------------------')
# People.change_country('英国')
# print(People.get_country()) #通过类对象去引用
# 为什么要使用静态方法呢
# 由于静态方法主要来存放逻辑性的代码,本身和类以及实例对象没有交互,
# 也就是说,在静态方法中,不会涉及到类中方法和属性的操作
# 数据资源能够得到有效的充分利用
# demo 返回当前的系统时间
import time # 引入第三方的时间模块
class TimeTest:
def __init__(self,hour,min,second):
self.hour=hour
self.min = min
self.second = second
@staticmethod
def showTime():
return time.strftime("%H:%M:%S",time.localtime())
pass
pass
print(TimeTest.showTime())
t=TimeTest(2,10,15)
print(t.showTime()) #没有必要通过这种方式去访问 静态方法
2.8三种方法对比
- 从方法定义的形式可以看出来
- 1.类方法的第一个参数是类对象 cls 进而去引用类对象的属性和方法 必须用装饰器 @classmethod来修饰
- 2.实例方法的第一个参数必须是self,通过这个self 可以去引用类属性或者实例属性,若存在相同名称实例属性和类属性的话,实例属性的优先级最高
- 3.静态方法不需要定义额外的参数,若是要引用属性的话 则可以通过类对象或者是实例对象去引用即可 必须用装饰器 @staticmethod来修饰
2.9多态
- 多态:顾名思义就是多种状态、形态,就是同一种行为 对于不同的子类【对象】有不同的行为表现
- 要想实现多态 必须的有两个前提需要遵守:
- 1、继承:多态必须发生在父类和子类之间
- 2、重写: 子类重写父类的方法
- 多态有什么用: 增加程序的灵活性;增加程序的拓展性。
# 案例演示
class Animal:
'''
父类【基类】
'''
def say_who(self):
print('我是一个动物....')
pass
pass
class Duck(Animal):
'''
鸭子类 【子类】 派生类
'''
def say_who(self):
'''
在这里重写父类的方法
:return:
'''
print('我是一只漂亮的鸭子')
pass
pass
class Dog(Animal):
'''
小狗类 【子类】 派生类
'''
def say_who(self):
print('我是一只哈巴狗')
pass
pass
class Cat(Animal):
'''
小猫类 【子类】 派生类
'''
def say_who(self):
print('我是一只小花猫 喵喵喵喵')
pass
pass
class Bird(Animal):
'''
新增鸟类 无需修改原来的代码
'''
def say_who(self):
print('我是一只黄鹂鸟')
pass
class People:
def say_who(self):
print('我是人类')
pass
class student(People):
def say_who(self):
print('我是一年级的学习 张明')
pass
def commonInvoke(obj):
'''
统一调用的方法
:param obj: 对象的实例
:return:
'''
obj.say_who()
# duck1=Duck()
# duck1.say_who()
# dog1=Dog()
# dog1.say_who()
# cat1=Cat()
# cat1.say_who()
listObj=[Duck(), Dog(),Cat(),Bird(),student()]
for item in listObj:
'''
循环去调用函数
'''
commonInvoke(item)
2.10 三大特征(面向对象)
- 在python中展现面向对象的三大特征:
- 封装、继承、多态
- 封装:指的是把内容封装到某个地方,便于后面的使用 他需要: 把内容封装到某个地方 从另外一个地方去调用被封装的内容 对于封装来说 其实就是使用初始化构造方法将内容封装到对象中,然后通过对象直接或者self来获取被封装的内容
- 继承: 和现实生活当中的继承是一样的:也就是 子可以继承父的内容【属性和行为】(爸爸有的儿子都有,相反 儿子有的爸爸不一定有) 所以对于面向对象的继承来说 其实就是将多个类共有的方法提取到父类中 子类仅需继承父类而不必一一去实现 这样就可以极大的提高效率 减少代码的重复编写,精简代码的层级结构 便于拓展
class 类名(父类):
'''
子类就可以继承父类中公共的属性和方法
'''
pass
- 多态:顾名思义就是多种状态、形态,就是同一种行为 对于不同的子类【对象】有不同的行为表现 要想实现多态 必须的有两个前提需要遵守: 1、继承:多态必须发生在父类和子类之间 2、重写: 子类重写父类的方法
3.面向对象(下)
3.1私有化属性
- 使用私有属性的场景
- 1.把特定的一个属性隐藏起来 不想让类的外部进行直接调用
- 2.我想保护这个属性 不想让属性的值随意的改变
- 3.保护这个属性 不想让派生类【子类】去继承
class Person:
__hobby='跳舞' #私有的类属性
def __init__(self):
self.__name='李四' #加两个下划线 将此属性私有化之后 就不能再外部直接访问了,当然在类的内部是可以防蚊贴
self.age=30
pass
def __str__(self):
'''
私有化的属性在内部可以使用 self.__name
:return:
'''
return '{}的年龄是{} 爱好是{}'.format(self.__name,self.age,Person.__hobby)
def changeValue(self):
Person.__hobby='唱歌'
class Student(Person):
def printInfo(self):
# print(self.__name) #在此访问父类中的私有属性 可以吗? 不可以
print(self.age)
pass
stu=Student()
# print(stu.__name)
stu.printInfo()
stu.changeValue() #修改私有属性的值
print(stu)
# print(stu.__hobby) #实例对象访问类属性
# print(Person.__hobby) #实例对象访问类属性
# xl=Person()
# # print(xl.__name) #是通过类对象 在外部访问的 不能访问私有属性
# print(xl)
# 小结:
# 1 私有化的【实例】属性 不能再外部直接的访问 可以在类的内部随意的使用
# 2.子类不能继承父类的私有化属性【只能继承父类公共的属性和行为】
# 3. 在属性名的前面直接加‘ __’ 就可以变为私有化了
3.2私有化方法
class Animal:
def __eat(self):
print('吃东西')
pass
def run(self):
self.__eat() #在此调用私有化的方法
print('飞快的跑')
pass
class Bird(Animal):
pass
b1=Bird()
# print(b1.eat())
# b1.eat()
b1.run()
3.3Property属性函数(意义不大)
- 目的:不需要通过函数的形式,来访问私有属性
class Person(object):
def __init__(self):
self.__age = 18 # 定义一个私有化属性,属性名字前加连个 __ 下滑线
# def get_age(self): # 访问私有实例属性
# return self.__age
# def set_age(self,age): # 修改私有实例属性
# if age < 0:
# print('年龄不能小于0')
# else:
# self.__age=age
# pass
# pass
# 定义一个类属性 实现通过直接访问属性的形式去访问私有的属性
# age=property(get_age,set_age)
# 实现方式2 通过装饰器的方式去声明
@property #用装饰器修饰 添加属性标志 提供一个getter方法
def age(self):
return self.__age
@age.setter #提供一个setter方法
def age(self,parms):
if parms < 0:
print('年龄不能小于0')
else:
self.__age=parms
pass
pass
pass
p1=Person()
print(p1.age)
p1.age=30
print(p1.age)
# p1.get_age()
# p1.set_age()
3.4__new__方法
class Animal:
def __init__(self):
self.color='红色'
pass
#在python当中, 如果不重写 __new__ 默认结构如下
def __new__(cls, *args, **kwargs):
return super().__new__(cls,*args, **kwargs)
# return object.__new__(cls, *args, **kwargs)
pass
tigger=Animal() #实例化的过程会自动调用__new__去创建实例
# 在新式类中 __new__ 才是真正的实例化的方法,为类提供外壳制造出实例框架,然后调用该框架内的构造方法__init__ 进行丰满操作
# 比喻建房子 __new__ 方法负责开发地皮 打地基 并将原料存放在工地,而__init__ 负责从工地取材料建造出地皮开发图纸规定的大楼,
# 负责细节设计、建造 最终完成
3.5单例模式
- 单例模式 是一种常用的软件设计模式 目的:确保某一个类只有一个实例存在
- 如果希望在真个系统中 某个类只能出现一个实例的时候,那么这个单例对象就满足要求
- 创建一个单例对象 基于__new__去实现的【推荐的一种】
class DataBaseClass(object):
def __new__(cls, *args, **kwargs):
# cls._instance=cls.__new__(cls) 不能使用自身的new方法
# 容易造成一个深度递归,应该调用父类的new方法
if not hasattr(cls,'_instance'): #如果不存在就开始创建
cls._instance=super().__new__(cls,*args, **kwargs)
return cls._instance
pass
class DBoptSingle(DataBaseClass):
pass
db1=DBoptSingle()
print(id(db1))
db2=DBoptSingle()
print(id(db2))
db3=DBoptSingle()
print(id(db3))
标签:__,name,面向对象,python,self,--,pass,print,def
From: https://blog.51cto.com/u_12518291/11880722