了解面向对象三大特点,在项目中Be a Boss?
众所周知,python是世界上入门最简单的语言!?——周某人
面向对象的三大特点
- 封装:既是对数据结构的封装,又是处理数据的方法的封装。
- 继承:强调的是父子类的关系
- 多态:不同对象调用相同的方法,有不同的响应。
下面将仔细对这三大特点进行详细阐述和实例演示
类的封装
我们在创建类的时候,class里面包裹着类的属性和方法其实就是对类的封装机制(emmmmmm,不知道这样大家能不能理解)
类的继承
-
相关概念:
- 定义:父类的属性和方法,子类可以直接拥有,称为继承。
- 派生:子类在父类的基础上衍生出新的特征(属性或行为),称为派生。
- 总结:其实他们是一回事,知识描述问题的角度不同(继承侧重相同点,派生侧重不同点)
-
继承语法:父类拥有属性和方法的子类都能直接拥有
# 当没有写父类时,默认继承自object class Animal(object): def __init__(self, name): self.name = name def run(self): print('小动物喜欢一天到晚跑个不停') # 定义一个子类,继承自Animal class Dog(Animal): pass d = Dog('旺财') # 可以直接拥有父类的属性 print(d.name) # 也拥有父类的行为 d.run()
-
派生示例:子类可以派生出父类没有的方法和属性
class Animal: def run(self): print('一天到晚跑个不停') class Cat(Animal): def eat(self): print('猫喜欢吃鱼') c = Cat() c.run() # 添加的属性 c.name = '加菲' print(c.name) # 派生的方法 c.eat()
-
方法重写:父类中的方法不适合子类,可以将其覆盖重写
class Animal: def run(self): print('小动物喜欢到处跑') def eat(self): print('小动物喜欢吃东西') class Cat(Animal): # 父类方法完全不合适,覆盖重写 def run(self): print('猫喜欢走猫步') # 父类的方法不够完善,需要添加完善 def eat(self): # 保留父类方法的内容 # Animal.eat(self) # 不建议使用 # super(Cat, self).eat() super().eat() # 推荐使用 # 添加完善的内容 print('猫喜欢吃鱼') c = Cat() c.eat() c.run()
-
多继承:一个类可以有多个父类
class A: def test(self): print('in class A func test...') class B: def test(self): print('in class B func test...') def eat(self): print('in class B func eat ...') class C(A, B): def eat(self): # 默认的方式找父类,跟不重写方法时的顺序是一样的, # 按照书写的先后顺序,默认是写在前面的类的方法 # super().eat() # 明确指定调用哪个父类的方法 B.eat(self) c = C() c.test() c.eat()
类的多态
-
定义:不同的对象,调用相同的方法,会有不同的响应,大概意思就是 “ 猫吃鱼狗吃肉 ” 酱紫
-
具体示例:
class Animal: def run(self): print('小动物走道都不一样') class Cat(Animal): def run(self): print('猫都的是猫步') class Dog(Animal): def run(self): print('狗一般都走S型') def func(obj): obj.run() # 这里的代码,大家动一下脑筋 func(Cat()) func(Dog())
权限管理
-
私有属性/方法:在一个类里面,例如用户类,我们希望我们的密码不能被外部使用或者直接访问,此时我们就可以将该属性设置为私有属性。
-
设置方法:两个下划线开头,声明该属性为私有
-
具体示例:(示例内包含一些重要内容,不知道怎么说,看代码吧)
class Person: def __init__(self, name, age): self.name = name # 定义私有属性 self.__age = age def test(self): # 私有属性和方法可以在类的内部使用 print(self.__age) self.__hello() # 定义私有方法 def __hello(self): print('for test') class Man(Person): def show(self): # 私有属性和方法在子类也不可以使用 print(self.__age) p = Person('老王', 38) print(p.name) # 属性前添加连个下划线,类的外部不能使用 # print(p.__age) # 默认在添加两个下划线的属性名前添加了'_类名' # print(p.dict) # 强烈建议不要这样使用 # print(p._Person__age) p.test() # p.__hello() m = Man('小明', 18) # m.show()
类属性
-
类属性:属于整个类
-
__slots__
:限制对象可以使用的属性,可以提高效率,节约存储空间 -
具体示例:
class Person: # nation = '中国' __slots__ = ('name', 'age', 'nation') def __init__(self, name): # 成员属性,属于某个对象 self.name = name # 成员属性,当不存在会会试着找一下类属性 # self.nation = 'xxx' def test(self): pass # 通过类名访问类属性 # print(Person.nation) p = Person('王大花') # 可以通过对象访问类属性,但是不建议 print(p.name) # print(p.nation) p.age = 20 # p.height = 180 # 特殊的类属性 # 类名字符串 print(Person.__name__) # 父类组成的元组,大家可以尝试让该类继承多个父类,查看输出结果 print(Person.__bases__) # 类相关的信息 print(Person.__dict__) print(Person.__slots__)
类方法
-
说明:
- 通过类名进行调用
- 定义是需要使用装饰器
classmethod
-
作用:
- 可以创建对象或者简洁的创建对象
- 可以对外提供简易的接口
-
示例一:
class Person: # 成员方法,通过对象进行调用 def eat(self): print('红烧鸡腿我喜欢吃') # 类方法,通过类名进行调用 @classmethod def test(cls): # cls表示当前类 print(cls, '类方法') # 创建对象 @classmethod def create(cls): obj = cls() obj.age = 1 return obj p = Person() p.eat() Person.test() # 创建或者简洁的创建对象 p2 = Person.create() print(type(p2))
-
示例二: 计算3^2 + 4^2
class Number: def __init__(self, num1, num2): self.num1 = num1 self.num2 = num2 def add(self): return self.num1 + self.num2 def sub(self): return self.num1 - self.num2 def mul(self): return self.num1 * self.num2 def div(self): if self.num2 == 0: return None return self.num1 / self.num2 # 对外提供简单易用的接口 @classmethod def pingfanghe(cls, num1, num2): n1 = cls(num1, num1) n12 = n1.mul() n2 = cls(num2, num2) n22 = n2.mul() n3 = cls(n12, n22) return n3.add() # 计算3^2 + 4^2 # n1 = Number(3, 3) # n12 = n1.mul() # # n2 = Number(4, 4) # n22 = n2.mul() # # n3 = Number(n12, n22) # ret = n3.add() # print(ret) print(Number.pingfanghe(3, 4))
-
小总结:类方法是一种通过创建自身对象来调用自身方法的特殊方法。(这样说你们晕不晕?)
静态方法
-
说明:
- 通过装饰器
staticmethod
修饰 - 通过类名进行调用
- 通过装饰器
-
示例:
class Person: # 静态方法:没有cls参数 @staticmethod def test(): print('static method test ...') # 静态方法:可以创建对象 @staticmethod def create(): p = Person() p.age = 1 return p Person.test() p = Person.create() print(type(p))
-
小总结:
- 凡是静态方法能够解决的问题类方法都能解决
- 若方法中没有涉及类名的操作,可以使用静态方法代替类方法
属性函数
-
说明:可以将成员方法当作属性一样访问
-
作用:获取时以及设置指定属性时都可以进行人为干预,可以保护特定属性,比如说用户类中的密码
-
示例:
class User: def __init__(self, username, password): self.username = username self.__password = password # 可以将方法像访问属性一样访问 @property def test(self): return 'hello' # 保护指定的属性 @property def password(self): print('大哥,有人想偷看密码') return '哈哈,让你偷看,没门' # 在设置对应属性时会自动调用 @password.setter def password(self, password): print('密码设置', password) # 人为干预密码的设置过程,如:加密存储密码 self.__password = 'xxx' + password + 'yyy' u = User('大狗', '123456') # u.test() # print(u.test) print(u.password) u.password = '654321' print(u.__dict__)
抽象基类(了解)
-
说明:
- 抽象基类就是为了统一接口而存在的
- 抽象类不能进行实例化(创建对象)
- 继承自抽象类的子类必须实现抽象类中的抽象方法
-
示例:
from abc import ABC, abstractmethod # 抽象基类 class Animal(ABC): # 定义抽象方法:规定接口 @abstractmethod def run(self): pass # 抽象基类无法实例化 # a = Animal() class Cat(Animal): # 子类中必须实现抽象基类的抽象方法,才能实例化 def run(self): print('猫喜欢走猫步') c = Cat()
总结
今天的内容超级多,大概花最多两天的时间可以消化,自己根据每个知识点自己想象一些好玩的例子,用代码写出来。还有就是,代码中有很多很多注释掉的代码,需要大家由上至下依次取消注释来运行代码,加深理解。内容比较多,所以很多隐藏知识点都在代码里面呢。
下期预告:下一期篇幅比较短,用来介绍python中的错误和异常处理
Tips:如有疑问欢迎随时打扰 ???