【Python面向对象编程】

Python 是一种支持面向对象编程(Object-Oriented Programming, OOP)的语言,可以很容易在Python中创建一个类和对象。

面向对象编程是一种编程范式,它使用"对象"来设计应用和软件。在面向对象的程序中,数据(属性)和功能(方法)被封装在对象中,并通过对象间的交互来实现程序的功能。

一、面向对象的基本特征

  • 类(Class): 用来描述具有相同的属性和方法的对象的集合类是对象的蓝图或模板,它定义了对象的属性和方法
  • 对象:通过类定义的数据结构实例。对象包括两个数据成员(类变量和实例变量)和方法。
    对象是类的实例,具有类定义的属性和方法。
  • 属性(Attribute):属性是对象的数据部分,它存储了对象的状态信息。
  • 方法(Method):方法是对象的行为的定义,即对象可以执行的操作。即类中定义的函数。
  • 类变量:类变量在整个实例化的对象中是公用的。类变量定义在类中且在函数体之外。
    类变量通常不作为实例变量使用。
  • 数据成员:类变量或者实例变量,用于处理类及其实例对象的相关的数据。
  • 方法重写:如果从父类继承的方法不能满足子类的需求,可以对其进行改写,
    这个过程叫方法的覆盖(override),也称为方法的重写。
  • 局部变量:定义在方法中的变量,只作用于当前实例的类。
  • 实例变量:在类的声明中,属性是用变量来表示的。
    这种变量就称为实例变量,是在类声明的内部但是在类的其他成员方法之外声明的。
  • 继承:即一个派生类(derived class)继承基类(base class)的字段和方法。
    继承也允许把一个派生类的对象作为一个基类对象对待。
  • 实例化:创建一个类的实例,类的具体对象。

二、面向对象编程

1、类的使用

注意:需要在单独的文件中定义一个类。

类的一般语法:

python 复制代码
class ClassName:
   '类的帮助信息'   #类文档字符串
   class_suite  #类体(由类成员、方法、数据属性组成)

示例1:

python 复制代码
# 定义一个名为Dog的类 
class Dog:  
    '基类'
    
    dogCount = 0 #类变量

    def __init__(self, name, age):  
        # 初始化方法,当创建类的新实例时自动调用
        self.name = name  # 对象的属性
        self.age = age

        Dog.dogCount += 1
    def bark(self):
        # 类的方法
        print(f"{self.name} says Woof!")

    def totaldogCount(self):  
        # 类的方法
        print("Total Employee %d" % Dog.dogCount)
        

 # 创建类的实例(对象)通过 __init__ 方法接收参数
my_dog = Dog("Buddy", 3)

# 访问对象的属性,使用.来访问属性
print(my_dog.name)  # 输出:Buddy
print(my_dog.age)  # 输出:3

# 调用对象的方法
my_dog.bark()  # 输出:Buddy says Woof!
my_dog.totaldogCount()

运行结果:

python 复制代码
Buddy
3
Buddy says Woof!
Total Employee 1

在这个示例中:定义了一个名为 Dog 的类,它有一个初始化方法 init 和两个方法 bark和totaldogCount。创建了一个 Dog 类的实例 my_dog设置了它的属性 name 和 age访问了 my_dog 的属性并调用了它的方法

  • dogCount 是类变量其值将在这个类的所有实例之间共享。可以在内部类或外部类使用 Dog.dogCount访问。
  • 第一种方法__init__()方法是一种特殊的方法,被称为类的构造函数或初始化方法,当创建了这个类的实例时就会调用该方法。
  • self 代表类的实例self 在定义类的方法时是必须有的,虽然在调用时不必传入相应的参数。

2、内置类属性

