面相对象编程的核心思想是封装,继承和多态。
面向对象三大特征
1.封装根据职责将属性和方法封装到一个抽象的类中。
2.继承实现代码的重用,相同的代码不需要重复的编写。
3.多态不同的对象调用相同的方法,产生不同的执行结果,增加代码的灵活度。
封装
是面向对象编程中的一个重要概念,它指的是将数据和方法封装在一个类中,并对外部隐藏对象的具体实现细节,只暴露必要的接口供外部访问。封装有助于实现数据的安全性、灵活性和可维护性。
1.面相对象编程第一步——将属性和方法封装到一个抽象的类中。
2.外界使用类创建对象,然后让对象调用方法。
3.对象方法的细节都被封装在类的内部。
4.一个对象的属性可以是另外一个类创建的对象
#定义一个名为Person的类。
class Person:
#构造函数__init__,该函数接受两个参数name和age。
#并将它们分别赋值给对象的属性name和age。
def __init__(self,name,age):
#封装数据
self.name = name
self.age = age
#封装方法
#定义了类Person的方法introduce,该方法用于打印对象的姓名和年龄信息。
def introduce(self):
print(f"Hello my name is {self.name} and I am {self.age} years")
##创建了一个名为person1的Person类的实例,传入参数"name"为"xiaoming",参数"age"为21。
person1 = Person("xiaoming",21)
#打印了person1对象的属性name,输出为"xiaoming"
print(person1.name)
#打印了person1对象的属性age,输出为21。
print(person1.age)
#调用了person1对象的方法introduce,输出"Hello my name is xiaoming and I am 21 years"
person1.introduce()
运行结果:
私有属性和私有方法
应用场景
1.在实际开发中,对象的某些属性或方法可能只希望在对象的内部被使用,而不希望在外部被访问到。
2.私有属性就是对象不希望被公开的属性。
3.私有方法就是对象不希望被公开的方法。
定义方式
在定义属性或方法时,在属性名或者方法名前添加两个下划线,定义的就是私有方法或私有属性。
class Car:
def __init__(self, make, model, year):
self.make = make
self.model = model
self.year = year
self.__mileage = 0 # 私有属性
def __update_mileage(self, new_mileage): # 私有方法
self.__mileage = new_mileage
def drive(self, distance):
self.__update_mileage(self.__mileage + distance)
print(f"The car has been driven {distance} miles.")
def get_mileage(self):
return self.__mileage
# 创建Car对象
my_car = Car("Toyota", "Camry", 2020)
# 无法直接访问私有属性和私有方法
# print(my_car.__mileage) # 会报错
# my_car.__update_mileage(500) # 会报错
# 通过公有方法间接访问私有属性和私有方法
my_car.drive(100)
print(f"Mileage: {my_car.get_mileage()}")
运行结果:
上面的示例中,__mileage是一个私有属性,只能在类的内部访问,外部无法直接访问。__update_mileage是一个私有方法,也只能在类的内部调用,外部无法直接调用。通过公有方法drive和get_mileage来间接访问和修改私有属性__mileage。
继承
子类拥有父类的所有属性和方法。
它允许一个类(称为子类)继承另一个类(称为父类)的属性和方法。通过继承,子类可以重用父类的代码,同时可以添加新的属性和方法,或者修改父类已有的属性和方法,以满足子类的特定需求。
1)继承的语法
单继承
class 类名(父类名):
多继承
在括号中写上要继承的所有父类的名称,用逗号隔开即可。
class 类名(父类名,父类名...):
1.子类继承自父类,可以直接享受父类中已经封装好的方法,不需要再次开发。
2.子类中应该根据职责,封装子类特有的属性和方法。
2)专业术语
·Dog类是Animal类的子类,Animal类是Dog类的父类,Dog类从Animal类继承。
·Dog类是Animal类的派生类,Animal类是Dog类的基类,Dog类从Animal类派生。
3)继承的传递性
·C类从B类继承,B类又从A类继承,那么C类就具有B类和A类的所有属性和方法。
·子类拥有父类以及父类的父类中封装的所有属性和方法。
4)方法的重写
·当父类的方法实现不能满足子类需求时,可以对方法进行重写。
重写父类的方法有两种情况:
1.覆盖父类的方法。
(1)如果在开发中,父类的方法实现中包含子类的方法实现,完全不同就可以使用覆盖的方式,在子类中重新编写父类的方法实现。
(2)具体的实现方式,就相当于在子类中定义了一个和父类同名的方法并且实现重写之后,在运行时,只会调用子类重写的方法,而不再会调用父类封装的方法。
2.对父类方法进行扩展。
(1)如果在开发中,子类的方法实现中包含父类的方法实现,父类原本封装的方法实现是子类方法的一部分,就可以使用扩展的方式。
(2)在子类中重写父类的方法,在需要的位置使用super().父类方法
来调用父类方法的执行,代码其他的位置针对子类的需求,编写子类特有的代码实现。
5)关于super
(1)在python
中super
是一个特殊的类。
(2)super()
就是使用super
类创建出来的对象。
(3)最常使用的场景就是在重写父类方法时,调用父类中封装的方法实现。
class Animal: # 定义Animal类
def __init__(self, name, age): # 初始化方法,接受name和age参数
self.name = name # 将name赋值给实例变量self.name
self.age = age # 将age赋值给实例变量self.age
def eat(self): # 定义eat方法
print(f"{self.name} is 进食") # 打印动物名称正在进食
def sleep(self): # 定义sleep方法
print(f"{self.name} is 睡觉") # 打印动物名称正在睡觉
def speak(self): # 定义speak方法
pass # 空的speak方法,没有具体实现
class Lion(Animal): # Lion类继承自Animal类
def __init__(self, name, age, mane_color): # Lion类的初始化方法,接受name、age和mane_color参数
super().__init__(name, age) # 调用父类的初始化方法
self.mane_color = mane_color # 将mane_color赋值给实例变量self.mane_color
def eat(self): # 重写eat方法
print(f"{self.name} 吃肉") # 打印狮子名称正在吃肉
def sleep(self): # 重写sleep方法
print(f"{self.name} 睡大觉") # 打印狮子名称正在睡大觉
def speak(self): # 重写speak方法
print("Roar!") # 打印狮子发出咆哮声
class Tiger(Animal): # Tiger类继承自Animal类
def __init__(self, name, age, stripe_pattern): # Tiger类的初始化方法,接受name、age和stripe_pattern参数
super().__init__(name, age) # 调用父类的初始化方法
self.stripe_pattern = stripe_pattern # 将stripe_pattern赋值给实例变量self.stripe_pattern
def eat(self): # 重写eat方法
print(f"{self.name} 喝水") # 打印老虎名称正在喝水
def sleep(self): # 重写sleep方法
print(f"{self.name} 眨眼睛") # 打印老虎名称正在眨眼睛
def speak(self): # 重写speak方法
print("Growl!") # 打印老虎发出低吼声
lion = Lion("Simba", 5, "golden") # 创建一个狮子实例
tiger = Tiger("Tony", 4, "striped") # 创建一个老虎实例
lion.eat() # 调用狮子的eat方法
lion.sleep() # 调用狮子的sleep方法
lion.speak() # 调用狮子的speak方法
print("--------------") # 打印分隔线
tiger.eat() # 调用老虎的eat方法
tiger.sleep() # 调用老虎的sleep方法
tiger.speak() # 调用老虎的speak方法
运行结果:
这段代码定义了Animal、Lion和Tiger类,分别表示动物、狮子和老虎。每个类都有初始化方法、eat方法、sleep方法和speak方法,其中Lion和Tiger类重写了父类Animal的eat、sleep和speak方法。然后创建了一个狮子实例和一个老虎实例,并调用它们的方法展示各自的行为。
多态
不同的子类对象调用调用相同的父类方法,产生不同的执行结果,多态可以增加代码的灵活度,以继承和重写父类方法为前提,调用方法的技巧,不会影响到类的内部设计。
# 定义了一个Animal类,有一个eat方法,但是没有具体实现,需要在子类中实现
class Animal:
def eat(self):
pass
# 定义了一个Dog类,继承自Animal类,实现了eat方法,打印“Dog is eating”
class Dog(Animal):
def eat(self):
print("Dog is eating")
# 定义了一个Cat类,继承自Animal类,实现了eat方法,打印“Cat is eating”
class Cat(Animal):
def eat(self):
print("Cat is eating")
# 定义了一个Elephant类,继承自Animal类,实现了eat方法,打印“Elephant is eating”
class Elephant(Animal):
def eat(self):
print("Elephant is eating")
# 定义了一个feed_animal函数,接受一个Animal对象作为参数,并调用该对象的eat方法
def feed_animal(animal):
animal.eat()
# 创建了Dog、Cat和Elephant的实例,分别传入feed_animal函数中,实现了多态性的效果
dog = Dog()
cat = Cat()
elephant = Elephant()
feed_animal(dog)
feed_animal(cat)
feed_animal(elephant)
运行结果:
这段代码定义了一个Animal类和它的子类Dog、Cat和Elephant,它们都有eat方法。然后定义了一个feed_animal函数,接受一个Animal对象作为参数,并调用该对象的eat方法。最后创建了Dog、Cat和Elephant的实例,分别传入feed_animal函数中,实现了多态性的效果。