创作不易,来了的客官点点关注,收藏,订阅一键三连❤😜
往期系列
Python——函数大全及使用方法! lambda?global?
Python——流程控制,pass?break?continue?这些你弄清楚了吗?
目录
面向对象编程 (OOP-Object Oriented Programming)
类:用来描述具有相同属性和方法的对象的集合,分为基类、子类。
常见的三种编程范式
函数式编程
• 函数可以作为参数传递、修改,或作为返回值
• 函数内不修改外部变量的状态
面向过程编程
• 根据操作数据的语句块来实现功能。
def login(username,passwd):
if username == "root" and passwd == "123456":
return True
else:
return False
面向对象编程 (OOP-Object Oriented Programming)
• 把数据和功能结合起来,用称为对象的东西包裹起来组织程序的方法。
class LoginCheck():
# 登陆数据
username = "root"
passwd = "123456"
# 登录功能
def login(self,username,passwd):
if username == "root" and passwd == "123456":
return True
else:
return False
面向过程VS面向对象
• 面向过程是一件事"该怎么做", 着重于做什么。
面向过程 = 分析问题 + 逻辑
优点:性能比面向对象高,因为类调用时需要实例化,开销比较大,比较消耗资源;比如单片机、嵌入式开发、 Linux/Unix等一般采用面向过程开发,性能是最重要的因素。
缺点:没有面向对象易维护、易复用、易扩展
• 面向对象是一件事"该让谁来做",着重于谁去做
优点:易维护、易复用、易扩展,由于面向对象有封装、继承、多态性的特性,可以设计出低耦合的系统,使系统 更加灵活、更加易于维护
缺点:性能比面向过程低
面向对象的基本概念
• 对象:通过类定义的数据结构实例。
• 对象包括两个数据成员(类变量和实例变量)和方法。
• python一切皆对象,类是对象,实例也是对象
示例代码:
class Bus317(object):
# 类属性
line = "317"
# 方法-->行为
def run(self,flag):
print("bus317 is run")
if flag == 0:
print("从农大到长华小区")
else:
print("从长华小区到农大")
实例化:创建了一个对象
bus01 = Bus317()
bus02 = Bus317()
类(class申明)
类:用来描述具有相同属性和方法的对象的集合,分为基类、子类。
什么是类?
生活例子:车可以理解为一个类,特征:有车轮、车牌,方法:会跑
基类/子类
车-->基类;摩托车,大卡车-->子类
对象
实例:具体的某一个事务,某个类型实实在在的一个例子
类的实例化
通过类创建的一个具体的实例,类的具体对象;
类就是一个生产实例的工厂,类就是一个模型图
实例化
lg1 = LoginCheck()
lg1就是一个对象,实例去干活
print(lg1.login("root1","21323"))
类的定义与使用
类空间和实例空间
创建类的时候就会创建类空间
实例化对象时就会生成实例空间,不同的实例有单独的空间
实例查找属性方法时,会现在实例空间查找,找不到就去类空间查找,类空间找不到就去父空间查找
eg:bus01.xx --> 查找xx属性
先在他自己的实例空间查找--找不到就去Bus317里找--再找不到再去object找--最后找不到就报错
类的基本特点
• 封装(Encapsulation)
在类中对数据的赋值、内部调用对外部用户是透明的
把一些功能的实现细节不对外暴露
将数据和函数做了一层封装,封装成类,使用者不需要管具体实现的代码
• 继承(Inheritance)
继承:即一个派生类(derived class)继承基类(base class)的字段和方法。
目的:为实现代码的重用, 一个类可以派生出子类
继承也允许把一个派生类的对象作为一个基类对象对待。
• 多态(Polymorphism)
接口重用, 一个接口,多种实现(重写)
类的定义与使用
• 类名的规范
一般首字母大写(大驼峰)
Person, GoodsInfo
• 函数的命名
由小写字母和下划线组成
scan_book, drink
• 类的定义方式(关键字:class)
python2 => 经典类和新式类
python3 => 新式类
继承了object类的类都属于新式类,没有继承的属于经典类
class A():
pass
class B:
pass
class C(object):
pass
python3中以上三种定义没有区别,默认会继承object类
class Bus317(object):
# 类属性
line = "317"
# 方法-->行为
def run(self,flag):
print("bus317 is run")
if flag == 0:
print("从农大到长华小区")
else:
print("从长华小区到农大")
#实例化:创建了一个对象
bus01 = Bus317()
bus02 = Bus317()
#打印类和实例的内存:类和实例化都有单独的命名空间
print(id(Bus317),id(bus01),id(bus02))
#查看对象的属性或方法
print(dir(bus01))
print(bus01.line)
bus01.run(0)
bus02.run(1)
#直接用类访问属性
print(Bus317.line)
__init__方法
实例化对象的构造方法,实例化对象的时候会自动调用__init__方法
用来初始化属性
__new__方法
创建实例化,一般情况下不需要重写,静态方法
class Bus317(object):
# 类属性
# line-->公共属性
line = "317"
def __init__(self,pro):
print("this is __init__")
self.pro1 = pro
# cls接收到的参数就是当前类(Bus317)
def __new__(cls, *args, **kwargs):
print("this is new method")
return "new"
# return object.__new__(cls)
# 返回父类object.__new__方法通过当前类创建的对象
# *args和 ** kwargs主要用于函数定义。你可以将不定数量的参数传递给一个函数。
# 这里的不定的意思是: 预先并不知道, 函数使用者会传递多少个参数给你, 所以在这个场景下使用这两个关键字。
def run(self,flag):
print("bus317 is run")
if flag == 0:
print("从农大到长华小区")
else:
print("从长华小区到农大")
# 创建实例
bus01 = Bus317("benci","chao")
bus02 = Bus317("futian")
print(bus01)
# print(dir(bus01))
# print(bus01.pro1,bus02.pro1)
# 查看类空间有什么东西
# print(Bus317.__dict__)
# 查看实例空间有什么内容
# print(bus01.__dict__)
__init__与__new__总结
__init__是对创建好的实例,进行初始化工作的方法
__new__是创建实例的方法
1.__new__方法必须传入一个参数(cls),代表当前类
2.__new__必须返回一个实例化的对象
3、__init__的self就表示__new__返回的实例,__init__对这个实例进行初始化工作
4、子类没有__new__,会去找父类的__new__
5、新式类才有__new__
6、如果实例化对象和本身class不一致,__init__不会执行
小练习:创建类,实现计算学生的总成绩与平均分
创建一个学生类
• 类名:Student
• 属性:姓名,年龄,学校,成绩(字典)
{'yuwen':100, 'suxue':100, 'yinyu':100}
• 方法:求总分、求平均值
class Student(object):
school = "hunau"
def __init__(self,name,age,scores):
# 初始化函数,self-->实例本身
self.name = name
self.age = age
self.school = Student.school # 使用类属性
self.scores = scores
def sum(self):
# sum1 = 0
# for i in self.scores.values():
# sum1 += i
# return sum1
# 方法二
return sum(self.scores.values())
def avg(self):
# avg1 = self.sum()/len(self.scores)
# return avg1
# 方法二
return self.sum()/len(self.scores)
lzc = Student("lzc", 20,{"math":100,"Chinese":90})
lzw = Student("lzw", 20,{"math":98,"Chinese":92})
llf = Student("llf", 20,{"math":97,"Chinese":91})
print(lzc.sum())
print(lzc.avg())
类的self方法
类-self
类的实例方法与普通的函数只有一个特别的区别——它们必须有一个额外的第一个参数名称
在调用这个方法的时候你不为这个参数赋值,Python会提供这个值
这个特别的变量指对象本身,按照惯例它的名称是self
class A:
name = "sc"
age = 4
def info(self,sex):
print(f"我是:{self.name},今年{self.age}岁,性别{sex}")
print(self)
print(id(self))
def info2(chao):
print(f"this is {chao}")
#self 表示实例本身
a = A()
print(id(a))
a.info("man")
print("***")
A.info(a,"man") # 实际上运行
#输出结果:
1889166028752
我是:sc,今年4岁,性别man
<__main__.A object at 0x000001B7DB11EFD0>
1889166028752
self 不必非写成self,self的名字不是强制规定的(可以理解为不一定要命名为self)
最好还是尊重约定俗成的习惯,使用self
b = A()
b.info2()
#输出结果:
this is <__main__.A object at 0x00000278DEEEEFD0>
方法中可以不传入self,如果不写的话就不能使用对象调用
实例调用方法的时候,默认就会把当前的实例传给self,不需要手动传入
示例:
class Parent:
def pprt(self):
print(self)
class Child(Parent):
def cprt(self):
print(self)
c = Child()
c.cprt()
c.pprt()
#输出结果:
<__main__.Child object at 0x00000278DEEEEFA0>
<__main__.Child object at 0x00000278DEEEEFA0>
练习:用面向对象实现斐波那契数列
用类实现斐波那契数列的运算(编写自定义迭代器)
斐波那契数列: 0 1 1 2 3 5
代码如下
class Fib_list:
def __init__(self):
self.before = 0
self.now = 1
def __iter__(self):
return self
def __next__(self):
result = self.now
self.before,self.now=self.now,self.before+self.now
return result
a = Fib_list()
print([next(a) for i in range(11)])
类的继承
面向对象的好处
面向对象的编程带来的主要好处之一是代码的重用,实现这种重用的方法之一是通过继承机制。
继承完全可以理解成类之间的类型和子类型关系。
• 可以节省很多的代码,不需要写,直接使用
• 衍生出不同的子类,大部分代码一样,部分代码不一样
继承
• 继承父类的属性和方法
• 对象属性查找
先在实例空间查找,没有就去类空间
再没有就去父类空间找,层层往上递归查找
class Animal():
species = "Animal"
count = 0
def __init__(self):
self.name = "animal"
Animal.count += 1
print("初始化animal......")
def breath(self):
print("i can breath")
def eat(self):
print("i can eat")
# 继承Animal类
class Person(Animal):
species = "Person" #重写父类属性
class Dog(Animal):
species = "Dog"
def __init__(self): #重写父类的__init__
print("i am dog")
def eat(self): #重写父类的eat()
print("dog is eatting......")
class Pig(Animal):
count = 0 #重写父类属性
def __init__(self): #重写父类__init__
self.name = "pig"
Pig.count += 1
print("初始化Pig......")
super().__init__() #去执行父类的__init__,子类访问父类属性的方法属性
print(Animal.count)
# 输出结果
0
# 实例化Animal
animal = Animal()
print(Animal.count,animal.count)
# 输出结果
初始化animal......
1 1
# 实例化Person
person = Person()
print(person.species,person.count,Person.count)
#输出结果
初始化animal......
Person 2 2
# 实例化Dog
dog = Dog()
print(dog.count)
print("*"*5)
# 输出结果
i am dog
2
# 实例化Pig
pig = Pig()
print(pig.count,pig.name)
# 输出结果
初始化Pig......
初始化animal......
1 animal
# 类与实例的关系
print("类与实例的关系".center(30,"*"))
print(type(dog))
print(isinstance(dog,Dog), isinstance(dog, Animal))
# 输出结果
***********类与实例的关系************
<class '__main__.Dog'>
True True
使用继承的好处
• 增加了代码的利用率,如果需要给Pig/Person同时增加新的功能时,只需要在Animal中添加即可
• 便于更新迭代,如果你的父类方法的功能不能满足你的需求,你可以在子类重写你父类的方法父类里的方法
python的多态
python不支持多态,语法上的多态,不需要额外实现多态代码
python里处处都是多态,python是一个多态类型语言,本身就实现了多态,崇尚鸭子类型
在鸭子类型中,关注的不是对象的类型本身,而是它是如何使用的。
多态的好处
• 增加了程序的灵活性
• 以不变应万变,不论对象千变万化,使用者都是同一种形式去调用,如func(animal)
• 增加了程序额可扩展性
• 通过继承animal类创建了一个新的类,使用者无需更改自己的代码,还是用func(animal)去调用
• 多态:同一种事物的多种形态,动物分为人类,猪类(在定义角度)
• 多态性:一种调用方式,不同的执行效果(多态性)
• 实现接口重用
练习:利用类自定义异常类
自定义异常类
• 自定义异常能让异常更精准
• 自定义异常类:当list内元素长度超过10的时候抛出异常
• 自定义异常类:消息小于8时抛出异常
方法一
class List_Error(Exception):
pass
lst1 = [1,2,3]
if not 8<len(lst1)<10:
raise List_Error("列表长度小于8或超出10")
else:
print("No Problem")
方法二:
class List_Error(Exception):# 注:继承Exception的基类
def __init__(self,lst,message):
self.lst = lst
self.message = message
def __str__(self):
str1 = "list is " + str(self.lst)
str1 = str1 +"\n" + self.message
return str1
try:
lst = [1,2,3,4,5,6]
if not 8 < len(lst) < 10:
raise List_Error(lst,"列表长度小于8或超出10!")
except List_Error as e:
print("listError error:",e)
创作不易,客官点个赞吧!评论一下!一起加油❤😜