面向对象和私有权限

1. 继承

继承允许一个类继承另一个类的属性和方法(所有方法和属性,魔法方法、类属性和方法、实例属性和方法)

# 所有的类都会继承 object(默认必须继承,可以省略不写)
class ParentClass(object):
    def __init__(self, name):  # 父类有 name 属性
        self.name = name

    def greet(self):  # 父类有 greet 方法
        return f"Hello, {self.name}!"

# 继承 ParentClass 类(也继承 object 类,这里写出来是想说 Python 可以多继承)
class ChildClass(ParentClass, object):
    def __init__(self, name, age):
        super().__init__(name)  # 初始化父类的属性(可以自己初始化,也可以像这里调用父类的构造方法来初始化)
        self.age = age  # 初始化子类的属性

    def greet(self):  # 重写了父类的 greet 方法(父类也有这个方法,子类如果有相同的方法就是重写)
        return f"Hello, {self.name}, you are {self.age} years old!"

child = ChildClass("Bob", 10)
print(child.greet())  # 输出: Hello, Bob, you are 10 years old!

print(type(child))  # 输出 <class '__main__.ChildClass'>
print(isinstance(child, ChildClass))  # child 实例是不是 ChildClass 类型。输出 True
print(isinstance(child, ParentClass))  # # child 实例是不是 ParentClass 类型。输出 True
print(issubclass(ParentClass, ChildClass))  # ParentClass 是不是 ChildClass 的子类。输出 False(反了)
print(issubclass(ParentClass, ParentClass))  # ParentClass 是不是 ParentClass 的子类。输出 True(自己也是自己的子类~~~~)
print(issubclass(ParentClass, object))  # ParentClass 是不是 object 的子类。输出 True

如果子类和自己都有相同的方法(重载:方法名、参数、返回值都相同),调用子类的实例的这个方法时,会调用子类自己的方法

如果子类没有某个方法,但是父类有,调用子类的实例的这个方法时,会调用父类的

私有属性和方法

java 是通过修饰符来区分公开(public)和私有(private)访问修饰符,Python 是以命名来区分的

  • 属性和方法不以下划线开头,普通的属性和方法,外部可以访问,子类可以继承
  • 单下划线开头命名的属性和方法,就是私有属性和方法,这只是一种约定,Python 解释器还是会当做普通属性和方法来对待
  • 双下划线开头命名的属性和方法,就是真正的私有属性和方法,子类不能继承这些属性和方法,外部也不能访问

单下划线 _ 开头

表现就和普通的属性、方法一致,只是一种约定,建议不要直接修改,但只是建议。示例如下:

class Person:

    _name = "Milk"  # 私有属性,雷属性

    def __init__(self):
        self._age = 30  # 私有属性,实例属性

    def _hello(self):  # 私有方法
        print("hello world")


class Student(Person):
    pass


stu = Student()
stu._hello()  # 输出 hello world。私有方法 _fun 可以继承
print(stu._name)  # 输出 Milk。私有类属性可以继承
print(stu._age)  # 输出 10。私有实例属性可以继承

双下划线 __ 开头

上面的例子中把 _ 换成 __,变成真正的私有,只能在类的内部(类定义里面)才能访问。示例如下:

class Person:
    __name = "Milk"  # 私有属性,雷属性

    def __init__(self):
        self.__age = 30  # 私有属性,实例属性

    def __hello(self):  # 私有方法
        print("hello world")


class Student(Person):

    def getage(self):  # 调用会报错,__age 自己没有定义,父类有但是继承不到
        return self.__age


# 子类以及子类的实例不能访问
stu = Student()
stu.getage() 
stu.__hello() 
print(stu._name) 
print(stu._age) 

# 本类以及本类的实例不能访问
person = Person()
print(Person.__name) 
print(person.__name) 
person.__hello() 

底层是因为 Python 解释器会对双下划线的属性和变量重命名来实现的。新的名字会加上 _类名。示例如下:

class Person:
    __name = "Milk"  # 私有属性,雷属性

    def __init__(self):
        self.__age = 30  # 私有属性,实例属性

    def __hello(self):  # 私有方法
        print("hello world")


class Student(Person):
    pass

# 子类的实例都能访问,本类就也可以了
stu = Student()
print(stu._Person__name)  # __name 变为 _Person__name
print(stu._Person__age)  # __age 变为 _Person__age
stu._Person__hello()  # __hello 变为 _Person__hello

上面的例子中通过访问新的名字来访问,但是建议提供专门的普通方法(get_xx()set_xx())来访问。示例如下:

class Person:
    __name = "Milk"  # 私有属性,雷属性

    def __init__(self):
        self.__age = 30  # 私有属性,实例属性

    # 为 __age 提供一组 getter 和 setter
    def get_age(self):
        return self.__age
    def set_age(self, age):
        self.__age = age

class Student(Person):
    pass

stu = Student()
print(stu.get_age())  # 输出 30

2. 多态

多态允许不同类的对象对同一方法做出不同的响应。

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

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

def animal_sound(animal):
    print(animal.speak())

dog = Dog()
cat = Cat()

animal_sound(dog)  # 输出: Woof!
animal_sound(cat)  # 输出: Meow!

3. 封装

封装通过将数据和方法隐藏在类内部,提供公共接口来访问和修改数据。

class MyClass:
    def __init__(self, name):
        self.__name = name  # 私有属性

    def get_name(self):
        return self.__name  # 公共方法访问私有属性

    def set_name(self, name):
        self.__name = name  # 公共方法修改私有属性

obj = MyClass("Alice")
print(obj.get_name())  # 输出: Alice
obj.set_name("Bob")
print(obj.get_name())  # 输出: Bob
posted @ 2025-03-09 19:10  CyrusHuang  阅读(19)  评论(0)    收藏  举报