【Python】类与对象
前提紧要:
本文介绍了Python面向对象编程的核心概念,包括类与对象的定义、类的组成、特殊方法和三大特性。主要内容包括:
类与对象基础:类作为蓝图定义类型,对象是类的具体实例。通过class关键字定义类,使用类名()创建对象。
类的组成:包含成员属性(在__init__方法中定义)和成员方法(带self参数)。介绍了__init__初始化方法和__str__字符串表示方法。
封装特性:通过双下划线__实现属性/方法私有化,使用@property装饰器控制访问。
三大特性:重点讲解了封装的概念,通过隐藏内部实现细节,仅暴露必要接口(如洗衣机案例中的操作方法)。
文章通过代码示例展示了如何定义类、创建对象、访问属性和调用方法,并说明了私有化机制和封装原则在实际编程中的应用。
1. 类与对象
● 类是描述了一种类型(相当于图纸)
● 对象是这个类型的具体实现(相当于图纸具体实现)
旺财 和 狗,哪个是类,哪个是对象?
1.1. 类定义与实例化
类的定义格式:
class 类名:
pass
创建对象:
对象名 = 类名()
# 定义类
class Person:
pass
# 创建对象
p1 = Person()
1.2. 类的组成
类可以描述世间万物,类都需要有类名,也应该具备一些属性和行为
● 类的关键字:
class
● 类的名称:类名
● 类的属性:一组数据
● 类的方法:允许进行操作的方法(行为)
人(Person)类应该具备什么属性和行为呢?
1.2.1. 成员属性
成员属性的定义需要在初始化方法 init 方法下定义
def __init__(self):
self.属性 = 属性值
#在创建对象时,属性值可以由外部传进来,也可以在初始化方法里设置为任意值
class Person:
def __init__(self, name, age):
# 成员属性
self.name = name
self.age = age
# 创建对象
p = Person('张三', 30)
# 访问成员属性
print(p.name)
print(p.age)
1.2.2. 成员方法
成员方法的定义格式为:
def 函数名(self):
成员方法都会默认有参数self,调用的时候不需要传递self
class Person:
# 定义成员方法 say_hello
def say_hello(self):
print('hello')
# 定义成员方法run
def run(self):
print('跑')
# 创建对象
p = Person()
# 调用成员方法
p.say_hello()
1.3. 特殊方法和参数
1.3.1. 成员方法的self参数
● 成员方法中self表示调用该方法的对象
● 对象调用方法时,python解释器会把这个对象作为第⼀个参数传递给方法
● 通过self也可以获取对象的属性,调用对象的其它成员方法
class Person:
def __init__(self, name, age):
# 定义成员属性
self.name = name
self.age = age
def say_hello(self):
# 通过self访问成员属性
print(self.name)
# 对象
p = Person('张三', 30)
p.say_hello()
1.3.2. __init__方法
●
__init__是一个内置的方法
● 当对象创建的时候就会自动执行__init__方法
# 定义类
class Person:
def __init__(self):
print('执行了init方法')
# 创建对象
p1 = Person()
p2 = Person()
1.3.3. __str__方法
● __str__也是类的内置方法
● 用于将对象转化为适于人阅读的形式
class Person:
def __init__(self,name,age):
# 成员属性
self.name = name
self.age = age
# 创建对象
p1 = Person('张三',30)
p2 = Person('李四',40)
print(p1)
print(p2)
创建了两个对象,输出两个对象
结果:
<__main__.Person object at 0x03769D10>
<__main__.Person object at 0x03769FD0>
从结果中我们并不能区分出到底哪个是属于
p1,哪个是属于p2
可以通过str提取对象的主要特征用于区分不同的对象
class Person:
def __init__(self,name,age):
# 成员属性
self.name = name
self.age = age
def __str__(self):
'''
以字符串输出对象,把对象变成我们能够读懂的形式输出出来
:return:
'''
return 'name:{}, age:{}'.format(self.name,self.age)
# 创建对象
p1 = Person('张三',30)
p2 = Person('李四',40)
print(p1)
print(p2)
输出结果:
name:张三, age:30
name:李四, age:40
1.4. 私有化
将属性或者方法设置为不能在外部访问,就是私有化
1.4.1. 属性私有化
属性私有化格式,注意是两个下划线
__self.__属性名 = 属性值
class MyClass:
def __init__(self, public_value, private_value):
self.public_value = public_value # 公有属性
self.__private_value = private_value # 私有属性
def get_private_value(self):
return self.__private_value # 通过公有方法访问私有属性
def set_private_value(self, value):
self.__private_value = value # 通过公有方法修改私有属性
# 创建类的实例
obj = MyClass(10, 20)
# 访问公有属性
print("公有属性:", obj.public_value) # 输出: 公有属性: 10
# 访问私有属性(会报错)
# print("私有属性:", obj.__private_value) # AttributeError: 'MyClass' object has no attribute '__private_value'
# 通过公有方法访问私有属性
print("私有属性:", obj.get_private_value()) # 输出: 私有属性: 20
# 通过公有方法修改私有属性
obj.set_private_value(30)
print("修改后的私有属性:", obj.get_private_value()) # 输出: 修改后的私有属性: 30
1.4.2. 方法私有化
1.4.2.1. 单下划线 (_)
单下划线前缀是一种约定,表示该方法或属性是“受保护的”或“私有的”,但实际上它仍然可以被外部访问。这只是一种约定,Python并不会阻止你访问它
class MyClass:
def _private_method(self):
return "This is a private method"
obj = MyClass()
print(obj._private_method()) # 仍然可以访问
双下划线 (__)
双下划线前缀会导致Python对名称进行“名称修饰”(name mangling),使得它在类外部更难被直接访问。名称修饰的规则是在名称前加上 _类名,从而使得它在外部访问时需要特定的方式
class MyClass:
def __private_method(self):
return "This is a private method"
obj = MyClass()
# print(obj.__private_method()) # 这行会报错
print(obj._MyClass__private_method()) # 通过名称修饰后的名称访问
1.4.2.2. 使用 @property 和私有属性
使用
@property装饰器来实现对私有属性的访问控制
class MyClass:
def __init__(self):
self.__private_attribute = "This is private"
@property
def private_attribute(self):
return self.__private_attribute
@private_attribute.setter
def private_attribute(self, value):
self.__private_attribute = value
obj = MyClass()
print(obj.private_attribute) # 通过property访问
obj.private_attribute = "New value" # 通过setter修改
print(obj.private_attribute) # 再次通过property访问
1.5. 面相对象的三大特性
● 封装 (Encapsulation)
● 继承 (Inheritance)
● 多态 (Polymorphism)
1.5.1. 封装
封装就是隐藏内部实现的细节,只保留功能接口
class WashMachine:
def __init__(self, brand, capacity):
"""
初始化
:param brand: 品牌
:param capacity: 容量
"""
self.brand = brand
self.capacity = capacity
# 是否关闭
self.is_closed = False
# 模式 0:未设定模式 1:轻揉模式 2:狂揉模式
self.__mode = 0
# 马达转速
self.motor_speed = 0
def open_door(self):
self.is_closed = False
print('打开洗衣机门')
def close_door(self):
self.is_closed = True
print('关闭洗衣机门')
def set_mode(self, new_mode):
"""
调节模式
:param new_mode:
:return:
"""
if new_mode not in [1, 2]:
print('设置模式错误')
else:
self.__mode = new_mode
def __set_motor_speed(self, speed):
"""
设置马达的转速
:param speed: 1000: 轻揉模式 2000:狂揉模式
:return:
"""
self.motor_speed = speed
def wash(self):
if not self.is_closed:
# 洗衣机门是否关闭 ,没有关闭 提示
print('请关闭洗衣机门...')
return
elif self.__mode == 0:
print('请设置模式')
return
# 执行下面的操作
print('放水...')
print('放满了...')
if self.__mode == 1:
print('轻揉模式')
# 调节马达转速
self.__set_motor_speed(1000)
print('马达转速:{}'.format(self.motor_speed))
print('开始洗...')
elif self.__mode == 2:
print('狂揉模式')
# 调节马达转速
self.__set_motor_speed(2000)
print('马达转速:{}'.format(self.motor_speed))
print('开始洗...')
print('洗完了')
machine = WashMachine('海尔', 20)
machine.open_door()
machine.close_door()
machine.set_mode(2)
machine.wash()
1.5.2. 继承
继承指的是一个对象直接使用另一个对象的属性或方法
class 子类名(父类名):
"""------------------ 定义Person类 ------------------"""
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def say_hello(self):
print('hello from ', self.name)
"""------------------ 定义Student类继承Person ------------------"""
class Student(Person):
def __init__(self, name, age, score):
# 调用父类的初始化方法
super().__init__(name, age)
# 定义自己的属性
self.score = score
# 创建学生类
stu = Student('小明', 15, 95)
# 访问属性
print("name: {} age: {} height: {}".format(stu.name, stu.age, stu.score))
# 调用方法
stu.say_hello()
1.5.3. 多态
● 多态指的是一类事物有多种形态(一个类有多个子类)
● 多态的概念依赖于继承
"""
多态案例
"""
# 父类
class Human:
def eat(self):
print('人类吃饭')
# 中国人
class ZhHuman(Human):
def eat(self):
print('中国人使用筷子吃饭')
# 美国人
class UsHuman(Human):
def eat(self):
print('美国人使用刀叉吃饭')
# 非洲人
class AfricaHuman(Human):
def eat(self):
print('非洲人直接用手吃饭')
# 函数
def someone_eat(someone):
'''
接收一个具备吃eat功能的对象
'''
someone.eat()
# 创建四个对象
human = Human()
zh_human = ZhHuman()
us_human = UsHuman()
africa_huamn = AfricaHuman()
# 调用方法
someone_eat(human)
someone_eat(zh_human)
someone_eat(us_human)
someone_eat(africa_huamn)
中国人、美国人、非洲人都是属于Human人类的子类,对于Human来说有多个子类就称为多态。
someone_eat方法需要接收具备eat功能的对象,但是由于ZhHumanUSHumanAfricaHuman都具备eat功能(继承了Human),所以也可以传递到someone_eat方法中
1.5.4. 多继承
当一个类从多个父类继承属性和方法时,就称为多继承
class 子类(父类1,父类2...)
class Animal:
def __init__(self, name):
self.name = name
def eat(self):
print(f"{self.name} is eating.")
def sleep(self):
print(f"{self.name} is sleeping.")
class Flyable:
def fly(self):
print(f"{self.name} is flying.")
class Swimmable:
def swim(self):
print(f"{self.name} is swimming.")
class Duck(Animal, Flyable, Swimmable):
def __init__(self, name):
super().__init__(name)
duck = Duck("Donald")
duck.eat() # 输出: Donald is eating.
duck.sleep() # 输出: Donald is sleeping.
duck.fly() # 输出: Donald is flying.
duck.swim() # 输出: Donald is swimming.
2. 异常处理
什么是异常?
● 程序在运行过程中,发生了未知的事件,影响到了程序的正常运行
● 异常是一种事件
● 异常会影响到程序正常运行
a = 10
b = 0
c = a/b
print(c)
Traceback (most recent call last):
File "c:\Users\Administrator\Desktop\测试工程\测试1.py", line 3, in <module>
c = a / b
ZeroDivisionError: division by zero
出现了
ZeroDivisionError异常
出现异常会造成程序停止
2.1. 异常捕获
try:
代码
except:
出现异常的代码
# 捕获异常
try:
result = a / b
print('没有异常',result)
except:# 如果代码有异常会执行 ,没有异常并不会执行
print('出现了异常')
# 捕获异常的类型
try:
a = 10
b = 0
result = a / b
print('没有异常',result)
except Exception as error:# 如果代码有异常会执行 ,没有异常并不会执行
print('出现了异常',error)
2.2. finally
try:
逻辑代码
finally:
无论是否出现异常,都会执行
try:
a = 1 / 0
print("异常之后的代码", a)
finally:
print("finally里的代码")
2.3. try except finally语法
try:
逻辑代码
except Exception as error:
print(error)
finally:
无论是否出现异常,都会执行
f = open('a.txt','w')
try:
f.write('hello')
# 出现异常
a = 10
b = 0
re = a/b
except:
print('出现异常')
finally: # 即使程序出现异常 finally里面的代码也可以继续执行
# 必须要关闭 内存泄漏
# 无论文件是否操作失败,最终都需要关闭文件
# 所以把文件关闭的方法放到finally中
f.close()
print('文件已经关闭了')
2.4. try except else finally 语法
try:
逻辑代码
except Exception as error:
print(error)
else:
没有出现异常的逻辑
finally:
无论是否出现异常,都会执行
a = 10
b = 0
try:
result = a / b
print(result)
except:
print('出异常')
else:
print('没有出异常')
finally:
print('最终执行的代码')
2.5. 多重捕获
# 可以通过多个except捕获不同的异常分别处理
try:
a = 1 / 0
b = [1, 2]
c = b[4]
except IndexError as error:
print("indexerror 错误逻辑")
except ZeroDivisionError as error:
print(error)
2.6. 常见的异常类型
2.6.1. IndexError
# 角标越界异常
lst = [10, 20, 30]
print(lst[6])
2.6.2. KeyError
# KeyError 字典中 的键不存在
d = {'name':'张三','age':30}
print(d['phone'])
2.6.3. ValueError
# ValueError 数据转换时出错
str = 'abc'
print(int(str))
2.6.4. AttributeError
class Person:
def __init__(self):
self.name = '张三'
self.age = 30
p = Person()
print(p.id)
3. 实战练习
'''
需求:
实现银行账户管理系统
BankAccount类:这是银行账户的类,包含账户持有人姓名和余额两个属性。
__init__:构造函数,用于初始化账户持有人和余额。
deposit:存款方法,允许用户向账户存入金额。
withdraw:取款方法,允许用户从账户取出金额。
get_balance:获取当前余额的方法。
__str__:返回账户信息的字符串表示。
'''
class BankAccount:
def __init__(self, account_holder, balance=0.0):
self.account_holder = account_holder
self.balance = balance
def deposit(self, amount):
if amount > 0:
self.balance += amount
print(f"存款成功!当前余额为: {self.balance}")
else:
print("存款金额必须大于0")
def withdraw(self, amount):
if amount > 0:
if self.balance >= amount:
self.balance -= amount
print(f"取款成功!当前余额为: {self.balance}")
else:
print("余额不足,无法取款")
else:
print("取款金额必须大于0")
def get_balance(self):
print(f"账户 {self.account_holder} 的当前余额为: {self.balance}")
return self.balance
def __str__(self):
return f"账户持有人: {self.account_holder}, 余额: {self.balance}"
# 示例使用
if __name__ == "__main__":
# 创建一个账户
account = BankAccount("张三", 1000.0)
# 存款
account.deposit(500.0)
# 取款
account.withdraw(200.0)
# 查看余额
account.get_balance()
# 打印账户信息
print(account)
以上,欢迎有从事同行业的电子信息工程、互联网通信、嵌入式开发的朋友共同探讨与提问,我可以提供实战演示或模板库。希望内容能够对你产生帮助!
更多推荐
所有评论(0)