Python面向对象编程实战指南

面向对象编程(OOP)

一.类与实例

1.类:

是对现实世界描述的一种类型,是抽象的,是实例的模板,类名采用大驼峰,定义方式为 `class 类名: pass 。

2.实例

根据类创建的具体对象,通过类名加括号(类名())创建。实例是具体的,内容依赖于类

3.self

在类的方法中,self 代表调用该方法的实例本身,在类内来代表未来的实例。通过 self 可以访问实例的属性和其他方法。

二.初始化函数 __init__

这是类的特殊方法,通过初始化 self 来初始化未来的实例,向 self 中添加数据就是向实例中添加数据。

运行结果:

三.魔法函数(特殊方法)

这些方法允许对象进行特定的操作,如字符串表示(__str__)、长度计算(__len__)、比较(__eq____ne__ 等)和算术运算(__add____sub__ 等)。


class MyClass:
    def __init__(self, name, age):
        print(f"初始化函数执行了")
        self.name = name
        self.age = age

    def __str__(self):
        return f"醒醒了:{self.name}"

    def __len__(self):
        return len(self.name)

    def __eq__(self, other):
        return self.age == other.age

    def __ne__(self, other):
        return self.age != other.age

    def __gt__(self, other):
        return self.age > other.age

    def __ge__(self, other):
        return self.age >= other.age

    def __lt__(self, other):
        return self.age < other.age

    def __le__(self, other):
        return self.age <= other.age

    def __add__(self, other):
        return self.age + other.age

    def __sub__(self, other):
        return self.age - other.age

    def __mul__(self, other):
        return self.age * other.age

    def __divmod__(self, other):
        return divmod(self.age, other.age)

    def __mod__(self, other):
        return self.age % other.age

    def __truediv__(self, other):
        return self.age / other.age

    def __floordiv__(self, other):
        return self.age // other.age


mc = MyClass("张飞", 18)
print(mc)
print(len(mc))

mc2 = MyClass("孙尚香", 18)
print(mc == mc2, mc != mc2, mc > mc2, mc >= mc2, mc < mc2, mc <= mc2)

print(mc + mc2, mc - mc2, mc * mc2, mc % mc2, divmod(mc, mc2), mc / mc2, mc // mc2)

运行结果:

四.构造函数与析构函数

  • 构造函数:用于创建实例(`self`)并返回实例,可通过父类来创建实例super().__new__() 。
  • 析构函数__del__ 方法在对象被销毁时调用,用于执行清理工作。实例不再使用,销毁之前执行。
  • 运行结果:

    五.三大特性

    封装

    包括数据(如名字、年纪)及数据相关的操作(如获取名字、设置名字、获取年纪、设置年纪)。

    """
    Light:  灯
    数据 state
    操作 is_open change_state
    """
    
    
    class Light:
        def __init__(self):
            self.state = False  # 初始灯的状态为关闭
            self.colors = ["红色", "绿色", "蓝色"]  # 定义了三种颜色:红色、绿色、蓝色
            self.current = 0  # 初始颜色索引为0,即红色
    
        def is_open(self):
            return self.state  # 返回当前灯的状态,True 表示开启,False 表示关闭
    
        def change_state(self):
            self.state = not self.state  # 切换灯的状态,如果是开启就关闭,如果是关闭就开启
    
        def get_color(self):
            return self.colors[self.current]  # 返回当前灯的颜色
    
        def set_color(self):
            self.current += 1  # 切换到下一个颜色
            if self.current == len(self.colors):  # 如果颜色索引超过了颜色列表长度
                self.current = 0  # 则重新回到第一个颜色
    
    
    # 示例用法
    l0 = Light()
    # 初始状态
    print(l0.is_open())  # 输出: False,灯是关闭的
    print("======================")
    # 切换状态
    l0.change_state()
    print(l0.is_open())  # 输出: True,灯现在是开启的
    print("======================")
    # 再次切换状态
    l0.change_state()
    print(l0.is_open())  # 输出: False,灯又关闭了
    print(l0.get_color())  # 输出: 红色,因为当前颜色索引是0
    print("======================")
    # 切换颜色
    l0.set_color()
    print(l0.get_color())  # 输出: 绿色,因为当前颜色索引现在是1
    print("======================")
    l0.set_color()
    print(l0.get_color())  # 输出: 蓝色,因为当前颜色索引现在是2
    print("======================")
    l0.set_color()
    print(l0.get_color())  # 输出: 红色,因为当前颜色索引超过了列表长度,重新回到0
    print("======================")
    l0.set_color()
    print(l0.get_color())  # 输出: 绿色,依次循环显示颜色
    
    
    

    运行结果:

    继承

    子类拥有父类的数据以及操作,子类不需要重新编写。Python 支持多继承,而 Java、C# 只支持单继承,通过接口等来实现多继承的功能。

    多继承:

    class MoveAble:
        def __init__(self, speed):
            self.speed = speed
    
        def move(self):
            print(f"I can move, my speed is {self.speed}m/s")
    
        def __str__(self):
            return "我是移动类"
    
    
    class SpeakAble:
        def __init__(self, language):
            self.language = language
    
        def speak(self):
            print(f"I can speak {self.language}")
    
        def __str__(self):
            return "我是说话类"
    
    
    class AttackAble:
        def __init__(self, skill):
            self.skill = skill
    
        def attack(self):
            print(f"使用{self.skill}发起攻击")
    
        def __str__(self):
            return "我是攻击类"
    
    
    class Person(MoveAble, SpeakAble):
        def __init__(self, name, speed, language):
            # super().__init__()  会执行第一个父类
            # super().__init__(speed)
    
            # 通过类名表名 需要初始化哪个父类  必须传入self
            MoveAble.__init__(self, speed)
            SpeakAble.__init__(self, language)
    
            self.name = name
    
        def show(self):
            print(f"my name is {self.name}")
    
        def __str__(self):
            return "我是人类"
    
    
    p0 = Person("小张", 50, "汉语")
    p0.show()
    p0.move()
    p0.speak()
    

    多态

    Python 中可以理解到处都是多态,有两种形式,一是函数同名不同参数,通过 `*args` 实现;二是父子类多态,函数名参数都相同,但实现不同。

    运行结果:

    六.抽象类
  • 是特殊的类,内部可编写抽象方法,不能直接实例化,也可编写普通实例方法。子类继承抽象类必须实现抽象类的抽象方法
  • """
    抽象类:不直接实例化, 通过子类来产生实例
    """
    from abc import ABC, abstractmethod
    
    
    class Animal(ABC):
        """
        抽象类:拥有抽象方法 不能直接实例化
        通过装饰器abstractmethod把 walk 变为抽象方法
        """
        @abstractmethod
        def walk(self):
            pass
    
        def eat(self):
            print(f"可以吃")
    
    
    # a0 = Animal()
    # print(a0, isinstance(a0, Animal))
    
    class Dog(Animal):
        """
        抽象类子类: 必须实现抽象类中的抽象方法
        """
        def walk(self):
            print(f"摇摇尾巴")
    
    
    dog = Dog()
    dog.eat()   # 调用继承自 Animal 的 eat() 方法
    print(isinstance(dog, Dog), isinstance(dog, Animal))  # 检查实例的类型
    
    
    class Cat(Animal):
        def walk(self):
            print(f"跳来跳去")
    
    
    cat = Cat()
    cat.eat()   # 调用继承自 Animal 的 eat() 方法
    print(isinstance(cat, Cat), isinstance(cat, Animal))  # 检查实例的类型
    
    七.类中内容
  • 实例属性:向实例中添加的数据,类内通过 self,类外通过实例。
  • 实例方法:第一个形参是 self,类内通过 self,类外通过实例
  • 类属性:向类中添加数据,获取与设置直接通过类名,通过实例获取不推荐,实例不能设置类属性。
  • 类方法:第一个形参一般是 cls,带有装饰器 classmethod,目的是获取类相关信息,实例可以获取类方法但不推荐。
  • 静态方法:没有特殊形参,带有装饰器 staticmethod,通过类名调用,实例可以访问但不推荐,项目的辅助类一般使用静态方法。
  • class Person:
        MAX_ACE = 100  # 类属性,最大值
        MIN_ACE = 0    # 类属性,最小值
    
        @classmethod
        def from_birth_year(cls, name, birth_year):
            current_year = 2024  # 假设当前年份是 2024
            age = current_year - birth_year
            return cls(name, age)  # 返回一个新的 Person 实例
    
        @staticmethod
        def is_adult(age):
            return age > 18  # 静态方法,判断是否成年
    
        def __init__(self, name, age):
            self.name = name  # 实例属性,姓名
            self.age = age    # 实例属性,年龄
    
        def __str__(self):
            return f"名字:{self.name}, 年龄:{self.age}"  # 返回对象描述的字符串
    
    
        def set_name(self, name):
            self.name = name  # 设置姓名的实例方法
    
        def get_name(self):
            return self.name  # 获取姓名的实例方法
    
    
    # 创建一个 Person 对象
    p0 = Person("张飞", 20)
    # 输出对象的 name 和 age 属性
    print(p0.name, p0.age)  # 输出: 张飞 20
    # 使用 __str__ 方法打印对象的字符串表示
    print(p0)  # 输出: 名字:张飞, 年龄:20
    # 使用 set_name 方法修改 name 属性
    p0.set_name("关羽")
    # 再次打印对象的字符串表示和获取名字
    print(p0, p0.get_name())  # 输出: 名字:关羽, 年龄:20
    
    # 访问类属性
    print(Person.MAX_ACE)  # 输出: 100
    print(Person.MIN_ACE)  # 输出: 0
    
    # 修改类属性
    Person.MIN_ACE = 10
    print(Person.MIN_ACE)  # 输出: 10
    
    # 通过实例访问类属性(不推荐这样做)
    print(p0.MIN_ACE, p0.MAX_ACE)  # 输出: 10 100
    
    # 尝试通过实例修改类属性(这不会修改类的属性,而是创建了一个实例属性)
    p0.MAX_ACE = 200
    print(Person.MIN_ACE, p0.MAX_ACE)  # 输出: 10 200
    
    # 使用类方法创建 Person 对象
    p2 = Person.from_birth_year("关羽", 1990)
    print(p2)  # 输出: 名字:关羽, 年龄:34
    
    # 使用静态方法判断年龄是否成年
    print(Person.is_adult(20))  # 输出: True
    print(Person.is_adult(15))  # 输出: False
    
    
    
    八.动态添加内容

    Python 的动态性允许在运行时向类中添加新的属性、方法等。

    import types
    
    
    class Person:
        pass
    
    
    # # 在实例上添加属性  向实例中添加实例数据  其他实例无影响
    p0 = Person()
    p = Person()
    p.name = "赵云"
    print(p.name)
    
    
    # 添加实例方法  # 向实例中添加实例数据 其他实例无影响
    def my_set_name(self, name):
        self.name = name
    
    
    p.set_name = types.MethodType(my_set_name, p)
    p.set_name("关羽")
    print(p.name)
    # 向类中添加类属性  类可以正常访问 所有实例均可访问
    Person.MAX_AGE = 120
    print(Person.MAX_AGE, p.MAX_AGE, p0.MAX_AGE)
    
    
    @classmethod
    def my_info(cls):
        print(cls.__bases__)
    
    
    # 向类中添加类方法  方法格式符合类方法格式  类与所有实例均可访问
    Person.info = my_info
    Person.info()
    p0.info()
    p.info()
    
    
    @staticmethod
    def my_max(x, y):
        return x if x > y else y
    
    
    #  向类中添加静态方法  方法要符合静态方法格式  类与实例均可访问
    Person.max = my_max
    
    print(Person.max(10, 20), p.max(50, 100), p0.max(200, 500))
    
    
    
    九.数据的访问级别
  • 公有:普通名字,类内、类外、子类都可以使用。。
  • 私有:以双下划线 __ 开头的属性或方法,在类外部不能直接访问,但可以通过类的公有方法间接访问。
  • 保护(Python 中不严格区分):以单下划线 _ 开头的属性或方法,遵在类内可以访问,在子类可以访问,在类外可强制访问。
  • """
    数据的访问级别
    	公有类型
    		public
    		普通名字
    		类内和类外,子类都可以使用
    	私有类型
    		private
    		以_ _开头
    		只能在类内访问
    	保护类型
    		protect
    		在类内可以访问
    		在子类中可以访问
    		在类外可以强制访问
    """
    
    
    class Person:
        def __init__(self, name, age, sex):
            self.name = name
            self.__age = age
            self._sex = sex
    
        def _set_sex(self, sex):
            self._sex = sex
    
        def _get_sex(self):
            return self._sex
    
        def __set_age(self, age):
            self.__age = age
    
        def __get_age(self):
            return self.__age
    
        def get_name(self):
            return self.name
    
        def set_name(self, name):
            self.name = name
    
        def __str__(self):
            return f"name:{self.name},age:{self.__age},sex:{self._sex}"
    
    
    # 公有
    p0 = Person("张飞", 20, "男")  # 私有只能在类内访问 age
    print(p0)
    p0.set_name("张菲菲")
    print(p0.name, p0.get_name())
    # 保护
    p0._set_sex("女")
    print(p0._get_sex())
    十.属性封装与 property
  • 口头称呼:类封装数据与操作,属性与行为,包括类属性、实例属性、公有属性、私有属性、保护属性。
  • property :包括 fget(获取触发,@property)和 fset(设置触发,@属性名.setter)装饰器。
  • class Person:
        def __init__(self, name, age, sex, height):
            self.__name = name
            self.age = age
            self.__sex = sex
            self.__height = height
    
        @property
        def height(self):
            return self.__height
    
        @height.setter
        def height(self, height):
            self.__height = height
    
        def __get_sex(self):
            return self.__sex
    
        def __set_sex(self, sex):
            if sex in ["男", "女"]:
                self.__sex = sex
            else:
                print("设置失败")
    
        # 封装真正的属性
        sex = property(__get_sex, __set_sex)
    
        def get_name(self):
            return self.__name
    
        def set_name(self, name):
            if 2 <= len(name) <= 4:
                self.__name = name
            else:
                print("设置失败")
    
    
    p = Person("张飞", 20, "男", 190)
    
    # 获取 设置age 直接使用 (容易产生不合法数据)
    print(p.age)
    p.age = -30
    print(p.age)
    print("=============================")
    # 获取设置name 需要通过函数  数据安全
    print(p.get_name())
    p.set_name("赵云")
    print(p.get_name())
    print("=============================")
    # 使用 property 获取和设置 sex
    print(p.sex)
    p.sex = "其他"
    print(p.sex)
    print("=============================")
    print(p.height)
    p.height = 200
    print(p.height)
    
    
    
    十一.单例模式
  • 只有一个实例,通过控制构造函数判定是否需要重新生成实例,第一次生成后放入类属性,以后返回第一次生成的实例。
  • class Person:
        pass
    
    
    # 每次调用类都可以生成一个新的实例
    p1 = Person()
    p2 = Person()
    p3 = Person()
    
    print(p1 is p2, p2 is p3, p3 is p1)
    
    
    class Manage(object):
        instance = None
    
        def __new__(cls, *args, **kwargs):
            """
            对构造函数进行控制 不是每次都生成新的实例
            1. 对类属性instance判断 如果为空 就构造一个实例 并且把实例赋予instance
            2. 对类属性instance判断 如果不为空 则直接把他返回
            """
            if not Manage.instance:
                Manage.instance = super().__new__(cls)
            return Manage.instance
    
        def __init__(self):
            """初始化函数 初始化实例 向self中添加内容"""
            print(f"初始化函数执行了")
    
    
    m1 = Manage()
    m2 = Manage()
    print(m1 is m2, m1 is None, m2 is None)
    
    
    class BaseManage:
        def __new__(cls, *args, **kwargs):
            if not hasattr(BaseManage, "instance"):
                obj = super().__new__(cls)
                setattr(BaseManage, "instance", obj)
    
            return getattr(BaseManage, "instance")
    
    
    m1 = BaseManage()
    m2 = BaseManage()
    print(m1 is m2)
    
    
    class SystemManage(BaseManage):
        pass
    
    
    sm1 = SystemManage()
    sm2 = SystemManage()
    print(sm1 is sm2)
    print(isinstance(sm1, SystemManage), isinstance(sm1, BaseManage))
    
    
    
    

     

    作者:钟离紫轩工程师

    物联沃分享整理
    物联沃-IOTWORD物联网 » Python面向对象编程实战指南

    发表回复