欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 科技 > IT业 > python面向对象

python面向对象

2024/10/25 3:27:24 来源:https://blog.csdn.net/weixin_44774550/article/details/139717162  浏览:    关键词:python面向对象

文章目录

  • 一、面向对象基础
  • 二、类的定义、创建和使用
    • 2.1、示例:通讯录
  • 三、属性与方法
    • 3.1、属性
    • 3.2、方法
    • 3.3、类的属性
    • 3.4、数类型于实例属性的比较
    • 3.5、类方法
    • 3.6、访问权限
  • 四、继承和多态


面向对象是一种软件开发方法,一种编程范式。

面向对象是相对于面向过程来讲的,它把相关的数据和方法组织为一个整体,从高的层次来进行系统建模,更贴近事务的自然运行模式。

面向对象程序设计的主要思想是把构成问题的各个事务分解成各个对象,建立对象的目的不是为了完成一个步骤,而是为了描述一个事物在解决问题的步骤中的行为。

面向对象程序设计中的概念主要包括对象、类、数据抽象、继承、动态绑定、数据封装、多态性、消息传递,通过这些概念,面向对象的思想得到了具体的表现。

一、面向对象基础

面向对象的python程序设计中最重要的两个概念就是类(class)和对象(object),在python中,对象被称为实例(instance)。

一个类就是一个可以用来定义同时具备值和操作行为两方面特征的对象的数据结构。

类是把真实世界中的问题抽象化后得到的程序化的表示形式。而实例则是这样一个抽象结果的具体实现。

类和实例是相互关联的:类提供了对一个对象的定义,而实例是根据该定义实际产生出来的对象。

在python中,对类的定义和对函数的定义很相似,代码如下:

class object-name:'define object class'
pass

(注:代码中class是一个关键字,它后面是类的名字接下去是对这个类进行定义的代码。)

创建一个实例的过程叫做实例化过程,具体方式是用类的名字加上函数操作符来调用这个类。

o = object-name()

二、类的定义、创建和使用

2.1、示例:通讯录

在日常生活中,我们会经常使用到通讯录,用来保存朋友的手机号码,此次使用python代码实现通讯录。

创建一个保存电话号码的通讯录的类

  • 确定类的名称
  • 在这个类里面需要保存通讯对象的两个属性,姓名和电话,以及用于更新电话属性的方法
  • 为类提供一个构造函数,用于对属性进行定义并赋值
class AddBook:  # 定义一个名为AddBook的类def __init__(self, name, phone) -> None:  # 初始化方法,接收两个参数:name和phoneself.name = name  # 将传入的name参数赋值给实例变量self.nameself.phone = phone  # 将传入的phone参数赋值给实例变量self.phoneprint("创建地址簿实例 %s" % self.name)  # 打印创建地址簿实例的信息def update_phone(self, phone):  # 定义一个名为update_phone的方法,接收一个参数:phoneself.phone = phone  # 将传入的phone参数赋值给实例变量self.phoneprint("通讯录 {} 's 已更新" % (self.name))  # 打印通讯录已更新的信息

这段代码定义了一个名为AddBook的类,该类具有两个属性:name和phone。其中,name表示通讯录中的名字,phone表示通讯录中的电话号码。

在初始化方法__init__中,传入的参数name和phone被赋值给实例变量self.name和self.phone,并打印出创建地址簿实例的信息。

另外,该类还定义了一个名为update_phone的方法,用于更新通讯录中的电话号码。该方法接收一个参数phone,将其赋值给实例变量self.phone,并打印出通讯录已更新的信息。

通过这个类,我们可以创建一个AddBook对象,并使用其属性和方法来管理通讯录信息。

  • 创建AddBook的两个实例
book = AddBook("张三", "123456789")  # 创建一个名为book的AddBook对象,并传入name和phone参数

在AddBook类的过程中,不需要主动调用_ _ init_ _ ()方法,系统会自动调用 _ _ init _ _()方法,方法中的self参数也是由系统自动传入的,我们需要主动传入的参数是name和phone,它们都不是默认参数。

实例的属性可以通过实例名加“.”再加属性名来进行访问,这种访问方法称为点属性访问法。

  • 显示book的值和它的两个属性的值
