Python中的魔力编程:掌握面向对象之道

2023-12-15 21:27:18

Python中的面向对象编程

背景:

? 最近在看一些代码的时候,对类中的一些内置方法不是很懂,因此出一篇文章来细说一下,希望大家看完后对Python中类有一个清楚的认识。

基础铺垫:

? 面向对象的三个特点:封装、继承、多态。面向对象的好处无非就是增加代码的复用性,利于维护和修改,这也是高内聚,低耦合的体现。

  1. 封装
    • 封装是一种将数据(属性)和操作数据的方法(方法)封装在一个单元内的机制。
    • 类的成员变量可以设置为私有,只能通过类的方法来访问和修改。
  2. 继承
    • 继承允许你创建一个新类,该类继承了一个现有类的属性和方法。新类称为子类,原始类称为父类或基类。
    • 子类可以扩展或修改继承的属性和方法,也可以添加新的属性和方法。
  3. 多态
    • 多态性允许不同类的对象对相同的方法名做出不同的响应。这是通过方法的重写和接口的实现来实现的。
类的特性:

Python使用class关键字来定义类,其基本结构如下:

  • class 类名(): #一般类名首字母是大写
        pass
    
内置方法合集(重点):

? 内置方法(也称为魔术方法或双下划线方法),它们具有特殊的含义和用途,为什么你有的时候看不懂一些方法,因为他是固定的,比较便捷,我们只需要对其重写即可。

  1. __init__(self, ...): 这是一个类的构造方法,用于初始化对象的属性。当你创建一个类的新实例时,__init__ 方法会自动调用,进行相关的赋值操作。
  2. __str__(self): 用于返回一个可读的对象字符串表示。当你使用 print 函数打印一个对象时,它会自动调用 __str__ 方法来获取字符串表示,我们一般对其重写。
  3. __repr__(self): 用于返回一个对象的官方字符串表示。通常,它应该返回一个字符串,以用于创建相同对象的副本。
  4. __len__(self): 这用于返回对象的长度。你可以通过内置函数 len() 来获取对象的长度,它会自动调用 __len__ 方法。
  5. __getitem__(self, key): 这用于允许对象像字典或列表一样通过索引或键来访问其元素。它用于实现对象的索引访问。
  6. __setitem__(self, key, value): 用于允许对象像字典或列表一样通过索引或键来设置其元素的值。它用于实现对象的索引赋值。
  7. __delitem__(self, key): 用于允许对象像字典或列表一样通过索引或键来删除其元素。它用于实现对象的索引删除。
class Book:
    # self 是调用者
    def __init__(self, title, author, pages): # Book类内置属性 标题 作者 页数
        self.title = title
        self.author = author
        self.pages = pages

    def __str__(self):
        return f"{self.title} by {self.author}"

    def __repr__(self):
        return f"Book({self.title}, {self.author}, {self.pages})"

    def __len__(self):
        return self.pages

    def __getitem__(self, page_number):
        if page_number >= 1 and page_number <= self.pages:
            return f"Page {page_number} of {self.title}"
        else:
            raise IndexError("Page number out of range")

    def __iter__(self):
        self.current_page = 1 # 封装一个属性
        return self

    def __next__(self):
        if self.current_page <= self.pages:
            result = f"Page {self.current_page} of {self.title}"
            self.current_page += 1
            return result
        else:
            raise StopIteration
# 创建一个Book对象
book = Book("Python Basics", "John Smith", 100) #会自动调用 __init__ 方法

# 使用内置方法
#  打印对象 会自动调用__str__
print(book) # 输出: Python Basics by John Smith 
# 调用__len__ 函数
print(len(book)) #输出 100
# 调用__repr__ 函数
print(repr(book))  # 输出: Book(Python Basics, John Smith, 100)
# __getitem__ 当取某一个元素得时候会自动调用
print(book[1])  # 输出: Page 1 of Python Basics
print(book[50])  # 输出: Page 50 of Python Basics

# # 迭代书的页面
for page in book:
    print(page)

#  第一次调用会执行__iter__函数,然后不断使用__next__ 函数,for page in book:会反复调用 __next__ 方法,每次迭代都会获取下一页的页面信息,直到没有更多的页面可供迭代为止。

在这里插入图片描述

组合:

? 组合指的是,在一个类中以另外一个类的对象作为数据属性,称为类的组合

class Student():
    def __init__(self):
        # 将创建好的手机对象赋值给了phone这个实例变量
        self.phone = Phone('霸王别姬')


class Phone():
    def __init__(self, movie_name):
        self.movie_name = movie_name

    def playMovie(self):
        print('手机正在播放的电影是:', self.movie_name)

s1 = Student()
s1.phone.playMovie()

在这里插入图片描述

继承:

? 通过继承,你可以创建一个新类(子类),它可以继承另一个类(父类或基类)的属性和方法。子类可以扩展或修改父类的功能,并可以添加自己的属性和方法。

  1. 父类和子类
    • 父类是被继承的类,也被称为基类或超类。
    • 子类是继承父类的类,也被称为派生类。
  2. 继承语法
    • 在子类的类定义中,将父类作为子类的参数传递给类定义。
    • 使用 super() 函数可以在子类中调用父类的方法。
class ParentClass:
    def __init__(self, name):
        self.name = name

    def speak(self):
        print(f"{self.name} is speaking.")

