跟光磊学Python开发-面向对象入门
面向对象概述
当前主流的软件开发思想有两种:面向过程和面向对象,面向过程出现的比较早,典型的面向过程的语言是C语言,能够高效的开发中小型软件,但是很难适用于如今主流的大中型项目开发场景。
面向对象出现的更晚一些,面向对象是基于面向过程发展而来的。典型的代表语言有C++/Java/Python,更加适合大型软件开发的应用场景。
对于面向过程的编程思想:需要实现一个功能的时候,看重的是开发的步骤和过程,每一个步骤都需要自己亲力亲为。
对于面向对象的编程思想:需要实现一个功能的时候,看中的不是过程和步骤,而是关心谁帮我做这个事情,注重结果。
面向对象的编程思想有三大特征:封装、继承、多态
类和对象
类和对象是面向对象编程的两个重要概念
类是对现实事物的特征和行为的抽象,用来描述特征信息以及功能等,不能实际使用,对象是类的描述创造出来的,可以实际使用。
例如苹果公司出iphone12设计图纸,然后富士康根据iphone12的设计图纸制造手机,其中iphone12的设计图纸就是类,而富士康根据设计图纸造出来的手机就是对象。
类的组成
类(Class) 由三部分组成
- 类的名称:类名
- 类的属性:也就是特征
- 类的方法:也就是行为
例如之前写的商品管理系统中的商品就可以定义成一个Product,商品类主要有编号(id)、名称(name)和价格(price)三个属性,同时有增加商品、修改商品、查询商品、查看商品列表等方法。
类的定义
Python中类的定义有两种格式,分别是经典类和新式类
经典类的定义格式
class 类名:
方法别表
使用经典类的定义格式定义产品信息类
class ProductInfoClass:
def init_product(self):
"""
初始化产品
:return:
"""
pass
def search_product_by_id(self, product_id):
"""
根据产品ID查询产品
:param product_id:
:return:
"""
pass
新式类的定义格式
class 类名(object):
方法列表
使用新式类定义产品信息类
"""
新式类定义
"""
class ProductInfoNew(object):
def init_product(self):
"""
初始化产品
:return:
"""
print("执行初始化产品方法")
pass
def search_product_by_id(self, product_id):
"""
根据产品ID查询产品
:param product_id:
:return:
"""
print(f"执行根据产品ID查询产品,产品ID是{product_id}")
pass
- 类名的命名规则遵守驼峰命名法,例如ProductInfo
- object 是所有Python类的顶级父类
- 方法的第一个参数通常是self,表示实例对象本身,其作用是一个变量指向了实例对象
创建对象
类定义完后,就可以创建多个对象,当对象创建完成后,就可以使用对象调用类中定义的属性和方法。
Python创建对象的语法格式如下
对象名 = 类名(参数列表)
实例对象时,会在内存中分配一块唯一的内存空间,这个空间就是对象的位置,然后将这个地址返回给对象名。
# 实例对象
iphone12 = ProductInfoNew()
# 打印对象的信息
print(iphone12)
# 调用对象的方法
iphone12.init_product()
iphone12.search_product_by_id(1)
# 创建多个对象
huawei_mate40 = ProductInfoNew()
print(huawei_mate40)
huawei_mate40.search_product_by_id(2)
程序运行结果
动态绑定属性
在实例化对象以后,可以为该对象动态绑定属性。
动态为对象绑定属性时,给哪个对象绑定了属性,只有哪个对象有该属性,其他对象是没有该属性。
如果在方法中引用了该属性,那么没有该属性的对象调用方法时会报错
"""
动态绑定属性
@author tony 18601767221@163.com
@version 2021-02-06 21:10:07
@since python3.9.1
"""
class ProductInfo(object):
def search_product_by_id(self, product_id):
"""
根据产品ID查询产品
:param product_id:
:return:
"""
# self.name使用动态绑定的name属性,当对象调用该方法时对象必须有name属性,
# 否则会出现AttributeError: 'ProductInfo' object has no attribute 'name'错误
print(f"执行根据产品ID查询产品,产品ID是{product_id},产品的名称是{self.name}")
pass
# 动态绑定属性
# 为对象动态添加name属性
iphone12 = ProductInfo()
iphone12.name = "iphone12"
iphone12.search_product_by_id(1)
# 如果ProductInfo对象不绑定属性,调用方法时会报错
huawei_mate40 = ProductInfo()
huawei_mate40.search_product_by_id(2)
程序运行结果
初始化方法绑定属性
由于在方法中使用了动态绑定的属性后,所有对象都需要动态绑定属性,否则没有属性的对象调用犯法时会报错。
Python提供了一个__init__
方法,这个方法是一个魔法方法,命名规则是init前后都有两个下划线。
魔法方法是Python中设定好的、具有特定功能的方法,一般这种方法不需要手动调用,系统会自动调用执行。
而__init__
方法会在创建对象时自动调用,这个方法调用时为对象执行初始化操作。
绑定属性时,使用self.属性名=属性值
,由于在创建对象时,可以指定参数,此时的参数会传递给__init__
方法的形参。通过形参给属性值赋值
"""
初始化方法__init__绑定属性
@author tony 18601767221@163.com
@version 2021-02-06 21:20:07
@since python3.9.1
"""
class ProductInfo(object):
def __init__(self, name, price):
"""
该方法在创建对象时自动调用
"""
print("execute init method")
print(self)
# 绑定属性
self.name = name
self.price = price
def show_attribute_info(self):
"""
显示属性信息
:return:
"""
# self 表示当前对象
print(self.name)
print(self.price)
# 创建对象时,可以使用__init__方法中绑定的属性
iphone12 = ProductInfo("iphone12 pro max", 12999.99)
print(iphone12)
iphone12.show_attribute_info()
mate40_pro = ProductInfo("mate40 pro plus", 8999.99)
print(mate40_pro)
# 在调用方法时,方法的第一个参数self是不用传参,这个参数由解释器自动调用该方法的对象传递过去
mate40_pro.show_attribute_info()
程序运行结果
__str__
方法
__str__
方法也是一个魔法方法,其作用是格式化对象,该方法必须返回一个字符串,当使用str()
方法做类型转换或者是使用print()
打印对象时会自动调用。
默认实例化对象后如果没有实现__str__
方法时打印对象时默认打印<模块名.类名. object at Ox...>
"""
__str__方法的使用
@author tony 18601767221@163.com
@version 2021-02-06 21:54:52
@since python3.9.1
"""
class ProductInfo(object):
def __init__(self, id, name, price):
"""
该方法在创建对象时自动调用
"""
# 绑定属性
self.id = id
self.name = name
self.price = price
def show_attribute_info(self):
"""
显示属性信息
:return:
"""
# self 表示当前对象
print(self.name)
print(self.price)
iphone12 = ProductInfo(1, "iphone12 pro max", 12999)
print(iphone12)
![程序运行结果 程序运行结果](./images/1612619828384.png)
如果为了格式化输出对象的属性值,可以实现__str__
方法
def __str__(self):
"""
该函数必须有一个返回值,并且这个返回值只能是字符串
如果对象需要按照一定的格式进行格式化,那么可以在这里进行处理,处理完成后将这个格式化字符串返回,
让str()方法在执行时,得到该对象转换的字符串类型
:return:
"""
s = str("商品的id:" + str(self.id).ljust(10) + "商品的名称:" + str(self.name).ljust(20) + "商品的价格:" + str(self.price).ljust(30))
return s
![程序运行结果 程序运行结果](./images/1612620833976.png)
__del__
方法
__del__
方法用于在销毁对象时使用,回收对象占用的资源使用的方法。该方法也是自动调用,当调用del
对象时,也会调用该方法。
python的内存管理由引用计数实现,不需要程序员手动销毁对象,当引用计数为0时系统会自动销毁对象,回收资源。
""""
__del__方法的使用
@author tony 18601767221@163.com
@version 2021-02-06 22:15:27
@since python3.9.1
"""
class ProductInfo(object):
def __init__(self, name):
self.name = name
def __del__(self):
"""
当对象没有引用指向,会自动调用该方法
:return:
"""
# 将当前对象持有的其他对象手动销毁
del self.name
print("delete ProductInfo object")
iphone12 = ProductInfo("iphone12")
# 执行 del iphone12 会自动调用__del__方法,将这个对象销毁,回收内存资源
del iphone12
print("End")
# 删除后的对象无法再使用
print(iphone12)
程序运行结果
__del__
方法在打印End
后被执行
![程序运行结果 程序运行结果](./images/1612621788575.png)
实例属性和实例方法
实例就等价于对象
在Python中万物皆对象,而实例属性和实例方法只能在类的实例对象创建以后通过对象.属性
和对象.方法
的方式来访问。不能通过类名来调用实例属性和实例方法,因为类对象存在时,实例对象不一定存在,类是一个抽象的概念。
"""
实例属性和实例方法
@author tony 18601767221@163.com
@version 2021-02-08 11:33:54
@since python3.9.1
"""
class Account(object):
def __init__(self, name, balance):
"""
定义两个公有属性
公有属性可以在外部访问
:param name:
:param balance:
"""
self.name = name
self.balance = balance
def __str__(self):
s = f"账户名称:{self.name} 账号余额:{self.balance}"
return s
def get_account_info(self):
"""
获取账户信息
:return:
"""
print("获取账户信息:")
# 使用self调用实例方法
print(self.__str__())
# 创建Account类的对象
tony = Account("tony", 99999999)
# 通过对象访问实例属性
print(tony.name)
print(tony.balance)
# 通过对象访问实例方法
tony.get_account_info()
程序运行结果
类对象和类属性
Python中一切皆对象,类也是对象,称为类对象。
当在类中定义一个类属性时,相当于这个类的全局变量,该类的所有对象都可以使用该类的属性,这样可以在所有的对象中间进行数据共享。
类对象和类属性归数于类,而不是归属于类的对象,因此类属性通常使用类访问,而不是对象访问。 类属性虽然可以使用实例对象引用,但是不能修改,如果通过对象修改类属性,等价于给对象绑定属性。
一般情况下类属性使用类对象调用,调用格式是类对象.类属性
"""
类对象、类属性
@author tony 18601767221@163.com
@version 2021-02-08 11:41:03
@since python3.9.1
"""
class UserInfo(object):
# 类中定义的属性,就是类的全局变量
default_register_resource = "app"
def show_default_register_resource(self):
"""
查看默认的注册来源
:return:
"""
# 实例方法访问类属性,直接通过类名.类属性名
print(UserInfo.default_register_resource)
# 多个对象的注册来源是一样的
tony = UserInfo()
print("默认的注册来源", tony.default_register_resource)
jack = UserInfo()
print("默认的注册来源", jack.default_register_resource)
# 给jack对象绑定default_register_resource属性
jack.default_register_resource = "web"
print("通过对象修改类属性", jack.default_register_resource)
print("通过对象修改类属性", tony.default_register_resource)
# 类属性可以使用实例对象引用,但是不能修改,一般情况下类属性使用类对象调用,调用格式是类对象.类属性
#
tony.show_default_register_resource()
![程序运行结果 程序运行结果](./images/1612835557615.png)
类方法和静态方法
类方法和静态方法的应用场景都是设计工具类时使用,类方法和静态方法都是通过类对象调用,而不是通过实例对象调用。
类方法是由类对象调用,类方法的定义格式如下
@classmethod
def 方法名(cls,参数列表):
pass
@classmethod
是一个装饰器,用于表示下面的方法是一个类方法
cls表示类对象参数,调用方法时该参数由解释器自动传入
类方法的调用格式:类对象.类方法名,需要注意的是类方法中不能使用self,但是可以使用cls,该参数用于表示当前类对象,这个参数也是解释器自动传递的。类方法的参数可以实现各个类方法进行共享数据。
类方法的应用场景:如果(工具)类包含了类方法,一般不会去实例对象,直接使用类对象操作,例如数学函数类。
"""
类方法的定义和使用
@author tony 18601767221@163.com
@version 2021-02-09 10:36:52
@since python3.9.1
"""
"""
自定义工具类
"""
class MyMath(object):
# @classmethod 是一个装饰器,用于表示下面的方法是一个类方法
@classmethod
def my_max(cls, *args):
"""
求最大值的方法
cls参数由解释器自动将类对象传入
:param args:
:return:
"""
max_value = args[0]
for i in args:
if i > max_value:
max_value = i
return max_value
# 类方法直接由类名调用
max_value = MyMath.my_max(1, 2, 4, 5, 7, 8, 9, 6, 3)
print("最大值", max_value)
![程序运行结果 程序运行结果](./images/1612840018584.png)
静态方法实际上就是放在类中的普通函数,静态方法和类方法作用类似,但是静态方法不接受任何默认参数,例如self和cls,不需要在创建对象的情况下直接使用类对象调用静态方法,
静态方法的定义格式如下
@staticmethod
def 方法名(参数列表)
pass
静态方法的调用方式:类对象.静态方法名(参数列表)
静态方法的定义和调用
"""
静态方法的定义和使用
@author tony 18601767221@163.com
@version 2021-02-09 11:09:36
@since python3.9.1
"""
"""
编码工具类,只是模拟编码和解码
"""
class EncodeUtil(object):
@staticmethod
def encode_data(data, format):
print(f"开始对{data}以{format}格式进行编码")
@staticmethod
def decode_data(data, format):
print(f"开始对{data}以{format}格式进行解码")
# 静态方法的调用
EncodeUtil.encode_data("hello world","utf-8")
EncodeUtil.decode_data("hello world","utf-8")
![程序运行结果 程序运行结果](./images/1612840642706.png)
__dict__属性
__dict__属性
是一个魔法属性,通过该属性可以看到对象的成员
"""
属性和方法的保存位置
@author tony 18601767221@163.com
@version 2021-02-09 09:55:28
@since python3.9.1
"""
class Storage(object):
def __init__(self, name):
self.__name = name
self.age = 18
def show(self):
print("公有对象方法")
def __display(self):
print("私有对象方法")
tony = Storage("tony")
jack = Storage("jack")
# 查看当前对象的属性和方法 __dict__ 是一个魔法实属性,保存当前对象的所有成员
# 查看Storage类对象的所有成员
print("Storage.__dict__ ->", Storage.__dict__)
# 查看tony对象的所有成员:包含属性
print("tony.__dict__ ->", tony.__dict__)
print("jack.__dict__ ->", jack.__dict__)
程序运行结果
通过程序的运行结果可以看出,成员对象存储了属性,而类对象存储了方法等信息。