print(book)  # 显示实例的值
print(book.name)  # 显示name属性的值
print(book.phone)  # 显示phone属性的值
  • 方法和属性类似,也是通过实例名加“.”再加方法名来进行访问。
book.update_phone("987654321")  # 调用update_phone()方法更新电话号码
print(book.phone)  # 显示更新后的电话号码

创建通讯录完整代码

class AddBook:  # 定义一个名为AddBook的类def __init__(self, name, phone) -> None:  # 初始化方法,接收两个参数:name和phoneself.name = name  # 将传入的name参数赋值给实例变量self.nameself.phone = phone  # 将传入的phone参数赋值给实例变量self.phoneprint("创建地址簿实例 %s" % self.name)  # 打印创建地址簿实例的信息def update_phone(self, phone):  # 定义一个名为update_phone的方法,接收一个参数:phoneself.phone = phone  # 将传入的phone参数赋值给实例变量self.phoneprint("通讯录 {} 's 已更新" % (self.name))  # 打印通讯录已更新的信息
book = AddBook("张三", "123456789")  # 创建一个名为book的AddBook对象,并传入name和phone参数
print(book)  # 显示实例的值
print(book.name)  # 显示name属性的值
print(book.phone)  # 显示phone属性的值

更新通讯录号码完整代码

class AddBook:  # 定义一个名为AddBook的类def __init__(self, name, phone) -> None:  # 初始化方法,接收两个参数:name和phoneself.name = name  # 将传入的name参数赋值给实例变量self.nameself.phone = phone  # 将传入的phone参数赋值给实例变量self.phoneprint("创建地址簿实例 %s" % self.name)  # 打印创建地址簿实例的信息def update_phone(self, phone):  # 定义一个名为update_phone的方法,接收一个参数:phoneself.phone = phone  # 将传入的phone参数赋值给实例变量self.phoneprint("通讯录 {} 's 已更新" % (self.name))  # 打印通讯录已更新的信息
book = AddBook("张三", "123456789")  # 创建一个名为book的AddBook对象,并传入name和phone参数
book.update_phone("987654321")  # 调用update_phone()方法更新电话号码
print(book.phone)  # 显示更新后的电话号码

方法update_phone()有self和phone两个参数,但是这里通过实例名加“.”再加方法名的形式调用update_phone()方法的,所以只需要传入phone这个参数,这种调用方法在python中称为绑定方法。

三、属性与方法

前面提到的类的属性和方法事实上指的是类实例的属性和方法,其它面向对象语言对两者未做太大的区分,通常所说的类的属性与方法事实上都是指实例的属性和方法,而静态属性和静态方法特指类的属性与方法。

由于python对类的声明与定义是同时发生的,并且python是一门动态语言,所以python中的类实例的属性是在程序运行时直接定义的。

3.1、属性

在一个实例被创建出来以后,它的属性值不依赖于任何其它实例,也不依赖于它所属的那个类,它的属性可以在能够访问该实例的代码的任意位置被设置任意次,但对这些属性进行设置的关键性位置之一是构造器_ init ();构造器是能够对实例属性进行设置的最早位置,这是因为 _ init _ _()是实例对象被创建后第一个被调用的方法。

# 定义一个Person类
class Person:# 初始化方法,用于创建对象时设置name和age属性def __init__(self, name, age):self._name = name  # 设置名字属性self._age = age    # 设置年龄属性# 定义一个name属性的getter方法,用于获取名字属性的值@propertydef name(self):return self._name  # 返回名字属性的值# 定义一个age属性的getter方法,用于获取年龄属性的值@propertydef age(self):return self._age  # 返回年龄属性的值# 定义一个age属性的setter方法,用于设置年龄属性的值@age.setterdef age(self, value):if value < 0:  # 如果设置的年龄值小于0raise ValueError("年龄不能为负数")  # 抛出异常,提示年龄不能为负数self._age = value  # 设置年龄属性的值# 创建一个Person对象,名字为张三,年龄为25
p = Person("张三", 25)# 访问name和age属性,分别输出名字和年龄
print(p.name)  # 输出:张三
print(p.age)   # 输出:25# 修改age属性的值,将年龄设置为30
p.age = 30
print(p.age)   # 输出:30# 尝试设置一个无效的年龄值(-5),会抛出异常
try:p.age = -5
except ValueError as e:print(e)  # 输出:年龄不能为负数