当创建一个类后,系统会自动为该类赋予一些内置类属性。这些属性名通常使用双下划线(__)包围,以与普通属性名区分。以下是一些常见的内置类属性:

  • init:类的初始化方法,当创建类的新实例时会自动调用。通常,我们在这里进行属性的初始化操作。__init__的第一个参数总是self,代表创建的实例本身。

  • new:一个静态方法,用于创建对象实例。它相当于构造器,负责对象的创建。__new__的第一个参数是cls,代表类本身。

  • str:一个特殊方法,用于定义当使用print函数或str()函数时对象的字符串表示形式。

  • doc:一个属性,用于存储对象的文档字符串。通过访问对象的__doc__属性,我们可以获取其文档字符串。

  • dict:这个属性可以作用在文件、类或类的对象上,最终返回的结果为一个字典,包含了对象或类的属性。

  • bases : 类的所有父类构成元素(包含了一个由所有父类组成的元组)

  • 还有其他一些内置类属性,如__file__、namemodulebase、__bases__等,它们各自具有特定的用途和含义。

这些内置类属性都是Python语言本身提供的,用于支持面向对象编程的各种特性和功能。

在编写Python代码时,了解这些内置类属性的用法和含义,可以帮助我们更有效地利用Python的面向对象编程特性。

对示例1查看内置类属性:

python 复制代码
print ("Dog.__doc__:", Dog.__doc__)
print ("Dog.__name__:", Dog.__name__)
print( "Dog.__module__:", Dog.__module__)
print ("Dog.__bases__:", Dog.__bases__)
print ("Dog.__dict__:", Dog.__dict__)

运行结果:

python 复制代码
Dog.__doc__: None
Dog.__name__: Dog
Dog.__module__: __main__
Dog.__bases__: (<class 'object'>,)
Dog.__dict__: {'__module__': '__main__', 'dogCount': 1, '__init__': <function Dog.__init__ at 0x00000281DAB9B380>, 'bark': <function Dog.bark at 0x00000281DAB9B420>, 'totaldogCount': <function Dog.totaldogCount at 0x00000281DAB9B4C0>, 'prt': <function Dog.prt at 0x00000281DAB9B560>, '__dict__': <attribute '__dict__' of 'Dog' objects>, '__weakref__': <attribute '__weakref__' of 'Dog' objects>, '__doc__': None}

3、self代表类的实例,而非类

示例2;

python 复制代码
class onetest:
    def prt(self):
        print(self)
        print(self.__class__)


t = onetest()
t.prt()

class twotest:
    def prt(too):
        print(too)
        print(too.__class__)

运行结果:

python 复制代码
<__main__.onetest object at 0x000002A8CA8CF1D0>
<class '__main__.onetest'>
<__main__.twotest object at 0x000002A8CA8CF200>
<class '__main__.twotest'>

这个示例可知,self代表的是类的实例,代表当前对象的地址,而self.__class__则是指向类。self不是关键字,换成其他的too也可以执行。

4、对象销毁(垃圾回收)

Python 使用了引用计数来跟踪和回收垃圾。

在 Python 内部记录着所有使用中的对象各有多少引用。

一个内部跟踪变量,称为一个引用计数器。

当对象被创建时, 就创建了一个引用计数, 当这个对象不再需要时, 也就是说, 这个对象的引用计数变为0 时, 它被垃圾回收。但是回收不是"立即"的, 由解释器在适当的时机,将垃圾对象占用的内存空间回收。

Python 的垃圾收集器是一个引用计数器和一个循环垃圾收集器。

__del__在对象销毁的时候被调用,当对象不再被使用时,__del__方法运行。

示例如下:

python 复制代码
class demo:
    def __init__(self,x=0,y=0,z=0):
        self.x = x
        self.y = y
        self.z = z


    def add(self):
        self.z = self.x + self.y
        print(self.z)
        return self.z


    def __del__(self):
       class_name = self.__class__.__name__
       print(class_name, "销毁")


# 创建类的对象
dem = demo(1,2,5)

#访问对象的属性
print(dem.x,dem.y,dem.z)
#调用对象的函数or方法
dem.add()

# 再次创建类的对象
dem1 = demo()
dem2=dem1
dem3=dem2
print(id(dem1),id(dem2),id(dem3))

运行结果:

