15.封装,继承,多态

可以使程序更加灵活.
1.封装
优势:提高了代码的安全性,外部无法直接修改对象内部数据,只能通过接口进行访问和操作
将数据和操作封装成对象,更加模块化和可复用.其他部分代码可以通过调用对象的接口使用.无需关心内部的具体实现.
降低耦合性,对象之间通过接口进行通信,而不是直接访问和修改其内部状态.更灵活金额易于维护.
封装的实现:
封装在类中,公有属性和方法,可以正常访问
私有属性和方法,__双下划表示私有,外部不能直接访问,必须通过接口
受保护的属性和方法: 单下划线,外部可以访问.

class Student:

    def __init__(self, name, age):
        self.__name = name
        self.__age = age

    def introduce(self):
        print(f'我是{self.__name},{self.__age}岁')

    def get_name(self):
        return self.__name

    def get_age(self):
        return self.__age

    def set_name(self, name):
        self.__name = name

    def set_age(self, age):
        self.__age = age


stu = Student('王五', 20)
stu.set_name('李四')
new_name = stu.get_name()
print(new_name)

stu.set_age(25)
new_age = stu.get_age()
print(new_age)

私有实际上变量改了一个名字
2.继承
子类从父类继承属性和方法.
优势:
1.代码重用,避免重复编写代码,提高代码的重用性,
2.代码组织和扩展,继承可以使代码的层次结构更加清晰,子类直接从父类继承,再写特定的.
3.复杂性降低.
class 子类(父类), 单继承 class 子类(父类)多继承
子类可以重写父类的方法,即在子类中重新实现与父类相同的方法

class Singer():

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

    def sing(self):
        print(f'{self.name}正在唱歌')


class Dancer():

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

    def dance(self):
        print(f'{self.name}正在跳舞')


class Person(Singer, Dancer):

    pass

person = Person('张三')
person.sing()
person.dance()

super()用于调用父类的成员,可以在子类中调用父类的成员

class Person(Singer, Dancer):
    
    def __init__(self, name, age):
    	#super().__init__(name)
        #Singer.__init__(self, name)
        super(Singer, self).__init__(name)

mro
方法解析顺序,链
子类.mro()
print(SingerDancer.mro())
继承与自定义异常

class LessEighteenError(ValueError):
    pass


def check_age(age):
    if age < 18:
        raise LessEighteenError('年龄小于18岁,禁止注册')
    else:
        pass
    print('年龄大于等于18岁,可以注册')


try:
    age = input('请输入年龄: ')
    check_age(int(age))
except Exception as e:
    print(e)

多继承实际上是按照mro的顺序进行的,
一般不建议用很复杂的.
mixin 混合
功能要单一,
不要跟真正的基类有关联,mixin的类需要可以和任意类组合
基类要在脱离了mixin的类,也可以单独完成初始化
再mixin的类中不要使用super
3.多态
允许不同的对象对相同的方法做出不同的响应.
同一个方法名可以在不同的类中实现,并且根据对象的类型调用不同类的方法

class Dog:

    def say(self):
        print('汪汪汪')


class Cat:

    def say(self):
        print('喵喵喵')


# animal = Dog()
animal = Cat()
animal.say()

抽象基类,允许定义抽象类和抽象方法,从而可以规范子类的行为,抽象基类并不能被实例化,只能用于继承,子类必须实现抽象基类中定义的所有方法

class Animal:
    def say(self):
        raise NotImplemented


class Dog:

    def say(self):
        print('汪汪汪')


class Cat:
    pass
    # def say(self):
    #      print('喵喵喵')


# animal = Dog()
animal = Cat()
animal.say()

abc模块
from abc import ABCMeta, abstractmethod
(metclass=ABCmeta):
元类创建类的类
使用抽象基类的作用:
规范子类行为,允许定义一组接口或者方法,子类必须实现这些方法
约束方法命名:强制子类必须事先指定的方法,避免方法名拼写错误,或者忘记实现方法的问题.
多态性支持,抽象基类实现了多态性,可以在使用抽象基类的地方接收不同的子类对象,实现更灵活的代码设计
文档化接口: 可以帮助文档化接口,让开发者了解哪些方法是必须实现的,哪些是可选的.

