python之面向对象详解(一)
一.类与对象
1.1类和对象的创建
- 类提供了创建对象的蓝图。
- 对象是类的实例,拥有类中定义的属性和方法。
- self 参数是对类实例自身的引用,用于访问类的属性和方法。
案例:
下面举一个“长方形”类的例子,包含长,宽属性
#面向对象基础
class Changfangxing: #类的首字母大写,这是规范
def __init__(self,chang,kuan): #类的初始化方法,self是实例本身,chang和kuan是变量名称(根据自己的需要定义,可要可不要).注意:在类中的函数叫做方法
print('两边长相等')
self.chang=chang
self.kuan=kuan
#若后面的方法中有self,就可以用self.chang和self.kuan
# (自身的长和宽可以被类中所有方法使用)
# (self用来串联类方法的一个桥梁)
def zhouchang(self):
return (self.chang+self.kuan)*2
def mianji(self):
return self.chang*self.kuan
cfx=Changfangxing(5,3) #实例化一个长方形
print(cfx.zhouchang())
print(cfx.mianji())
print(cfx.__dict__) #实例的属性
练习:写一个三角形的类,有初始化方法,周长方法,面积方法
练习的答案,可在资源绑定中下载
1.2类方法和静态方法
类方法
- 类方法是用 @classmethod 装饰器定义的。
- 类方法的第一个参数是类本身,通常命名为 cls,通过它可以访问类的属性和其他类方法。
- 类方法可以访问和修改类状态,通常用于定义那些不依赖于具体实例的方法。
案例:
class Rectangle: #新建一个长方形的类
def __init__(self,length,width): # self是实例本身,而cls是类本身
self.length=length
self.width=width
def permeter(self): #定义周长的方法
return (self.length+self.width)*2
def area(self): #定义面积的方法
return self.length*self.width
@classmethod #装饰器,表示下面的方法是类方法
def features(cls): # self是实例本身,而cls是类本身
print('两边长相等,两边的宽也相等,长和宽的角度为90度')
# Rectangle.permeter(2,4) #这样写会报错的。类不能直接调用实例方法,类必须要实例化才能调用方法(实例方法只能用实例调用)
rec=Rectangle(3,4) #创建一个实例对象
print(rec.permeter()) #实例方法只能用实例调用
print(rec.area())
Rectangle.features() #类方法可以用类调用,也可以用实例调用
静态方法
- 静态方法是用 @staticmethod 装饰器定义的。
- 静态方法不接受类 (cls) 或实例 (self) 的隐式第一个参数,它就像是一个普通的函数,只是碰巧在类的定义中。
- 静态方法不能访问类或实例的属性和其他方法,它主要用于放置在逻辑上属于类的功能,但不需要访问类或实例的任何数据。
案例:
class Rectangle: #新建一个长方形的类
def __init__(self,length,width): # self是实例本身,而cls是类本身
self.length=length
self.width=width
def permeter(self): #定义周长的方法
return (self.length+self.width)*2
def area(self): #定义面积的方法
return self.length*self.width
# 类方法和静态方法的区别:
# 类方法有一个类本身,但是静态方法没有
@classmethod #装饰器,表示下面的方法是类方法
def features(cls): # self是实例本身,而cls是类本身
print('两边长相等,两边的宽也相等,长和宽的角度为90度')
@staticmethod # 静态方法,本质上是函数
def sumdata(a,b):
return a+b
# Rectangle.permeter(2,4) #这样写会报错的。类不能直接调用实例方法,类必须要实例化才能调用方法(实例方法只能用实例调用)
rec=Rectangle(3,4) #创建一个实例对象
print(rec.permeter()) #实例方法只能用实例调用
print(rec.area())
Rectangle.features() #类方法可以用类调用,也可以用实例调用
rec.features()
print(rec.__dict__) #查看实例属性
print(rec.sumdata(23,43))
print(Rectangle.sumdata(23,33)) #类和实例都可以调用静态方法
类和实例都可以调用静态方法
# 类方法和静态方法的区别:
# 类方法有一个类本身,但是静态方法没有
验证静态方法其实是一个函数,可以type
#type的方式验证静态方法是否是函数
print(type(rec.sumdata)) #运行结果:。注意sumdata后不能跟小括号,因为这样判断的类型就是sumdata函数返回值的类型了,而不是sumdata本身
print(type(rec.permeter)) #运行结果:method为方法,function为函数
二.继承
在 Python 中,继承允许我们定义一个类(子类)继承另一个类(父类)的属性和方法。子类会继承父类的所有公有属性和方法,并可以添加自己的属性和方法,或者重写继承的方法。
2.1完全继承
案例(继承上面例子中长方形的类) :
class Rectangle: #新建一个长方形的类
def __init__(self,length,width): # self是实例本身,而cls是类本身
self.length=length
self.width=width
def permeter(self): #定义周长的方法
return (self.length+self.width)*2
def area(self): #定义面积的方法
return self.length*self.width
# 类方法和静态方法的区别:
# 类方法有一个类本身,但是静态方法没有
@classmethod #装饰器,表示下面的方法是类方法
def features(cls): # self是实例本身,而cls是类本身
print('两边长相等,两边的宽也相等,长和宽的角度为90度')
@staticmethod # 静态方法,本质上是函数
def sumdata(a,b):
return a+b
# Rectangle.permeter(2,4) #这样写会报错的。类不能直接调用实例方法,类必须要实例化才能调用方法(实例方法只能用实例调用)
rec=Rectangle(3,4) #创建一个实例对象
print(rec.permeter()) #实例方法只能用实例调用
print(rec.area())
Rectangle.features() #类方法可以用类调用,也可以用实例调用
rec.features()
print(rec.__dict__) #查看实例属性
print(rec.sumdata(23,43))
print(Rectangle.sumdata(23,33)) #类和实例都可以调用静态方法
#type的方式验证静态方法是否是函数
print(type(rec.sumdata)) #运行结果:。注意sumdata后不能跟小括号,因为这样判断的类型就是sumdata函数返回值的类型了,而不是sumdata本身
print(type(rec.permeter)) #运行结果:method为方法,function为函数
#inspect模块
import inspect #python的自检模块,可以判断一个对象是否是某种类型
print(inspect.ismethod(rec.area)) #说明实例方法是方法,返回值是布尔类型
print(inspect.ismethod(rec.features)) #说明类方法是方法
print(inspect.isfunction(rec.sumdata)) #说明静态方法是函数
#继承
#完全继承
class Square(Rectangle):
pass
squ=Square(6,6)
print(squ.permeter())
print(squ.area())
2.2部分继承
重写了某方法
class Rectangle: #新建一个长方形的类
def __init__(self,length,width): # self是实例本身,而cls是类本身
self.length=length
self.width=width
def permeter(self): #定义周长的方法
return (self.length+self.width)*2
def area(self): #定义面积的方法
return self.length*self.width
# 类方法和静态方法的区别:
# 类方法有一个类本身,但是静态方法没有
@classmethod #装饰器,表示下面的方法是类方法
def features(cls): # self是实例本身,而cls是类本身
print('两边长相等,两边的宽也相等,长和宽的角度为90度')
@staticmethod # 静态方法,本质上是函数
def sumdata(a,b):
return a+b
# Rectangle.permeter(2,4) #这样写会报错的。类不能直接调用实例方法,类必须要实例化才能调用方法(实例方法只能用实例调用)
rec=Rectangle(3,4) #创建一个实例对象
print(rec.permeter()) #实例方法只能用实例调用
print(rec.area())
Rectangle.features() #类方法可以用类调用,也可以用实例调用
rec.features()
print(rec.__dict__) #查看实例属性
print(rec.sumdata(23,43))
print(Rectangle.sumdata(23,33)) #类和实例都可以调用静态方法
#type的方式验证静态方法是否是函数
print(type(rec.sumdata)) #运行结果:。注意sumdata后不能跟小括号,因为这样判断的类型就是sumdata函数返回值的类型了,而不是sumdata本身
print(type(rec.permeter)) #运行结果:method为方法,function为函数
#inspect模块
import inspect #python的自检模块,可以判断一个对象是否是某种类型
print(inspect.ismethod(rec.area)) #说明实例方法是方法,返回值是布尔类型
print(inspect.ismethod(rec.features)) #说明类方法是方法
print(inspect.isfunction(rec.sumdata)) #说明静态方法是函数
#继承
#完全继承
class Square(Rectangle):
pass
squ=Square(6,6)
print(squ.permeter())
print(squ.area())
#部分继承
class Square(Rectangle):
def __init__(self,side):
self.length=side
self.width=side
squ=Square(6)
print(squ.permeter())
print(squ.area())
注:如果全部重写,其实相当于没有继承任何方法,没有任何的意义
2.3重载
重载就是重新写了该方法的内容,如果你想保留父类的该方法,可加上super()
#重载,有时对于某方法,想继承一部分,又不想彻底重写,只想增补一些内容
class Square(Rectangle):
def __init__(self,side):
self.length=side
self.width=side
@classmethod
def features(cls):
# Rectangle.features() #与下一行的作用是相同的,选一种使用即可
super().features() #保留父类方法中的内容
print('长和宽也相等')
squ=Square(6)
squ.features()
2.4多继承
class Youqian2:
def money(self):
print('有钱2个亿')
class Youqian1:
def money(self):
print('有钱1个亿')
class Human(Youqian1,Youqian2): #继承多个类时,中间用逗号隔开,书写的顺序决定继承的顺序
pass
hum=Human()
hum.money() #方法名相同时调用,会执行写到前面的那个类中定义的方法。所以该运行结果是:有钱1个亿
2.5扩充
所有的类都是object的子类,无论是否声明继承object,其实都继承了
class Class1:
'''
两岸猿声啼不住
轻舟已过万重山
'''
class Class2(object):
pass
print(Class1.__doc__) #显示类的注释
print(Class1.__name__) #显示类的名称
print(Class1.__bases__) #显示父类的名称
三.封装
封装是面向对象编程(OOP)的基石之一,它涉及到将对象的数据(属性)和操作这些数据的代码(方法)捆绑在一起的概念。这不仅可以保护对象的状态免受外部干扰,还可以简化外部与对象的交云。
3.1数据隐藏
- 私有属性和方法:通过在属性或方法名前添加双下划线(__)来定义私有属性和方法,这样它们就不能从类的外部被访问或修改,只能通过类的内部方法访问。
私有属性和方法案例
- 私有属性,在属性的前面加__就是私有属性
- 私有方法,在方法的前面加__就是私有方法
- 私有属性和私有方法不能被外部直接访问,也不能被子类直接继承
class Cls1:
__a=10 #私有属性
def __init__(self):
pass
def __yinchang(self):
print('这是一个私有方法')
def aabbcc(self):
print(self.__a) #私有属性可以被类当中的方法访问
self.__yinchang() #私有方法可以被类当中的其他方法访问
cls1=Cls1()
# print(cls1.__a) #这样会报错
cls1.aabbcc()
# cls1.__yinchang() #这样会报错
class Cls2(Cls1):
pass
cls2=Cls2()
# print(cls2.__a) #这样会报错
四.多态
多态是面向对象编程中的一个核心概念,它允许我们使用一个统一的接口来操作不同的数据类型。在 Python 中,多态意味着不同类的对象可以对同一个方法调用做出不同的响应。这通常是通过继承和方法重写实现的
案例一:
#多态 几个类当中有同名的方法,根据传的实例的不同,调用不同的方法
class Animal:
def say(self):
pass
class Dog(Animal): #定义一个狗的类
def say(self):
print('汪汪') #打印汪汪
class Cat(Animal): #定义一个猫的类
def say(self):
print('喵喵') #打印喵喵
def anmial_say(obj): #定义一个函数,根据传的实例调用各自的say()方法
obj.say()
dog=Dog()
cat=Cat()
anmial_say(dog)
anmial_say(cat)
注意:anmial_say方法中的obj参数是要传类的实例对象
案例二:
class Fanguan:
pass
class Yuxiangrousi(Fanguan):
def caidan(self):
print('鱼香肉丝')
class Gongbaojiding(Fanguan):
def caidan(self):
print('宫保鸡丁')
class Qingjiaotudousi(Fanguan):
def caidan(self):
print('青椒土豆丝')
def fuwuyuan(obj):
obj.caidan()
guke1=Yuxiangrousi()
guke2=Gongbaojiding()
guke3=Qingjiaotudousi()
fuwuyuan(guke1)
fuwuyuan(guke2)
fuwuyuan(guke3)