python 面向对象

本文介绍了Python中的面向对象编程,包括类的定义、封装、继承和多态等概念。通过实例解析了如何创建类、使用封装保护变量、实现继承以及理解和使用类属性和实例对象属性。还探讨了动态修改类属性和方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言

面向对象是一种编程思想,与面向过程相对应。

面向过程是分析解决问题所需的步骤,用函数实现每个步骤,最后从头到尾依次调用。
面向对象是把问题分派给多个人,让每个人完成自己应做的任务,最后选择合适的人和顺序来解决问题。

面向过程的优点是按步骤、逻辑清晰,但在复杂庞大的项目中效率低下。
面向对象增加了程序的可扩展性,但同时也使开发人员不易预知对象之间的交互结果。

面向对象包含继承、封装、多态三个特征。

1. 面向对象的基础——类

类是描述具有相同的属性和方法的对象的集合。它定义了该集合中每个对象所共有的属性和方法。对象是类的实例。

定义一个类

  • class People(object):
    People是自定义的类名,首字母大写
    object是所有类默认继承的父类,可省略
  • __new__(cls)
    定义类时,默认加载new方法。
    创建一个类对象的地址,并返回给实例对象
  • __init__(self)是初始化方法/构造函数,用于初始化实例对象的变量。
    其中self指的是实例对象,设置self.name可在整个类中使用
  • 创建实例对象
    a = People("张三", 20, "男")
    a是自定义的People类的实例对象
class People:
	# new方法,创建地址并返回给实例对象
	def __new__(cls):
    	return super().__new__(cls)
	
    # 初始化方法/构造函数,初始化数据属性
    def __init__(self, name, age=None, gender=None):
        self.name = name
        self.age = age
        self.gender = gender

    def eat(self):
        print(f"{self.name}吃饭")


# 创建实例对象
a = People("张三", 20, "男")
b = People("李四", 25, "女")

示例

要求:设计“老张开车去东北”

分析:面向对象是将一个问题分派给多个对象去完成。

  1. 首先确定对象:人、车、地点,创建三个类People、Car、Place

  2. 再确定每个对象的属性和任务:

人:姓名——开车

class People:
    def __init__(self, name):
        self.name = name

    def drive(self, car, place):
        print(f"{self.name}开车")

车:品牌/速度——行驶

class Car:
    def __init__(self, brand, speed):
        self.brand = brand
        self.speed = speed

    def move(self):
        print(f"{self.name}行驶ing...")

地点:地名/距离——(无行为)

class Place:
    def __init__(self, name, distance=0):
        self.name = name
        self.distance = distance
  1. 车在行驶过程中,离目的地距离随时间变化,因此在Car类的move方法中调用Place对象的distance属性
    距离非0时,汽车行驶,距离递减,
    直到距离为0,到达目的地。
    def move(self):
        while place.distance > 0:
            print(f"{self.brand}行驶中,还有{place.distance}公里...")
            place.distance -= self.speed
            time.sleep(1)
        print(f"到达{place.name}!")
  1. 人的开车行为会使汽车行驶,因此在People类的drive方法中调用Car对象的move方法
class People:
    def __init__(self, name):
        self.name = name

    def drive(self, car, place):
        print(f"~~~{self.name}驾驶{car.brand}去往{place.name}~~~")
        car.move()
  1. 创建实例对象,调用类的方法
# 创建实例对象
zhang = People("老张")
car = Car("五菱宏光S", 50)
place = Place("东北", 500)
# 老张开车去东北
zhang.drive(car, place)

结果:

~~~老张驾驶五菱宏光S去往东北~~~
五菱宏光S行驶中,还有500公里...
五菱宏光S行驶中,还有450公里...
五菱宏光S行驶中,还有400公里...
五菱宏光S行驶中,还有350公里...
五菱宏光S行驶中,还有300公里...
五菱宏光S行驶中,还有250公里...
五菱宏光S行驶中,还有200公里...
五菱宏光S行驶中,还有150公里...
五菱宏光S行驶中,还有100公里...
五菱宏光S行驶中,还有50公里...
到达东北!
  1. 完整代码
