面向对象之封装,多态
什么是封装?
封装(从字面意思理解)就是隐藏,隐藏指的是在类内部将一个属性藏起来
让类外部的使用者无法直接用到。在py中就是用__开头将一个属性藏起来.
补充说明:封装绝对不是单纯意义的隐藏
需知定义属性的目的就是为了让使用者去用,使用者要想使用类内部隐藏的属性
需要类的设计者在类内部开一个接口(定义一个方法),在该方法内访问隐藏的属性
,使用者以后就通过该方法来“间接地”访问内部隐藏的属性
作为类的设计者可以在接口之上附加任意逻辑从而严格控制类的使用者对属性的操作
class People: def __init__(self,name): self.__name=name def tell_name(self): # 添加逻辑,可以添加任意判断逻辑 return self.__name obj=People('egon') #obj.__name obj.tell_name()
封装函数属性:隔离复杂度 class ATM: def __card(self): print('插卡') def __auth(self): print('用户认证') def __input(self): print('输入取款金额') def __print_bill(self): print('打印账单') def __take_money(self): print('取款') def withdraw(self): #可以变得更加清晰,统一的接口。 self.__card() self.__auth() self.__input() self.__print_bill() self.__take_money()
封装之property
class People: def __init__(self,name,weight,height): self.name=name self.weight=weight self.height=height @property def bmi(self): return self.weight / (self.height * self.height) # 首先需要明确。bmi是算出来的,不是一个固定死的值,也就说我们必须编写一个功能,每次调用该功能 #都会立即计算一个值 egon=People('egon',75,1.80) yl=People('yangli',85,1.74) # 但很明显人的bmi值听起来更像一个名词而非动词 # print(egon.bmi()) # print(yl.bmi()) # 于是我们需要为bmi这个函数添加装饰器,将其伪装成一个数据属性 # egon.weight=70 # print(egon.bmi) #21.604938271604937,调用egon.bmi本质就是触发函数bmi的执行,从而拿到其返回值 # print(yl.bmi) #这样就不用加括号直接使用
# egon.bmi=123 # egon.bmi背后对应的是一个函数,所以不能赋值
了解 class People: def __init__(self,name): self.__name=name @property def name(self): #obj.name print('您现在访问的是用户名。。。') return self.__name @name.setter #obj.name='EGON' #setter可以改封装的函数属性值 def name(self,x): # print('=================',x) if type(x) is not str: raise TypeError('名字必须是str类型,傻叉') self.__name=x @name.deleter #deleter删除封装的函数属性 def name(self): # print('就不让你删') del self.__name obj=People('egon')
多态
1 什么是多态
多态指的是同一种事物多种形态
2、为什要用多态
用基类创建一套统一的规则,强制子类去遵循(使用抽象类实现),这样便可以
在不用考虑对象具体类型的前提下而直接使用对象下的方法
3、怎么使用多态
import abc #调用内置模块abstract class,可以简写成abc class Animal(metaclass=abc.ABCMeta): @abc.abstractmethod #在父类属性上添加 def eat(self): pass @abc.abstractmethod def drink(self): pass @abc.abstractmethod def run(self): pass @abc.abstractmethod def bark(self): pass # obj=Animal() # 抽象基类本身不能被实例化 class Cat(Animal): def eat(self): #这样子类在使用相同属性时就必须遵循父类相同属性的标准,否者会报错 print('cat eat') def drink(self): print('cat drink') def run(self): print('cat run') def bark(self): print('喵喵喵') class Dog(Animal): def eat(self): print('dog eat') def drink(self): print('dog drink') def run(self): print('dog run') def bark(self): print('汪汪汪') class Pig(Animal): def eat(self): print('pig eat') def drink(self): print('pig drink') def run(self): print('pig run') def bark(self): print('哼哼哼') c=Cat() d=Dog() p=Pig()
这样可以在不同人开发同一个程序有继承关系时而且有基类与子类相同属性名称时使用一基类的标准,这样更清晰,易懂。
classmethod与staticmethod的绑定方法
1 绑定方法:
在类内部定义的函数,默认就是给对象来用,而且是绑定给对象用的,称为对象的绑定方法
绑定对象的方法特殊之处:
应该由对象来调用,对象来调用,会自动将对象当作第一个参数传入
绑定到类的方法特殊之处:
应该由类来调用,类来调用,会自动将类当作第一个参数传入
import settings class People: def __init__(self,name,age): self.name=name self.age=age def tell(self): print('%s:%s' %(self.name,self.age)) @classmethod #哪个类来调用就把哪个类作为第一个参数传入 def from_conf(cls): return cls(settings.NAME,settings.AGE) # p=People('egon',19) # p.tell() # p1=People(settings.NAME,settings.AGE) # p1.tell() # p2=People(settings.Name,settings.AGE) # p3=People('alex',74) # p3.tell() # print(People.from_conf) # p4=People.from_conf(People) # print(People.from_conf) # p4=People.from_conf() # p4.tell()
2、staticmethod:非绑定方法,就是一个普通函数
特性:既不跟类绑定,也不跟对象绑定,这意味着谁都能用
谁来用都是一个普通函数,也就是说没有自动传值的特性了
import settings
import hashlib
import time
class People:
def __init__(self,name,age):
self.uid=self.create_id()
self.name=name
self.age=age
def tell(self):
print('%s: %s:%s' %(self.uid,self.name,self.age))
@classmethod
def from_conf(cls):
return cls(settings.NAME,settings.AGE)
@staticmethod
def create_id():
m=hashlib.md5()
m.update(str(time.clock()).encode('utf-8'))
return m.hexdigest()
obj=People('egon',18)
# print(obj.uid,obj.name,obj.age)
# obj.tell()
# print(obj.create_id)
# print(People.create_id)
print(obj.create_id())
print(People.create_id())