from abc import ABCMeta, abstractmethod

class Animal(metaclass=ABCMeta):
    def say(self):
        raise NotImplemented


@abstractmethod
class Cat:
    pass

animal = Cat()
animal.say()
### 封装继承多态的概念及其用法 #### 1. 封装 封装是一种将数据(属性)和操作数据的方法绑定在一起的机制,同时隐藏对象的内部实现细节[^1]。通过封装,对象的外部只能通过公开的接口与对象交互,而无法直接访问其内部状态。这种设计可以保护对象的数据不被外部代码随意修改。 以下是封装的一个简单示例: ```cpp class Person { private: std::string name; int age; public: // 设置名称 void setName(const std::string& newName) { name = newName; } // 获取名称 std::string getName() const { return name; } // 设置年龄 void setAge(int newAge) { if (newAge > 0 && newAge < 120) { age = newAge; } else { std::cout << "Invalid age!" << std::endl; } } // 获取年龄 int getAge() const { return age; } }; ``` 在这个例子中,`name` 和 `age` 是私有成员变量,不能直接从类外部访问。取而代之的是提供公共方法(如 `setName` 和 `getName`)来间接访问和修改它们[^1]。 #### 2. 继承 继承是面向对象编程中的一个重要特性,允许一个类(子类)继承另一个类(父类)的属性和方法[^2]。通过继承,子类可以重用父类的代码,同时还可以扩展或修改父类的行为。 继承的基本形式如下: - 子类继承父类的所有非私有成员。 - 子类可以添加新的成员或覆盖父类的成员。 - 使用 `super` 或 `this` 关键字可以显式访问父类的成员[^3]。 以下是一个继承的例子: ```cpp class Animal { public: void eat() { std::cout << "This animal is eating." << std::endl; } }; class Dog : public Animal { public: void bark() { std::cout << "The dog is barking." << std::endl; } }; int main() { Dog myDog; myDog.eat(); // 调用从父类继承的方法 myDog.bark(); // 调用子类自己的方法 return 0; } ``` 在这个例子中,`Dog` 类继承了 `Animal` 类的 `eat` 方法,并且还定义了自己的 `bark` 方法[^2]。 #### 3. 多态 多态是指同一个接口可以表示不同的类型或行为的能力。多态的主要作用是解决程序中函数重载的问题,允许将父对象设置为与其一个或多个子对象相等的技术,从而根据当前赋值给它的子对象的特性以不同的方式运作。 多态通常通过虚函数(virtual function)实现。虚函数允许在基类中声明一个函数,并在派生类中重新定义它。当通过基类指针或引用调用虚函数时,实际调用的是派生类中定义的版本。 以下是一个多态的例子: ```cpp class Shape { public: virtual void draw() { std::cout << "Drawing a generic shape." << std::endl; } virtual ~Shape() {} // 虚析构函数确保正确释放内存 }; class Circle : public Shape { public: void draw() override { std::cout << "Drawing a circle." << std::endl; } }; class Rectangle : public Shape { public: void draw() override { std::cout << "Drawing a rectangle." << std::endl; } }; void drawShape(Shape* shape) { shape->draw(); } int main() { Circle circle; Rectangle rectangle; drawShape(&circle); // 输出: Drawing a circle. drawShape(&rectangle); // 输出: Drawing a rectangle. return 0; } ``` 在这个例子中,`Shape` 是一个基类,`Circle` 和 `Rectangle` 是派生类。通过基类指针调用 `draw` 方法时,实际调用的是派生类中定义的版本,这体现了多态的特性。 #### 4. 面向对象编程概念 面向对象编程(OOP)是一种以对象为中心的编程范式,强调将数据和操作数据的逻辑封装在一起。OOP 的核心思想包括封装继承多态,这些特性共同支持代码的可重用性、可扩展性和可维护性[^2]。 封装提供了数据的保护,确保对象的状态只能通过公共接口访问。继承允许类之间的层次结构,促进代码重用和逻辑分类。多态通过共享接口使得不同类型的对象可以被统一处理,增强了程序的灵活性[^1]。 --- ###
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值