封装:将一个对象的数据隐藏在对象内部,不让外接直接访问,而是通过对象提供的方法来访问这些隐藏起来的数据。
面向对象流程——封装:
将属性和方法封装到一个抽象的类中
外界使用类创建对象,然后让对象调用方法
对象方法的细节都被封装在类的内部
封装的意义:
a. 将属性和方法放到一起作为一个整体,然后通过实例化对象来处理
b. 隐藏内部实现细节,只需要和对象及其属性和方法交互即可
c. 对类的属性和方法增加访问权限控制
创建student的封装
class Student:
def __init__(self, mz, nl, cj):
self.name = mz
self.age = nl
self.score = cj
def print_score(self):
print(f'{self.name}的成绩为:{self.score}')
# 使用类创建对象,然后让对象调用方法
s1 = Student('张三', 18, 78)
s1.print_score() # 张三的成绩为:78
s2 = Student('李四', 17, 88)
s2.print_score() # 张三的成绩为:78
私有属性:在python中,实例属性(变量名)如果以__(双下划线)开头,就是一个私有属性
# 私有属性
class Fun:
def __init__(self):
self.__name = '私有属性'
self.data = '实例属性'
def test(self):
print(self.__name)
f = Fun()
print(f.data) # 实例属性
# 私有属性不能再类外面进行访问,只能在类里面进行访问,作用:使得数据更加安全
# print(f.__name) # 报错:AttributeError: 'Fun' object has no attribute '__name'
f.test() # 私有属性
# 可以在类外面获取私有属性的方法:对象名._类名__私有属性名 (了解,不建议使用)
print(f._Fun__name) # 私有属性
私有方法:不能在类的外部调用,外界无法访问私有方法,但可以在类内部调用私有方法
# 私有方法
class Fun:
def __init__(self):
self.__name = '私有属性'
self.data = '实例属性'
def __inner(self):
print('这是一个私有实例方法')
def test(self):
print(self.__name)
print('这是一个实例方法')
# 访问私有方法:self.私有实例方法
self.__inner()
f = Fun()
f.test() # 私有属性\n 这是一个实例方法\n 这是一个私有实例方法
# f.__inner() # 报错:AttributeError: 'Fun' object has no attribute '__inner'
# 私有方法不能在类外面进行访问,可在类里面进行访问
# 可以在类外面获取私有属性的方法:对象名._类名__私有属性名 (了解,不建议使用)
print(f._Fun__name) # 私有属性
f._Fun__inner() #这是一个私有实例方法
提示: ① _xx :单下划线开头,声明私有属性/方法,类对象和子类可以访问
② __xx :双下划线开头哦,私有属性,无法在外部直接访问
③ __xx__ :魔法方法(eg: __init__ ,__del__)
④ xx__:用于避免与python关键字的冲突
继承:子类拥有父类的所有属性和方法。继承必定发生在两个类之间,参与继承关系的双方成为的是父类和子类;类的继承是指新类从已有的类中取得已有的特性(eg: 属性、变量、方法等)
继承的优点:
a. 增加类的耦合性(耦合性不宜多,宜精)
b. 减少了重复代码
c. 使得代码更加规范化、合理化
单继承:一个子类继承一个父类。注意:子类不能继承父类的私有属性和方法
# 父类:动物类
class Animal:
def eat(self):
print('eat')
def drink(self):
print('drink')
# 子类:狗类
class Dog(Animal):
def sleep(self):
print('sleep')
dog = Dog()
dog.eat() # eat
dog.drink() # drink
dog.sleep() # sleep
重写:当子类在使用父类中的方法时,如果发现父类中的方法不符合子类的需求,可以对父类中的方法进行重写,这个过程称为方法的覆盖也成为方法的重写
扩展:对父类方法进行扩展的实现方式:
父类名.方法名(self)
super().方法名()
# 重写和扩展
# 父类:动物
class Animal:
def eat(self):
print('eat')
def drink(self):
print('drink')
# 子类:狗类
class Dog(Animal):
# 重写——在子类中对父类中的方法进行重新定义
def eat(self):
print('啃骨头')
def drink(self):
# 扩展1:父类名.方法名(self)
Animal.drink(self)
print('喝水')
# 扩展2:super().方法名()
super().drink()
dog = Dog()
dog.eat() # 啃骨头
dog.drink() # drink\n 喝水\n drink
多继承:指一个子类可以同时继承多个父类,在实现多继承定义时,在定义子类时需要继承父类括号中以“ , ”分隔多个父类。
子类调用父类中同名的属性或方法:再多继承中,如果继承的父类中有相同的方法名,那么调用先继承的类中的同名方法。
多继承方法的搜索顺序:多是从左往右搜索的去,调用方法时执行先搜到的方法。
__mro__:在调用方法时,会对当前类以及所有的基类进行搜索,来查找方法所在。
通过使用 __mro__ 来查看搜索的顺序(print(类名.__mro__))
扩展:父类名.方法名(self) 和 super().方法名()
# 父亲类
class Father:
def eye(self):
print('双眼皮')
def pro(self):
print('c++')
# 母亲类
class Mother:
def face(self):
print('鹅蛋脸')
def pro(self):
print('java')
# 儿子类 —— 继承父亲类、母亲类
#class Son(Father, Mother):
# pass
#s = Son()
#s.eye() # 双眼皮
#s.face() # 鹅蛋脸
#s.pro() # c++
#print(Son.__mro__) # 查看基类调用顺序 (<class '__main__.Son'>, <class '__main__.Father'>, <class '__main__.Mother'>, <class 'object'>)
# 重写儿子类
class Son(Father, Mother):
def pro(self):
print('python')
# 父类名.方法名(self)
Father.pro(self)
Mother.pro(self)
# super().方法名() —— 扩展的是第一个匹配的父类中的方法
super().pro()
s = Son()
s.eye() # 双眼皮
s.face() # 鹅蛋脸
s.pro() # python\n c++\n java\n c++
print(Son.__mro__)
多态:指一类事物有多种形态。多态是一种使用对象的方式,子类重写父类方法,调用不同子类对象的相同父类方法,可以产生不同的执行结果。
实现步骤:
定义父类,并提供公共方法
定义子类,并重写父类方法
传递子类对象给调用者,可以看到不同子类执行效果不同
优点:在定义类方法时,有了多态更容易编写出通用的代码,作出通用的编程以适应需求不断变化。
class Animal:
def talk(self): # 公共方法
print('Animal is talking')
class People(Animal): # 动物的第一种形态:人
def talk(self):
print('普通话')
class Dog(Animal): # 动物的第二种形态:狗
def talk(self):
print('汪汪汪')
class Cat(Animal): # 动物的第三种形态:猫
def talk(self):
print('喵喵喵')
p = People()
d = Dog()
c = Cat()
p.talk() # 普通话
d.talk() # 汪汪汪
c.talk() # 喵喵喵
类方法:在定义类方法时,要使用@classmethod进行修饰,并且必须有默认参数“cls”,通过它可以传递类的属性和方法(不能传递实例的属性和方法)
类方法可以通过对象进行调用,也可以通过类名进行调用。
类方法的使用场景:
当方法中需要使用类对象(如访问私有类属性等)时,定义类方法
类方法一般和类属性配合使用,可以直接对类属性进行修改
静态方法:定义时,要使用@staticmethod进行修饰。参数随意,没有“self”和“cls”参数,但是方法体中不能使用类或实例的任何属性和方法
可通过对象进行调用,也可以通过类名进行调用。
使用场景:当方法中既不需要使用实例对象(eg: 实例对象、实例属性),也不需要使用类对象(eg: 类属性、类方法、创建实例等)时,定义静态方法。
class Test:
__name = '私有类属性'
def funa(self): # 实例方法
print(self) # self -> 对象
print('这是一个实例方法')
self.__name = 'hahahaha'
print(self.__name)
@classmethod
def funb(cls): # 类方法
print(cls) # cls -> 类
print('这是一个类方法')
cls.__name = '重新赋值'
print(cls.__name)
@staticmethod
def func(): # 静态方法
print('这是一个静态方法')
t = Test()
print(t) # <__main__.Test object at 0x0000021ABF55B7F0>
t.funa() # # <__main__.Test object at 0x000002761BB03580>\n 这是一个实例方法\n hahahaha
print(Test) # <class '__main__.Test'>
t.funb() # <class '__main__.Test'>\n 这是一个类方法\n 重新赋值
print(t._Test__name) # hahahaha
t.func() # 这是一个静态方法
小结:
定义类:class
定义方法:def
属性:
类属性: 定义在类中,该属性属于类
__类属性: 私有类属性
实例(对象)属性: 在实例方法中,通过self进行定义的,该属性属于对象
__实例(对象)属性: 私有实例(对象)属性
方法:
实例方法:self ,只能够通过对象、self进行调用
类方法: cls ,可通过对象、类、cls进行调用 , @classmethod
静态方法: 无 ,可通过对象、类进行调用 , @staticmethod
__类方法: 私有类方法
__实例(对象)方法: 私有实例(对象)方法