python - 类和对象:面向对象、继承、组合

2025.2.25更新:
有点晦涩混乱,重新梳理一下

面向对象编程

用造物主的视角去编写程序。也是一种代码封装的方法,就是将相关的数据和实现的函数封装到了一起,每封装一个类,就如同创造出了一类物种,再顺着物种去逐个创造生物——也就是对象。

面向对象编程的三个特点:封装、继承、多态。

对象和类

先从现实世界开始。我们描述一个物件或生物,可以通过它的静态属性特征、动态行为特征两方面去描述,例如描述一只狸花猫,它的静态属性可以有虎纹、大耳朵、全包眼线,动态特征则可以有会跳、会打架、会睡觉。

对应到对象里,猫这个对象就具有了属性和方法的描述。所以可得:对象的描述 = 属性 + 方法
(一般好像会写作对象 = 属性 + 方法,但对我来说容易混淆,故为了区分类和实例化对象做了自己的修改。)

在得到一个对象之前,先创建类,再创建对象。就比如先做模具,再批量生产。

# 类名称开头约定大写
class Lihuacat :
	color = 'tigerlook'
	ear_features = 'bigears'
	eye_features = 'full-coverage eyeliner'
	
	# self参数是什么?见下文展开
	def jump(self):
		print('我跳!')
	
	def beat(self):
		print('我打!')
		
	def bite(self):
		print('我咬!')

可以看到,在代码层面的体现上,属性,就是写在类里面的变量;方法,就是写在类里面的函数。

对象实例化

这时候,完成了类的创建,这个类的内部包含的是对这一类对象的描述。接下来,根据这个描述,我们再去创建真正的对象——这便是对象实例化。

如何完成对象实例化?将类赋值到一个变量,即完成了一个对象的实例化,这个变量才是真正被创造出来了的对象。

# 就这样完成对象实例化
lhc = Lihuacat()

# 然后就可以通过lhc这个对象调用类中的属性或方法了

类和对象的使用

通过对象调用类中的属性和方法

完成对象实例化之后呢,于是类里面的属性(变量)和方法(函数)都可以通过这个实例化对象用点操作符连接,像调用函数一样来进行调用:

print(lhc.color)
>>>tigerlook

lhc.bite()
>>>我咬!

利用类创建更多类似的对象

前面说到类就如同模具,所以同理,一个类可以创造出无数个对象,只需要赋值到不同的变量名就可以了:

lhc = Lihuacat()
lhc1 = Lihuacat()
lhc2 = Lihuacat()

创建好的对象可以随意修改它的属性值了,也可以给它增添属性:

lhc1.ear_features = 'smallears'
lhc2.color = 'lionlook'
lhc.paw = 'white'

此时再重新调用lhc1或lhc2,输出的就是各自修改后的属性值了,同时也可以印证,同一个类创建的不同对象之间不会共享数据,就像一个物种中的不同生物个体也是各长各的。

self参数

类中的每一个实例方法都必须将 self 作为第一个参数。因为,同一个类可以生成无数个对象,由上文也已知不同对象的方法是各论各的,当一个对象的方法被调用的时候,对象会将自身的引用作为第一个参数传给该方法,于是python就知道需要操作哪个对象的方法了,就像同一个模具生产出来 的产品有不同的编号,对不同产品做处理就传入不同的编号,这就是self参数的用处。

打个比方说,我们写一个点名的类,当作点名名单纸,利用这个类里的方法体现一下self参数的传递:

class roll_call:
	# 写一个创建姓名属性的方法
	def stu_name(self,name):
		# self.name是实例的一个属性,这里意思是本方法将外部传入的名字给到名为name的实例属性
		self.name = name
		
	# 再写一个点名方法
	def call(self):
		print("嘿!%s,你被老师点到辣!" % self.name)

# 有了点名单这个载体后,我们来创建几个学生名字实体
a = roll_call()
b = roll_call()
c = roll_call()