import time


class People:
    def __init__(self, name):
        self.name = name

    def drive(self, car, place):
        print(f"~~~{self.name}驾驶{car.brand}去往{place.name}~~~")
        car.move()


class Car:
    def __init__(self, brand, speed):
        self.brand = brand
        self.speed = speed

    def move(self):
        distance = place.distance
        while distance > 0:
            print(f"{self.brand}行驶中,还有{distance}公里...")
            distance -= self.speed
            time.sleep(1)
        print(f"到达{place.name}!")


class Place:
    def __init__(self, name, distance=0):
        self.name = name
        self.distance = distance


# 创建实例对象
zhang = People("老张")
car = Car("五菱宏光S", 50)
place = Place("东北", 500)
# 老张开车去东北
zhang.drive(car, place)

# 创建实例对象
wang = People("小王")
car = Car("mini", 100)
place = Place("云南", 1210)
# 小王开车去云南
wang.drive(car, place)

2. 封装、继承、多态

2.1 封装

在面向对象程式设计方法中,封装(英语:Encapsulation)是指一种将抽象性函式接口的实现细节部份包装、隐藏起来的方法。
封装可以被认为是一个保护屏障,防止该类的代码和数据被外部类定义的代码随机访问。
要访问该类的代码和数据,必须通过严格的接口控制。
封装最主要的功能在于我们能修改自己的实现代码,而不用修改那些调用我们代码的程序片段。
适当的封装可以让程式码更容易理解与维护,也加强了程式码的安全性。
https://www.runoob.com/java/java-encapsulation.html

公有变量、受保护的变量、私有变量

  • 公有变量:可以随意访问与修改

  • 受保护的变量_,建议只在类内访问和修改
    类外访问和修改不会出错,但波浪线提示:正在访问一个受保护的变量
    python中的受保护变量只是一种自我约定(口头约定),可以访问但是不建议访问

  • 私有变量__,只允许类内访问
    类外访问时报错:AttributeError: 没有这个属性
    类外修改时不会报错,但修改无效

class Person:

    def __init__(self, name, age, number):
        self.name = name  # 公有变量
        self._age = age  # 受保护的变量_,建议只在类内访问
        self.__number = number  # 私有变量__,只允许类内访问


# 创建实例对象
p = Person("老王", 28, "001")

# 公有变量:
p.name = "小王"
print(p.name)

# 受保护的变量:
print(p._age)  # 波浪线提示:正在访问一个受保护的变量
#              # 注意:python中的受保护变量只是一种自我约定(口头约定),可以访问但是不建议访问

# 私有变量:
print(p.__number)  # 访问时报错:AttributeError: 没有这个属性
p.__number = "100"
p.info()  # 修改不报错,但修改无效
  • 若想访问和修改私有变量:设置set和get方法,即为外界提供一个接口
class Person:

    def __init__(self, name, age, number):
        self.name = name  # 公有变量
        self._age = age  # 受保护的变量_,建议只在类内访问
        self.__number = number  # 私有变量__,只允许类内访问

    # 更改私有变量
    def set_number(self, value):
        self.__number = value

    # 访问私有变量
    def get_number(self):
        return self.__number


## 若要修改或访问必须在类内部,设置set/get方法
p = Person("老王", 28, "001")
p.set_age(100)
print(p.get_age())
  • 快速设置set和get方法:
    props+enter
    @property
    def number(self):
        return self.__number

    @number.setter
    def number(self, value):
        if value < 10000:
            self.__number = value

【注意!】:
在类外修改私有属性:
不是调用方法传参 p.number(456)
是直接对示例对象的私有变量进行赋值!p.number = 456

p = Person("tom", 20, 123)
print(p)

# 改变tom的number
# p.number(456)  # TypeError: 'int' object is not callable
p.number = 456  # 更改私有变量,直接赋值
print(p)

运行结果:

