面向对象和私有权限
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

浙公网安备 33010602011771号