class ChildClass(ParentClass):
    def __init__(self, name, age):
        super().__init__(name)  # 调用父类的构造方法
        self.age = age

    def speak(self):
        super().speak()  # 调用父类的方法
        print(f"{self.name} is {self.age} years old and speaking.")

child = ChildClass("Alice", 10)
child.speak()

在这里插入图片描述

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

class ChildClass(ParentClass):
    def __init__(self, name, age):
        # 不显式调用父类的构造方法,Python会自动调用
        self.age = age

child = ChildClass("Alice", 10)
print(child.name)  # 输出: Alice
print(child.age)   # 输出: 10

? 子类 ChildClass 的构造方法没有显式调用 super().__init__(name),但仍然可以正确地初始化 name 属性,因为Python会自动调用父类 ParentClass 的构造方法。但是,如果你在子类的构造方法中想做一些其他特定于子类的初始化工作,你可以显式调用 super().__init__(name) 来确保父类的构造方法也被执行。

多态:
class Animal:
    def speak(self):
        pass

class Dog(Animal):
    def speak(self):
        return "Woof!"

class Cat(Animal):
    def speak(self):
        return "Meow!"

def make_animal_speak(animal):
    return animal.speak()

dog = Dog()
cat = Cat()

print(make_animal_speak(dog))  # 输出: "Woof!" 调用谁得对象,执行who得函数
print(make_animal_speak(cat))  # 输出: "Meow!"

实例变量和类变量:
实例变量:
  • 实例变量指的是实例化对象本身拥有的变量。
  • 通过实例名加圆点的方式调用实例变量 对象.属性
class Student():
    def __init__(self,i_name,i_age):
        #只要定义在init方法内部的变量就是【实例/对象变量】
        self.name = i_name #self.name就是定义的实例变量,name是init方法的参数值
        self.age = i_age #self.age就是定义的实例变量,age就是init方法的参数值

s1 = Student('xxx',21) #调用Student类中的init这个构造方法
s2 = Student('lisi',225)
print(s1.name,s1.age) #访问s1对象的name和age这两个实例变量
print(s2.name,s2.age) #访问s2对象的name和age这两个实例变量
类变量:

? 顾名思义,类和实例化对象公用得属性叫做类变量。定义在类中,方法之外的变量,称作类变量。类变量是所有实例公有的变量,每一个实例都可以访问类变量。

class Student():
    # 定义在方法外部的变量:类变量
    address = 'Beijing'
    classroom = 167

    def __init__(self, i_name, i_age):
        # 只要定义在init方法内部的变量就是【实例/对象变量】
        self.name = i_name
        self.age = i_age


s1 = Student('zhangsan', 20)  # 调用Student类中的init这个构造方法
s2 = Student('lisi', 25)
# 根据对象的引用访问对象的实例变量
print(s1.name, s1.age)  # 访问s1对象的name和age这两个实例变量
print(s2.name, s2.age)  # 访问s2对象的name和age这两个实例变量
print(s1.address, s1.classroom) # 对象访问类变量
print(Student.address,Student.classroom) # 类访问类变量

一句话:类变量是可以被所有的对象公用的

类的方法:

? Python的类中可以包含三种不同类型的方法:实例方法、静态方法和类方法。它们之间的区别主要涉及参数和调用方式,

实例方法
  • 实例方法是最常见的方法类型,在类内部定义时,第一个参数通常是 self,它表示对象自身。
  • 实例方法可以访问和修改对象的属性,因为它们有对当前实例的引用。
class Student():
    classroot = 167 #类变量
    #构造方法
    def __init__(self,name,age):
        #实例变量
        self.name = name
        self.age = age

    #注意:实例方法只可以通过对象调用。
    def study(self,book):
        print('正在学习的书籍是:',book)

s = Student('zhangsan',20) #实例化对象
#只给除了self其他的参数传值
s.study('C++程序设计')
静态方法
  • 静态方法在类内部定义时,使用 @staticmethod 装饰器来标识,它们不需要访问对象的状态,因此没有 self 参数。
  • 静态方法通常用于类级别的操作,而不是实例级别的操作。
class Obj():
    def __init__(self):
        pass

    # 定义一个静态方法
    @staticmethod
    def staticFunc(name):  # 静态方法不需要有任何的必要参数(self)
        print('我是静态方法!,我有一个普通参数:', name)


Obj.staticFunc('帅哥')  # 通过类名调用(推荐)
o = Obj()
o.staticFunc('小帅哥')  # 通过对象名调用(不推荐)

类方法
  • 类方法在类内部定义时,使用 @classmethod 装饰器来标识,它们的第一个参数通常是 cls,它表示类本身。
  • 类方法可以访问和修改类级别的属性,通常用于创建、操作或修改类级别的状态。
class Obj():
    f = 'classVar'  # 类变量

    def __init__(self):
        pass

    @classmethod
    def classFunc(cls):  # 类方法必须要有一个cls的参数,且作为第一个参数
        # cls也不是python的关键字,cls也可以写作其他的形式,比如:xx,self
        print('我是类方法!必要参数cls的值为:', cls)
        print('类变量的值为:', cls.f)  # 类名访问类变量



o = Obj()
o.classFunc()  # 通过对象名访问(不推荐)

Obj.classFunc()  # 通过类名访问(推荐)

在这里插入图片描述

文章来源:https://blog.csdn.net/ak_bingbing/article/details/134936284
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。