# 分别各自调用类中创建姓名方法,单独改好不同对象对应的学生名字
a.stu_name('Alice')
b.stu_name('Bob')
c.stu_name('Carol')

# 接下来再各自调用类中的点名方法,不同对象就得到不同点名
a.call()
>>>嘿!Alice,你被老师点到辣!

b.call()
>>>嘿!Bob,你被老师点到辣!

c.call()
>>>嘿!Carol,你被老师点到辣!

继承

面向对象编程的第二个重要特性:继承,通过继承创建的类我们叫子类,这些子类可以继承现有类,亦即父类的属性和方法。通过继承,子类可以复用父类的代码,也可以添加自己独特的属性和方法,或者对父类的方法进行重写。

子类与父类

  • 父类:也叫基类或超类,定义了通用的属性和方法。
  • 子类:也称为派生类,继承父类的属性和方法,还可添加新特性或重写父类方法。

试着创建包含继承关系的类:

# 定义父类
class Parent:
    def parent_method(self):
        print("这是父类的方法")

# 定义子类,即将父类名添个括号加在子类名后面表示继承关系
class Child(Parent):
    pass 	# 写个占位符示例一下、

# 实例化父类对象
p = Parent()
# 实例化子类对象
c = Child()

# 子类对象可调用父类方法
c.parent_method()

>>>这是父类的方法

不过要注意,如果子类中有与父类同名的方法或属性,则在通过子类调用父类方法时,子类中的那个同名的方法会覆盖掉父类的方法,也就是如果同名,调用子类的方法时输出优先级子类比父类高。比如说:

class Parent:
	    def method(self):
	        print("这是父类的方法")
	        
class Child(Parent):
    def method(self):
        print("这是子类的方法")

# 实例化父类对象
p = Parent()
# 实例化子类对象
c = Child()

# 再调用时:
c.method()

>>>这是子类的方法

那么,一个子类能否继承多个父类呢?答案是可以的,这就是:

多重继承

Python 支持一个子类同时继承多个父类,子类可从多个父类获取属性和方法。

在多重继承中,当子类调用一个方法或访问一个属性时,Python 会按照从左到右的顺序在父类中查找。除非子类调用的方法或属性在左边的父类中查找不到,才会到右边下一个父类里查找。这种查找顺序也被称为方法解析顺序(Method Resolution Order,MRO)。可以通过 类名.mro 查看具体的查找顺序。

class Parent1:
    def method(self):
        print("Parent1 method")

class Parent2:
    def method(self):
        print("Parent2 method")

class Child(Parent1, Parent2):
    pass

c = Child()
c.method()  

>>>Parent1 method

# 查看 MRO
print(Child.__mro__)#输出结果会显示一个元组,元组中的元素表示 Python 在查找方法和属性时的顺序。

不过,多重继承很容易导致代码混乱,所以非必要还是尽量避开使用。

判断从属关系的函数

isinstance 函数

用于判断一个对象是否是某个类或其子类的实例,返回布尔值。

print(isinstance(child_obj, Child))  # 输出: True
print(isinstance(child_obj, Parent)) # 输出: True

issubclass 函数

用于判断一个类是否是另一个类的子类,返回布尔值。

print(issubclass(Child, Parent))  # 输出: True

组合

假如说,想要把几个类放在一起,组成新的类,那么就是组合。比如说,公园里有动物有植物,我们想把动物类和植物类放进公园类里,可以这么写:

class Plants:
	def __init__(self,x):
		self.num = x
		
class Animals:
	def __init__(self,x):
		self.num = x
		
class Parks:
	def __init__(self,x,y):
		self.plants = Plants(x)
		self.animals = Animals(y)
	
	def print_num(self):
		print("公园里总共有植物%d种,动物%d种"%(self.plants.num,self.animals.num))
		
parks = Parks(2,3)
parks.print_num()


>>>公园里总共有植物2,动物3
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值