python 复制代码
1 2 5
3
1602445688368 1602445688368 1602445688368
demo 销毁
demo 销毁

5、类的继承

类的继承允许创建一个新类(称为子类或派生类),继承自一个或多个已存在的类(称为父类或基类)。通过继承,子类可以自动获得父类的属性和方法,并可以添加或覆盖自己的属性和方法。这提供了一种重用代码和组织代码层次结构的强大机制

示例:

python 复制代码
# 定义一个父类
class Animal:
    def __init__(self, name):
        self.name = name


    def speak(self):
        raise NotImplementedError("Subclass must implement this method")


# 定义一个子类,继承自Animal类
class Dog(Animal):
    def __init__(self, name, breed):
        # 调用父类的初始化方法
        super().__init__(name)

        self.breed = breed

    def speak(self):
        # 实现父类中未实现的方法
        return f"{self.name} barks!"


# 创建一个Dog类的实例
my_dog = Dog("小黄", "Labrador")

# 访问实例的属性
print(my_dog.name)  # 输出: 小黄
print(my_dog.breed)  # 输出: Labrador

# 调用实例的方法
print(my_dog.speak())  # 输出: 小黄 barks!

运行结果:

python 复制代码
小黄
Labrador
小黄 barks!

在示例中,Dog 类继承了 Animal 类。

Dog 类通过调用 super().__init__(name) 来调用父类 Animal 的 init 方法,以初始化从 Animal 继承的属性 name。且Dog 类添加了自己的属性 breed,并实现了 speak 方法。

super() 函数是调用父类方法的一种常见方式。super() 返回一个临时对象,它绑定到父类,并允许调用父类的方法。这种方式特别有用当类继承自多个父类,且需要明确调用特定的父类方法时。

类的继承可以形成复杂的层次结构,一个类可以继承自多个父类(多重继承),但通常应该谨慎使用,以避免复杂的继承和复杂的依赖关系。在Python中,多重继承是允许的,但可能会导致一些难以预料的行为,特别是在处理方法解析顺序(MRO,Method Resolution Order)时。

注意点:
(1) 若子类需要覆盖父类的方法(即使用自己的实现替代父类的实现),可以简单地在子类中定义同名方法。当在子类的实例上调用该方法时,Python 会优先使用子类中的定义

示例:

python 复制代码
class Parent:  # 定义父类
    def myMethod(self):
        print('调用父类方法')


class Child(Parent):  # 定义子类
    def myMethod(self):
        print('调用子类方法')

# 创建子类实例
dem = Child()
dem.myMethod()  # 子类调用重写方法

运行结果:

python 复制代码
调用子类方法

(2) 若父类中的方法不应该被子类直接覆盖,或者需要在子类实现之前执行一些操作,可以在父类中使用 raise NotImplementedError 来抛出一个异常。这样,若子类没有实现该方法,当尝试调用时就会触发异常。

相关推荐
喜欢猪猪2 分钟前
Java技术专家视角解读:SQL优化与批处理在大数据处理中的应用及原理
android·python·adb
海绵波波1073 分钟前
flask后端开发(1):第一个Flask项目
后端·python·flask
林的快手9 分钟前
209.长度最小的子数组
java·数据结构·数据库·python·算法·leetcode
FeboReigns11 分钟前
C++简明教程(10)(初识类)
c语言·开发语言·c++
学前端的小朱12 分钟前
处理字体图标、js、html及其他资源
开发语言·javascript·webpack·html·打包工具
从以前23 分钟前
准备考试:解决大学入学考试问题
数据结构·python·算法
Ven%40 分钟前
如何修改pip全局缓存位置和全局安装包存放路径
人工智能·python·深度学习·缓存·自然语言处理·pip
枫欢41 分钟前
将现有环境192.168.1.100中的svn迁移至新服务器192.168.1.4;
服务器·python·svn
摇光931 小时前
js高阶-async与事件循环
开发语言·javascript·事件循环·宏任务·微任务
沐泽Mu1 小时前
嵌入式学习-QT-Day09
开发语言·qt·学习