在这个示例中,我们定义了一个Person类,其中包含两个私有成员变量_name和_age。我们使用@property装饰器定义了name和age属性,这样我们就可以像访问普通属性一样访问这两个成员变量。同时,我们还定义了一个age属性的setter方法,用于设置年龄值。在setter方法中,我们检查了年龄值是否为负数,如果是负数,则抛出一个ValueError异常。

除了在构造器中设置实例属性外,在实例的任何方法中,以及能够访问该实例的任意位置都可以设置属性。

class A : pass
a = A()
a2 = A()
a2.foo = 100
a.x = 10
a.y = 23
print(a.x + a.y)

在python程序中,可以像定义变量一样定义实例的属性,在代码中a和实例a2虽然都是类A的实例,但是经过a2.foo=100、a.x=10、a.y=23三句代码后,a2具有了foo属性,而a则拥有了x属性和y属性。

python提供vars()函数,以便于查看实例的属性

class A : pass
a = A()
a2 = A()
a2.foo = 100
a.x = 10
a.y = 23
print(a.x + a.y)
print(vars(a2))
print(vars(a))D:\pythonLED\python.exe E:/pythonProject/1.py
33
{'foo': 100}
{'x': 10, 'y': 23}

3.2、方法

方法是在类的定义中定义的函数。

class object:def func(self):passo = object()  
print(o.func())

为了保持OOP传统,python里有规定:方法不能再不通过实例的情况下被调用,想要完成方法的调用,必须拥有一个实例。

与属性类似,方法也可以动态添加。

class object:def func(self):passo = object()
print(o.func())
o.f = lambda x : x ** 2
print(o.f(20))D:\pythonLED\python.exe E:/pythonProject/1.py
None
400

3.3、类的属性

类的属性就是类里面的变量,它们是在创建某个类时设置的,可以在创建了那个类的程序环境里像其他变量一样使用;但修改它们的值却只能在类的内部或主程序部分用方法来进行。

在类定义中定义的变量称为类变量。

class MYclass:version = '1.0'def show_vertsion(self):print(MYclass.version)

上面的代码中可以看到属性version的定义不在任何方法中,这种定义方式的属性就是类属性。

在python中提供了函数dir()来查看类属性,也可以使用前面的vars()来查看类属性及其值。

class MYclass:version = '1.0'def show_vertsion(self):print(MYclass.version)
print(dir(MYclass))
print(vars(MYclass))D:\pythonLED\python.exe E:/pythonProject/1.py
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getstate__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'show_vertsion', 'version']
{'__module__': '__main__', 'version': '1.0', 'show_vertsion': <function MYclass.show_vertsion at 0x000002A1E255A7A0>, '__dict__': <attribute '__dict__' of 'MYclass' objects>, '__weakref__': <attribute '__weakref__' of 'MYclass' objects>, '__doc__': None}

在其它面向对象语言中,类的属性也被称为静态成员、静态数据、类变量等,它只属于对它进行定义的类,并且独立于任何类的实例。

3.4、数类型于实例属性的比较

类属性是指与类相关而不与某个特定的实例相关的数据,即使类经过多次实例化之后,这些数据都会保持不变,除非直接、明确的对它进行了修改。

类属性的访问方法

通过类访问

class MyClass:class_attr = "这是一个类属性"print(MyClass.class_attr)

通过实例直接访问类属性

class MyClass:class_attr = "这是一个类属性"my_instance = MyClass()
print(my_instance.class_attr)

类属性是独立于每个实例的,当类属性的值发生改变时,通过实例访问到的类属性的值都会发生改变;通过实例访问类属性,严格来说只能以只读方式进行;对类属性的改变只能通过类进行,通过实例来改变类属性是不被允许的,那样只会创建出一个同名的实例属性。

赋值操作创建的属性

class MyClass:passmy_instance = MyClass()
my_instance.attr = "这是一个实例属性"
print(my_instance.attr)

对一个实例属性的任何赋值行为都会创建和赋值一个实例属性,即使存在一个同名的类属性,它也会在实例中被覆盖,就像局部变量和全局变量一样。
类属性的特殊性质

由于类属性是独立于每一个实例存在的,因此对类属性的修改会直接影响每一个实例中的类属性。

