类与对象的部分机制
1. 抽象基类
Python的鸭子类型无法判断对象类型,为了有判断类型的手段Python中提供了抽象基类,使用装饰器 @abc.abstractmethod和abc模块实现抽象基类的创建
抽象基类的创建和分析:
class CacheBase(metaclass=abc.ABCMeta): #抽象基类的定义
@abc.abstractmethod # 抽象方法的定义
def get(self, key):
pass
@abc.abstractmethod
def set(self, key, value):
pass
class MyCacheBase(CacheBase): # 继承CacheBase
def set(self, key, value): #重写抽象方法 不重写会出现异常
return key+" "+value
def get(self, key):
return key
if __name__ == '__main__':
readis_List = MyCacheBase()
b= readis_List.set("boby", "value")
a= readis_List.get("boby")
print(b) #输出 boby value
print(a) #输出 boby
总结:实现抽象基类的抽象方法才能实现继承,抽象基类很好的把类单独的区分开了,要使用特定的类,就必须实现相应的方法,这就是抽象基类。
2. isinstance和type的区分
两者都可以判断实例的类型,下面分析二者的区别:
class A:
pass
class B(A):
pass
if __name__ == '__main__':
a = B()
print(isinstance(a, A)) #输出 True
print(isinstance(a, B)) #输出 True
print(type(a) is B) # 输出 True
print(type(a) is A) #输出 False
分析上述代码 :A是B的基类,B是A的子类,type只能判断a和B是同类型,isinstance函数可以判断a和B以及基类都是同类型对象,isinstance内部的判断比type更加全面
3. 魔法函数
Python内部的魔法函数比较多,这里介绍几个入门的:
class Person:
def ask(name="名字"): #普通方法
print(name)
class Commany:
def __init__(self, name): #构造函数
self.Name = name
def __getitem__(self, item): # __的方法称为魔法函数 getitem代表对象可迭代 并不是迭代函数
return self.Name[item] # item是索引
def __len__(self): #计算长度
return len(self.Name)
if __name__ == '__main__':
b = Commany(["tome", "Jack", "Li","MM"]) #调用构造
c = b.Name
for a in b: # python for的自动语法 存在 getitem可迭代 反之无法执行for循环
print(a) # 输出tome Jack Li MM
print(len(b)) #输出4 获取类中赋值列表的长度 因为存在len魔法函数可以执行 反之报错
总结:魔法函数定义在类中,无需调用,在执行某些需求时会向类中查找。
4. 类方法、静态方法、和实例方法
关于Python的方法类型直接看代码:
# 一段根据输入的YYYY-MM-SS 给用户反馈YYYY/MM/SS 的日期代码
class Date:
def __init__(self, year, month, day):
self.year = year
self.month = month
self.day = day
def __str__(self):
return "{year}/{month}/{day}".format(year=self.year, month=self.month, day=self.day)
@staticmethod #静态方法
def sta_show(str_date):
try:
year, month, day = tuple(str_date.split("-")) # 分割日期符号
except Exception as e:
print("格式错误 False") # 判断输入是否合法
if int(year) > 0 and int(month) < 12 and int(day) < 31:
return True
@classmethod #类方法
def cla_show(cls, str_date): # 传入类变量
year, month, day = tuple(str_date.split("-"))
return Date(int(year), int(month), int(day))
class Demo:
def tomorrow(self): # 实例方法
print("这是日期")
if __name__ == '__main__':
str_date = input("输入日期 格式为YYYY-MM-SS:")
new_day = Date.sta_show(str_date) #调用静态方法
new_day1 = Date.cla_show(str_date) #调用类方法
d = Demo() #创建实例
d.tomorrow() #调用实例方法
print(new_day)
print(new_day1)
5. 数据封装即私有属性
Python中的"private"。
class User:
def __init__(self, boy):
self.__boy = boy #这里的boy就是私有的属性
def get_boy(self):
return self.__boy
if __name__ == '__main__':
user = User("Jack")
#user.boy是行不通的需要使用get方法
b = user.get_boy()
print(b) # 输出 Jack
print(user._User__boy) #不存在所谓的绝对私有 java中的反射机制也能无视一切 但是python就有些随意了
6. 自醒机制
在Python的每一个类(类也是对象)中存在一串内部结构,在代码中展示:
class Person:
Tname = "user"
class Student(Person):
def __init__(self, name):
self.name = name
if __name__ == '__main__':
user = Student("Jack") #给name赋值Jack
print(user.Tname) # 输出 user
print(user.__dict__) # dict是 python 的字典类型 输出 {'name': 'Jack'}
user.__dict__["name"] = "MaLi" # 直接赋值
print(user.__dict__["name"]) # 输出 MaLi
#下面3句的输出结果分别在结尾的 1 ,2 ,3
print("1",Person.__dict__)
print("user", dir(user)) #dir 输出全部的内部结构
print("Person", dir(Person))
#1. {'__module__': '__main__', 'Tname': 'user', '__dict__': <attribute '__dict__' of 'Person' objects>, '__weakref__': <attribute '__weakref__' of 'Person' objects>, '__doc__': None}
#2. user ['Tname', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'name']
#3. Person ['Tname', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__']
总结:这里的输出结果就是Python中的的内部Key的结构
7. 父类Super函数
class A:
def __init__(self):
print("A")
class B(A):
def __init__(self):
print("B")
super().__init__()
class C(A):
def __init__(self):
print("C")
super().__init__()
class D(B, C):
def __init__(self):
print("D")
super(D, self).__init__()
if __name__ == '__main__':
d = D()
print(D.__mro__) # 打印RMO算法的寻址路径
#输出结果
#D
#B
#C
#A
#(<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)
总结:父类并不是调用父类的构造,而是通过MRO的路径去调用相应的方法
8. 上下文管理器协议
#上下文管理器 with语句
class Sample():
def __enter__(self):
# 获取资源
print("跑起来了")
return self
def __exit__(self, exc_type, exc_val, exc_tb):
#释放资源
print("exit")
def do_something(self):
print("doing something")
if __name__ == '__main__':
with Sample() as sample: # sample 是 Sample类的对象
sample.do_something() #调用方法 默认去执行 enter 和 exit
简化操作:
#contextlib 简化管理器
import contextlib
@contextlib.contextmanager #装饰器 变成上下文管理器
def file_open(file_name):
print("file_start")
yield{} # 定义生成器
print("file end")
if __name__ == '__main__':
with file_open("box") as f:
print("执行中")
#输出结果
#file_start
#执行中
#file end
总结:上下文管理器协议可以方便在开头获取资源在结尾释放资源,自动向类中查找enter 和 exit 魔法函数。