引言
hello啊,兄弟们,这几天更新的都没怎么好好唠嗑,今天我学习的是面向对象的内容,学过java和c嘎嘎的同学应该都不陌生吧,当初在学习这一章节的时候简直是生不如死啊。好在那段时间都挺过来了,现在看这东西,比之前那几章节都快,昨天摸了一天🐟,今天本来说8点开始的,结果听说农药上了一个10v10的模式,我也是赶紧上号体验了一番。不打不知道啊,一打就在对面两条中路防御塔空隙里面来回蹦迪,第一次玩这样的地图实在是不适应。哎,等我打完游戏,时间就已经来到了10点,我就紧赶慢赶看完了今天的所有知识点,开始了今天笔记总结,计划明天,后天写两个小项目,就写学生管理系统和银行管理系统吧,毕竟是java开发出生,对后台系统有种莫名的亲切,计划是一个用字典和列表写,另一个用面向对象写,顺便到最后吧存储的最终数据做一个导入导出操作,这涉及到之前学IO的操作,当然我会建立一个git仓库,存放我的代码,供大家参考。话不多说,开始今天的博客之旅,现在是北京时间22:27.
一.什么是面向对象
面向对象编程(Object-Oriented Programming,OOP)是一种常用的编程思想,它强调万物皆对象,因此在编程时我们可以将现实世界中的事物抽象成程序中的对象,从而更好实现软件的设计与开发。与传统的基于函数的编程不同,面向对象编程注重于将数据与行为封装在一起,即对象既包含数据状态,还包含可调用的行为方法。具有三大特性,封装,继承以及多态。
二.类和对象的概念定义
类:类是一个抽象的概念,是模板,是一个参考物。用来描述具有相同属性和方法的集合。
比如:人类,动物类。
对象:具体存在的事物。精准存在,可以看得见摸得着的东西
类和对象的关系:从实际来看,可以表示为,对象归为类。类是最大的,对象把类给精确化了。
类的构成:
1、类的名称:类名
2、类的属性:一组数据
3、类的方法:允许对类操作的方法 类里面的函数,称之为方法
类的定义:
1、class 类名:
2、class 类名():括号里面可以什么都不写的时候。继承obj
3、class 类名(object):
三.对象的创建
对象的创建也叫做类的调用,默认是调用类中的构造方法。每个类中都用构造方法,如果没有重写或者重载,那就是调用系统默认的无参构造方法。
class Student2():
def __init__(self):
self.name = "张三"
self.age = "20"
self.id = "123456"
def __str__(self):
return f"{self.name},{self.age},{self.id}"
#创建对象
stu2 = Student2()
四.私有属性
学过java的都知道,私有属性使用prative修饰的字段,在python里面,私有属性或者私有方法都是用1(2)个下划线+字段名表示的,当然读取和修改私有属性也用get()和set()
class Book:
def __init__(self): # 不需要调用,在特定时间、特定地点。自动触发的函数
self.name = "西游记"
self.id = "1001"
self._author = "吴承恩"
self.classify = "神话"
def __read(self):
print("小明爱读书")
def info(self):
Book.__read(self)
print(f"名字为{self.name}")
print(f"id为{self.id}")
print(f"作者是{self._author}")
print(f"属于{self.classify}的故事")
print(f"图书名称{self.name},id号{self.id},作者{self._author},属于{self.classify}类的故事") # 属于class内部,在内部运行,私有属性可以全部打印出来,
b = Book()
#读取不到私有属性,会报错
# print(b._author)
#读取不到私有方法,会报错
# b.read()
#私有属性和私有方法被封装在类中的方法时候,类中的方法可以访问,不报错
b.info()
# 小明爱读书
# 名字为西游记
# id为1001
# 作者是吴承恩
# 属于神话的故事
# 图书名称西游记,id号1001,作者吴承恩,属于神话类的故事
五.魔法函数
所谓魔法函数是系统内部自己嵌套的函数,比方说构造函数如果不重新写,在创建对象的时候会使用系统默认的无参构造函数,目前常用的三个魔法函数,如下:
# __init__ 触发条件,对象一旦创建,则自动执行
# __str__ 触发条件,对象打印的时候,可以将对象的地址转化为自定义的输出内容
# __lt__ 触发条件:两个对象参与比较,自动触发该魔法方法
class Number:
def __init__(self,value):
self.value = value
def __lt__(self,other):
return self.value < other.value
n1 = Number(3)
n2 = Number(4)
# print(n1 < n2) #True
print(n1.__lt__(n2))
六.类的成员
类的成员:区分为两大类:属性和方法
属性:1、实例属性[普通字段] 2、类属性[静态字段]
方法:1、实例方法[普通方法] 2、类方法[类方法]
类属性
1、字段是固定的:不会随着对象的改变而改变。
2、使用静态字段(类属性)减少内存消耗。
3、如果传递的参数要随着对象的变化而变化,那么要用实例属性。
class A:
name = "狗岁" #name就是静态字段,即类属性
pass
静态方法
方法被@staticmethod 修饰
self 不再呆滞对象本身,只是一个简单的参数
可以不实例化对象,直接进行调用。通过类名.方法名()、
Class A:
@staticmethod
def run():
print("A在奔跑")
#直接用A类去调用方法
A.run() #A在奔跑
类方法
方法被@classmethod修饰
也不需要传递self,系统自带的关键字(cls)指代类本身。
使用和静态方法一样,直接用类名.方法名
Class A:
@classmethod
def run():
print("A在奔跑")
#直接用A类去调用方法
A.run() #A在奔跑
修饰器
这个是我刚学的东西,我在写这篇帖子之前还不知道这是啥玩意,看完以后才懂,有点类似代理的意思。这个是老师给我的文档介绍,待会我用代码给你们解释一下。
装饰器:(函数)
1、装饰器函数,必须接收一个函数来作为参数。并且返回一个新的函数。
2、装饰器函数,一般都是在函数内部定义一个新的函数,用来包裹旧的函数。在原始的函数之前来调用增加或者删除其他功能。
3、装饰器函数,@ 将其作用到其他函数
@: 称之为语法糖。
装饰器遵循的原则封闭开放原则。
首先,如果我写一个函数
class f():
time.sleep(1000)
print("我想月入过万")
我想测试这个函数的编译时间
def F():
start = time.time()
time.sleep()
end = time.time()
print(end - start)
一个这样的函数还好,但是有很多这样对f()呢,这时候就需要修饰器出场
def F(fun())
start = time.time()
f()
end = time.time()
print(end - start)
def f1():
time.sleep()
print("我想月入过万")
def f2():
time.sleep()
print("我也想")
F(f1())
F(f2())
当然也可以使用@语法糖
def F(fun())
start = time.time()
f()
end = time.time()
print(end - start)
@F #默认调用F(fun())函数
def f1():
time.sleep()
print("我想月入过万")
@F
def f2():
time.sleep()
print("我也想")
受保护的方法
类似静态方法和类方法,在方法头上加@property注解的方法,其他类不读取修改,只能通过get()方法进行读取,只读不能通过其他方法修改。
class Demo:
def __init__(self):
self.name = "rose"
@property
def get_name(self):
print(self.name)
d = Demo()
d.get_name
七.封装,继承,多态
终于来到面向对象最重要的部分了,因为之前学过,感觉理解起来不麻烦,所以直接就一块写了。
封装
面向对象的基本特征之一,[封装对象内部的细节,只保留对外的接口]
要调用你封装的细节,符合你对象内部的特征
以下是一个梨子,应为id是私有属性,外部类无法访问,所有封装了get_id()和set_id()来对私有变量进行读取和修改,私有方法外部类无法访问,也是同理。
class Student():
def __init__(self, name):
self.__id = ""
self.name = name
def set_id(self, id):
if id >= 0:
self.__id = id
else:
self.__id = 0
def get_id(self):
return self.__id
stu1 = Student("小张")
stu1.set_id(-10)
print(stu1.get_id())
继承
继承:
面向对象的特征之一: 子类继承父类(亲爹)
重写: 当子类的方法和父类一样的时候。优先执行子类。
单继承
# 单继承
class Animal(ABC):
def __init__(self,name,age):
self.name = name
self.age = age
def drink(self):
print(f"{self.name}:在喝水")
class Dog(Animal):
# 没有构造方法
def eat(self):
print(f"{self.name}在吃东西")
def play(self):
print("在玩骨头")
d = Dog("旺财","12")
d.drink()
d.play()
多继承
深度优先,从左到右
class Horse():
def __str__(self, name):
self.name = name
def show_info(self):
print(f"马叫{self.name}")
def run(self):
print("马在跑")
class Donkey():
def __str__(self, name):
self.name = name
def show_info(self):
print(f"驴叫{self.name}")
def run(self):
print("驴跑的慢")
def roll(self):
print("驴打滚")
class MM(Horse, Donkey):
def __init__(self, name, age):
self.name = name
self.age = age
m1 = MM("小罗", 2)
m1.roll()
m1.run() #因为先继承的Horse,所以输出结果为 马在跑
抽象基类继承
子类继承抽象基类,必须实现抽象基类中抽象方法,并且抽象基类无法实现自己实现实力,只能通过多条来实现实例化。抽象方法头上有个注解是@abstractmethod
class Animal(ABC):
def __init__(self,name,age):
self.name = name
self.age = age
@abstractmethod
def drink(self):
print(f"{self.name}:在喝水")
class Dog(Animal):
def drink(self,name):
print(f"{name}不爱喝水")
# 没有构造方法
def eat(self):
print(f"{self.name}在吃东西")
def play(self):
print("在玩骨头")
d = Dog("旺财","12")
d.drink("wo")
子类使用父类方法时可以使用super()函数
Class A:
@abstractmethod
def drink(self):
print("我要喝水")
Class B(A):
def drink(self):
super.drink(self)
print("我不喝水")
多态
必须要有继承才会有多态
继承又重写父类
class Student():
def speak(self):
print("同学们,大家喊123")
class Stu1(Student):
def speak(self):
print("小张会讲话,会说ABC")
class Stu2(Student):
def speak(self):
print("小李会说话,会说欧耶")
class Stu3(Student):
pass
s1 = Stu1()
s2 = Stu2()
s3 = Stu3()
s1.speak()
s2.speak()
s3.speak()
在这里我就在考虑,java中有向上转型和向下转型,向上转型无所谓,但是向下转型会先判断类型是否相同,比方说,猫向上转型成动物,这个动物能向下转型成狗吗?显然是不可能的,所以在python里有没有相同的定义呢,我找了一下,显然是没有的,python的多态主要还是显示在,同一类的对象调用共同的行为或者说是方法,这里叫做鸭子模型。 Python解释其中,不坚持发生多态的对象是否继承一个父类,但是,只有有相同的行为。
class Animal():
def speak(self):
print("动物在叫,不知道怎么教的")
class Dog:
def speak(self):
print("狗在叫")
class Cat:
def speak(self):
print("猫在叫")
class Car:
def speak(self):
print("汽车在叫")
def start(obj):
obj.speak()
d = Dog()
start(Dog())
start(Cat())
start(Car())
结语
OK了,面向对象,到这里就结束了,注意核心,封装继承多态。现在是北京时间23:42,明天工作的地方要开始直播了,我得早点睡了,今天任然是python小白,梦想是月入过万,mai起!