class MyClass:class_attr = 0  # 类属性def __init__(self, instance_attr):self.instance_attr = instance_attr  # 实例属性# 创建实例
obj1 = MyClass(1)
obj2 = MyClass(2)# 访问类属性
print(MyClass.class_attr)  # 输出:0
print(obj1.class_attr)     # 输出:0
print(obj2.class_attr)     # 输出:0# 修改类属性
MyClass.class_attr = 100
print(MyClass.class_attr)  # 输出:100
print(obj1.class_attr)     # 输出:100
print(obj2.class_attr)     # 输出:100# 通过实例修改类属性
obj1.class_attr = 200
print(MyClass.class_attr)  # 输出:100
print(obj1.class_attr)     # 输出:200
print(obj2.class_attr)     # 输出:100

3.5、类方法

类方法是Python中的一种方法类型,它属于类而不是类的实例,类方法使用@classmethod装饰器进行定义,第一个参数通常是cls,表示类本身。类方法可以通过类名直接调用,也可以通过类的实例调用;类方法主要用于实现与类相关的功能,而不是与实例相关的功能。

class MyClass:@classmethoddef my_class_method(cls):print("这是一个类方法")# 通过类名调用类方法
MyClass.my_class_method()# 通过实例调用类方法
my_instance = MyClass()
my_instance.my_class_method()

3.6、访问权限

在Python中,访问权限是指类或对象的属性和方法的可访问性。Python提供了三种访问权限:公开(public)、受保护(protected)和私有(private)。

  • 公开(public):公开属性和方法可以在类的外部直接访问,不需要使用任何特殊的前缀。
  • 受保护(protected):受保护属性和方法使用一个下划线(_)作为前缀,表示它们不应该在类的外部直接访问,但仍然可以在子类中访问。
  • 私有(private):私有属性和方法使用两个下划线(__)作为前缀,表示它们只能在类的内部访问,不能在类的外部直接访问,也不能在子类中访问。
class MyClass:def __init__(self):self.public_var = "I'm a public variable"self._protected_var = "I'm a protected variable"self.__private_var = "I'm a private variable"def public_method(self):return "I'm a public method"def _protected_method(self):return "I'm a protected method"def __private_method(self):return "I'm a private method"obj = MyClass()
print(obj.public_var)  # 输出:I'm a public variable
print(obj._protected_var)  # 输出:I'm a protected variable
# print(obj.__private_var)  # 报错:AttributeError: 'MyClass' object has no attribute '__private_var'
print(obj.public_method())  # 输出:I'm a public method
print(obj._protected_method())  # 输出:I'm a protected method
# print(obj.__private_method())  # 报错:AttributeError: 'MyClass' object has no attribute '__private_method'

四、继承和多态

继承就是子类继承父类的属性和方法,使得子类对象具有与父类相同的属性、相同的行为。

class Myclass:version = "1.0"
class C(Myclass):pass
print(C.version)

相对而言,在继承中使用更多的则是实例的属性与方法。

class P:def __init__(self,name) -> None:self.name = nameprint("Init in p.")def foo(self):print("This is P-foo().")
class C(P):def foo(self):print("This is C-foo().")p = P("Parent")
c = C("Chind")
print(c.name)D:\pythonLED\python.exe E:/pythonProject/1.py
Init in p.
Init in p.
Chind

在代码中,创建了类P,并定义了一个实例属性name和两个实例方法。类C作为P的子类,虽然没有创建自己的属性和方法,但在实例化类C时,会发现输出了Init in p.,这说明类C调用了父类的方法,并创建了属性name。

虽然类C继承了类P的foo方法,但是由于类C定义了自己的foo方法,所以继承的foo就会被覆盖掉,这样一来,实例p和实例c都拥有foo方法,确实不同的实现,这种现象就是多态,即为不同数据类型的实体提供统一的接口。

class P:def __init__(self,name) -> None:self.name = nameprint("Init in p.")def foo(self):print("This is P-foo().")
class C(P):def foo(self):print("This is C-foo().")p = P("Parent")
c = C("Chind")
print(c.name)
p.foo()
c.foo()D:\pythonLED\python.exe E:/pythonProject/1.py
Init in p.
Init in p.
Chind
This is P-foo().
This is C-foo().

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com