tom	20	123
tom	20	456

2.2 继承

继承就是子类继承父类的特征和行为,使得子类对象(实例)具有父类的实例域和方法,或子类从父类继承方法,使得子类具有父类相同的行为。
https://www.runoob.com/java/java-inheritance.html

  • 单继承
class Person:
	pass
class Man(Person):
	pass

Man类继承一个Person类
具有Person类的属性和方法
可直接使用

  • 多继承
class Man:
	pass
class Woman:
	pass
class Someone(Man, Woman):
	pass

Someone类继承一个Man类,一个Woman类
具有两个类的属性和方法

多继承中的继承优先级问题:

如果Someone继承的两个类中含有同名属性和方法,就会出现优先级的问题。

  1. 继承的父函数的父函数只有默认的object时,优先使用第一个类(即Man类)的属性/方法
class Man:
	pass
class Woman:
	pass
class Someone(Man, Woman):
	pass
  1. 继承的父函数都继承同一个类
class Person:
	pass
class Man(Person):
	pass
class Woman(Person):
	pass
class Someone(Man, Woman):
	pass

Man类和Woman类都继承Person类,
Someone调用属性/方法的顺序:
self->Man->Woman->Person。
在这里插入图片描述

  1. 继承的父函数继承不同的类
class Person1:
	pass
class Person2:
	pass
class Man(Person1):
	pass
class Woman(Person2):
	pass
class Someone(Man, Woman):
	pass

Man类继承Person1类
Woman类继承Person2类
Someone调用属性/方法的顺序:
self->Man->Person1->Woman->Person2。
在这里插入图片描述

4. 类属性和实例对象属性、类方法和实例对象方法

定义

类方法

@classmethod
def play(cls):
	print("类方法")
class Person:
    # 类属性:
    count = 0

    # 实例对象属性
    def __init__(self, name):
        self.name = name

    # 类的方法:
    @classmethod
    def play(cls):
        print("类方法")

    # 类的静态方法:不用传参
    @staticmethod
    def work():
        print("静态方法")
    
    # 实例对象的方法
    def eat(self):
        print(f"实例方法访问类属性{Person.count}")

两者区别在于:

  • 实例对象的属性和方法必须先创建一个实例对象,才能调用
print("实例对象的属性和方法必须先创建实例对象")
p = Person("小王")
p.eat()
  • 类的属性和方法可以直接调用
print("访问类属性、类方法、静态方法,无须创建实例对象")
print(Person.count)
Person.play()
Person.work()
  • 实例对象也可以调用类的属性和方法
print("实例对象可以访问类属性、类方法、静态方法")
p = Person("小王")
print(p.count)
p.play()
p.work()

动态修改

动态语言便于更改数据结构:
写好的代码不建议随意更改,因此需要在使用时动态地添加。

  • 定义一个类,如下。
    此时Cat类中含有一个类属性name、一个实例对象方法eat。
class Cat:
    # 类属性
    name = "tom"

    def __init__(self) -> None:
        super().__init__()

    def eat(self):
        print("eat fish")
  • 添加类属性:新建属性–>直接赋值。
类名.属性=值
Cat.age = 12
  • 添加实例属性:创建实例对象–>新建属性–>赋值
c = Cat()
c.age = 12
print(c.age)
  • 添加类方法和静态方法:定义类方法/静态方法,赋值给类的新建方法名。
# 在类外定义classmethod和staticmethod,并使用

@classmethod
def play(cls):
    print("playing...")
Cat.play = play
Cat.play()

@staticmethod
def sleep():
    print("sleeping..")
Cat.sleep = sleep
Cat.sleep()
  • 添加实例对象方法:创建实例对象,定义带self参数的函数,用types.MethodType将新建函数传给实例对象
import types
def play(self):
    print("playing...")
c = Cat()
c.play=types.MethodType(play,c)
c.play()
  • 在类外定义方法时,要注意方法所带的参数:
    类方法,cls
    静态方法,没有参数
    实例对象方法,self
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值