python面向对像
- 一、面向对象的三大特性
- 面向对象包含3大主要特性:
- 封装
- 私有成员
- 继承
- 复写
- pass关键字
- 多态
- 总结
一、面向对象的三大特性
面向对象包含3大主要特性:
-
封装
封装是面向对象编程中的一个重要概念,它指的是将数据(
属性
)和操作数据的方法(方法
)捆绑在一起,以实现数据的隐藏和保护。通过封装,我们可以控制对象内部数据的访问权限,只允许通过对象的接口(方法
)来访问和修改数据,而不直接暴露数据给外部。封装表示的是,将现实世界事物的
属性
、行为
封装到类中,描述为:- 成员变量
- 成员方法
从而完成程序对现实世界事物的描述。
在Python中,封装通常通过定义类来实现。类中的属性可以用于存储数据,而方法可以用于操作这些数据。通过使用访问控制符(例如,在属性名前加上一个下划线“_”),我们可以约定哪些属性和方法是公开的,哪些是私有的,从而实现封装的效果。
下面是一个简单的示例,演示了如何在Python中实现封装:
class Person:def __init__(self, name, age):self._name = name # 受保护属性self._age = age # 受保护属性def get_name(self):return self._namedef set_name(self, name):self._name = namedef get_age(self):return self._agedef set_age(self, age):if age > 0:self._age = age# 创建一个Person对象
person = Person("Alice", 30)# 使用公开的方法访问和修改属性
print(person.get_name()) # 输出:Alice
person.set_age(25)
print(person.get_age()) # 输出:25# 尝试直接访问属性(不推荐)
print(person._name) # 输出:Alice
私有成员
在Python中,以双下划线
__
开头的属性或方法被视为私有成员(private member)。私有成员的存在是为了实现封装,防止外部直接访问和修改类内部的属性或方法。尽管在语法上可以直接访问私有成员,但Python通过名称修饰来对其进行保护。
私有属性通常也被称为私有成员变量。在面向对象编程中,私有属性用来表示只能在类的内部访问或修改的成员变量。这种封装性可以确保类的内部状态不会被外部直接访问或修改,而是通过公共的接口(例如公有方法)来进行操作。
当一个名称以双下划线开头时,Python会自动对这个名称进行变换,将其重命名为 _ClassName__name
的形式,其中 ClassName
是包含私有成员的类名。这种变换使得外部无法直接访问私有成员,而只能通过特定的方式来间接访问。因此,私有属性和私有成员变量通常可以互换使用,它们都指代类的内部状态,只能通过类内部的方法进行访问和修改。
既然现实事物有不公开的属性和行为,那么作为现实事物在程序中映射的类,也应该支持。
定义私有成员的方式非常简单,只需要:
私有成员变量:变量名以__开头(2个下划线)
私有成员方法:方法名以__开头(2个下划线)
即可完成私有成员的设置
class Car:def __init__(self, make, model, year):self.__make = make # 私有属性self.__model = model # 私有属性self.__year = year # 私有属性def get_make(self):return self.__makedef set_make(self, make):self.__make = makedef __update_year(self):self.__year += 1print(f"Year updated to {self.__year}")def increase_year(self):self.__update_year()# 创建一个 Car 实例
my_car = Car("Toyota", "Corolla", 2022)# 尝试访问私有属性(不推荐)
# 这里实际上访问的是名称经过变换后的属性
print(my_car._Car__make) # 输出:Toyota# 使用公开的方法访问和修改私有属性
print(my_car.get_make()) # 输出:Toyota
my_car.set_make("Honda")
print(my_car.get_make()) # 输出:Honda# 尝试调用私有方法(不推荐)
# 这里实际上调用的是名称经过变换后的方法
my_car._Car__update_year() # 输出:Year updated to 2023# 使用公开方法调用私有方法
my_car.increase_year() # 输出:Year updated to 2024
在上面的示例中,__make
、 __model
和 __year
被定义为私有属性,外部无法直接访问。我们使用 get_make
和 set_make
方法来间接访问和修改私有属性。同时,__update_year
被定义为私有方法,外部无法直接调用,但我们通过 increase_year
方法间接调用私有方法来更新年份。
通过这种方式,我们可以保护类的内部数据和行为,确保良好的封装性和安全性。
注意:
1. 私有方法无法直接被类对象使用
2. 私有变量无法赋值,也无法获取值
在面向对象编程中,继承是一种重要的概念,它允许一个类(称为子类)继承另一个类(称为父类)的属性和方法(
不含私有
)。子类可以使用父类的所有公共成员,并且可以根据需要添加自己的属性和方法。这种机制使得代码的复用变得更加容易,并提供了一种层次化的结构来组织和管理类。
在Python中,通过在定义子类时将父类作为参数传递给子类,即可实现继承。子类可以继承父类的属性和方法(不含私有
),并可以添加新的属性和方法,也可以对父类的方法进行重写(覆盖)以改变其行为。
下面举一个简单的示例来说明继承的概念:
# 定义一个父类
class Animal:def __init__(self, name):self.name = namedef make_sound(self):pass# 定义一个子类,继承自 Animal
class Dog(Animal):def make_sound(self):return "Woof!"# 定义另一个子类,也继承自 Animal
class Cat(Animal):def make_sound(self):return "Meow!"# 创建 Dog 对象并调用方法
my_dog = Dog("Buddy")
print(my_dog.name) # 输出:Buddy
print(my_dog.make_sound()) # 输出:Woof!# 创建 Cat 对象并调用方法
my_cat = Cat("Kitty")
print(my_cat.name) # 输出:Kitty
print(my_cat.make_sound()) # 输出:Meow!
在上面的示例中,Animal
类是父类,Dog
和 Cat
类是子类。子类 Dog
和 Cat
继承了父类 Animal
的 name
属性和 make_sound
方法。注意,在子类中可以重写父类的方法,以实现特定于子类的行为。这里的 make_sound
方法在两个子类中被重写,分别返回狗的吠声和猫的喵声。
这样,我们就通过子类继承了父类的属性和方法,并且可以根据需要添加特定于子类的功能,实现了代码的复用和扩展。
当一个类继承自单个父类时,称为单继承;而当一个类同时继承自多个父类时,称为多继承。Python支持多继承,允许一个子类继承自多个父类,从而获得多个父类的属性和方法。
单继承示例:
# 定义一个父类
class Animal:def __init__(self, name):self.name = namedef make_sound(self):pass# 定义一个子类,继承自 Animal
class Dog(Animal):def make_sound(self):return "Woof!"# 创建 Dog 对象并调用方法
my_dog = Dog("Buddy")
print(my_dog.name) # 输出:Buddy
print(my_dog.make_sound()) # 输出:Woof!
在这个单继承示例中,Dog 类继承自 Animal 类,只有一个父类。
多继承示例:
# 定义两个父类
class A:def method_a(self):return "Method A"class B:def method_b(self):return "Method B"# 定义一个子类,同时继承自 A 和 B
class C(A, B):def method_c(self):return "Method C"# 创建 C 对象并调用方法
my_c = C()
print(my_c.method_a()) # 输出:Method A
print(my_c.method_b()) # 输出:Method B
print(my_c.method_c()) # 输出:Method C
在这个多继承示例中,C 类同时继承自 A 和 B 两个父类,可以使用两个父类的方法。需要注意的是,在多继承中可能出现方法名冲突的情况,此时可以通过方法解析顺序(MRO)来确定调用哪个父类的方法。
多继承注意事项
多个父类中,如果有同名的成员,那么默认
以继承顺序(从左到右)为优先级。
即:先继承的保留,后继承的被覆盖
class A:def method(self):return "A"class B:def method(self):return "B"class C(A, B):passc = C()
print(c.method()) # 输出:A
复写
在面向对象编程中,方法的覆盖(Override)或者称为复写(Overwrite),是指子类重新定义(覆盖)了从父类继承而来的方法,使得子类可以提供自己的实现。当子类中定义了一个与父类中同名的方法时,子类中的方法会覆盖父类中的方法,从而改变了原有的方法行为。
复写通常用于子类需要定制特定行为而不是完全继承父类方法的情况。通过复写,子类可以根据自身的需要重写父类的方法,实现多态性和定制化。
子类继承父类的成员属性和成员方法后,如果对其“不满意”,那么可以进行复写。
即:在子类中重新定义同名的属性或方法即可。
以下是一个简单的示例来说明复写的概念:
class Animal:def speak(self):print("Animal speaks")class Dog(Animal):def speak(self):print("Dog barks")class Cat(Animal):def speak(self):print("Cat meows")dog = Dog()
cat = Cat()dog.speak() # 输出:Dog barks
cat.speak() # 输出:Cat meows
在这个示例中,Animal
类定义了一个 speak
方法,而 Dog
和 Cat
类分别继承自 Animal
类并复写了 speak
方法。当调用 speak
方法时,根据对象的类型不同,会执行相应子类中的方法,而不是直接调用父类的方法,实现了方法的覆盖效果。
pass关键字
在 Python 中,pass 是一个空语句,用于在语法上需要语句但程序不需要执行任何操作的情况下进行占位。简单来说,pass 关键字表示什么也不做,只是作为占位符存在,保持语法结构的完整性。
常见的用途包括:
占位: 在代码中暂时不做任何操作,但又需要保持语法结构完整时使用 pass。
占位函数或类: 在定义函数或类时,暂时不添加具体实现,可以使用 pass 作为占位符,避免出现语法错误。
例如:
# 定义一个空函数
def my_function():pass# 定义一个空类
class MyClass:pass# 使用 pass 占位
if condition:pass
else:do_something()
在上述示例中,pass 的作用是确保代码的完整性,即使暂时不需要实现任何功能,也能通过 pass 占位符保持代码的结构正确。
多态性通常与继承和方法覆盖(Override)相结合。当子类覆盖父类中的方法时,可以根据具体的子类对象来调用相应的方法,实现多态性。
多态性的优势包括:
代码复用: 可以通过多态性实现不同类之间共享相同的接口或方法,减少重复代码的编写。
灵活性: 可以根据具体对象的类型来动态调用方法,实现针对不同对象的定制化操作。
简化代码逻辑: 通过多态性可以将一组相关的操作抽象到同一个接口中,使得代码更加清晰易懂。
多态,指的是:多种状态,即完成某个行为时,使用不同的对象会得到不同的状态。
class Animal:def speak(self):print("Animal speaks")class Dog(Animal):def speak(self):print("Dog barks")class Cat(Animal):def speak(self):print("Cat meows")# 多态性的应用
def make_sound(animal):animal.speak()animal = Animal()
dog = Dog()
cat = Cat()make_sound(animal) # 输出:Animal speaks
make_sound(dog) # 输出:Dog barks
make_sound(cat) # 输出:Cat meows
在这个示例中,make_sound
函数接受一个动物对象作为参数,并调用该对象的 speak
方法。根据传入的对象类型不同,会执行相应对象的 speak
方法,实现了多态性。这样,可以通过统一的接口来处理不同类型的对象,提高了代码的灵活性和可维护性。
总结
面向对象编程(OOP)的三大特性是封装、继承和多态。以下是对这三个特性的简要总结:
-
封装(Encapsulation):
- 封装是指将数据和方法(行为)捆绑在一起,以防止外部直接访问对象的内部数据。
- 通过封装,对象的内部细节被隐藏,只暴露必要的接口给外部使用,提高了安全性和代码的可维护性。
- 封装还有助于实现信息隐藏,并且可以通过 getter 和 setter 方法来控制对属性的访问和修改。
-
继承(Inheritance):
- 继承是指一个类(子类)可以获取另一个类(父类)的属性和方法,从而实现代码的重用。
- 子类可以扩展或修改父类的功能,同时可以继承父类的行为,避免重复编写相同的代码。
- 继承有助于建立类之间的层次关系,提高代码的可扩展性和灵活性。
-
多态(Polymorphism):
- 多态是指同一种操作作用于不同的对象上时,可以产生不同的行为。
- 多态性允许不同类的对象对同一个方法做出不同的响应,提高了代码的灵活性和可重用性。
- 多态性通常与继承和方法覆盖(Override)相结合,使得代码可以根据具体对象的类型来动态调用方法,实现针对不同对象的定制化操作。
这三大特性共同构成了面向对象编程的基础,帮助开发人员设计出结构清晰、可维护、可扩展的代码,并提高了代码的重用性和可读性。