目录
一、isinstance和issubclass
判断某个对象是不是某个类的实例
isinstance()
判断一个类是不是另一个类的子类(所有类都是object的子类或子子类)
issubclass()
#判断某个对象是不是某个类的实例
# isinstance()
#判断一个类是不是 另一个类的子类(所有类都是object的子类或子子类)
#issubclass
class Person:
pass
class Student(Person):
pass
stu = Student()
# 判断两个对象是不是同一类型
print(type(1) == type(1))
#判断stu对象是不是Student类的实例
print(isinstance(stu,Student))
#判断一个类是不是 另一个类的子类(所有类都是object的子类或子子类)
print(issubclass(Student,Person))
二、反射
1.反射的定义
反射即反省,对象要具备一种修正错误的能力
2.反射的方法
hasattr 是否存在某个属性
getattr 获取某个属性的值
setattr 设置某个属性的值
delattr 删除某个属性
使用场景:访问的属性不明确
如果在编写代码期间,就能明确知道我要访问的属性,没有必要使用反射
如果在编写代码期间,无法明确知道我要访问的属性,这时就应该使用反射
3.如何使用
通过字符串来操作属性
hasattr(obj, "name") # stu.name 查看这个属性是否存在
getattr(obj, "name", "没有name属性") # stu.name 获取这个属性,不存在则:输出没有name属性
setattr(stu, "school", "beijing") #stu.school = beijing 增加一个school属性
delattr(stu, "school") #del stu.school 删除学校属性
class Student:
def __init__(self,name,sex,age):
self.name = name
self.age = age
self.sex = sex
def study(self):
print("学生正在学习...")
stu = Student("aigen", "woman", 38)
#当你获取一个对象,但是并不清楚该对象的内部细节时,就需要反射了
def test(obj):
if hasattr(obj, "name"): # stu.name 查看这个属性是否存在
print(getattr(obj, "name", "没有name属性")) # stu.name 获取这个属性,不存在则:输出没有name属性
test(stu)
setattr(stu, "school", "beijing") #stu.school = beijing 增加一个school属性
delattr(stu, "school") #del stu.school 删除学校属性
print(getattr(stu, "school", "没有学校属性"))
delattr(stu, "age")
print(stu.age)
反射练习:
# 使用场景:编写代码期间无法明确要访问的属性
class Student:
def study(self):
print("学习中...")
stu = Student()
res = getattr(stu, "study", None)
print(res)
def eat(self):
print("正在吃饭...")
#可以通过反射的方式为对象增加一个方法 但是这样的增加方法就是一个普通函数不会自动传值
setattr(stu, "eat", eat)
print(getattr(stu, "eat", None))
#编写一个CMD工具,这个工具可以支持两个命令 dir,tasklist
class CMD:
def dir(self):
print("列出当前文件目录...")
def tasklist(self):
print("查看任务列表...")
cmd = CMD()
res = input("请输入指令:").strip()
if hasattr(cmd, res):
func = getattr(cmd, res)
print(func)
func()
else:
print("输入的指令不正确...")
三、__ str __ 方法
将对象转换成字符串
1.内置函数
函数前后都带有双下划线,会在某些时机自动执行,一般情况不应该直接调用它们。
2.使用
将需要自定义打印的内容通过__ str __方法实现,返回一个字符串
class Test:
def __init__(self,name):
self.name = name
def __str__(self):
print("str run...")
return self.name
t = Test("安米")
print(int(1).__str__())
print(str(t)) #在将一个对象转换字符串时,本质就是在调用这个
四、__ del __ 方法
析构函数:分析构造,并拆除这个对象
1.执行方式
- 当对象被从内存中删除时会自动执行
- 程序员手动删除了这个对象,也会自动执行
2.什么时候使用
当程序运行结束时,需要做一些清理操作,就使用__ del __
import time
class Student:
def __del__(self):
print("对象被删除了")
stu = Student()
del stu
time.sleep(1)
class TextFile:
def __init__(self, filepath, mode="rt", encoding="utf-8"):
self.file = open(filepath, mode=mode, encoding=encoding)
def read(self):
return self.file.read()
def write(self, text):
return self.write(text)
#该方法其实就是一个通知性质,仅仅是告诉程序员,对象即将被删除
def __del__(self):
self.file.close() #关闭系统文件
tf = TextFile("反射.py")
print(tf.read())
# tf.file.close() 手动关闭多余了,在程序运行完一次以后就会删除对象进行关闭
tf.read()
五、exec方法
execute:执行
1.作用
解析执行python代码,并且将得到的名称,存储到制定的名称空间。(解释器内部也是调用它来执行代码)
2.如何使用
参数一:需要一个字符串对象,表示需要被执行的python语句
参数二:是一个字典,表示全局名称空间
参数三:也是一个字典,表示局部名称空间
globalsdic = {}
localsdic = {}
exec("""
aaaaaaaaaa = 1
bbbbbbbbbb = 2
def func1():
print("我是func1")
""", globalsdic, localsdic) #globalsdic 也可以用 {}
#如果同时制定了 全局和局部 则会将字符串中包含的名称 解析后存储到局部中
print(globalsdic)
print(localsdic)
localsdic["func1"]()
六、元类
用于产生类的类,type就是元类
所有的自定义类都是通过type实例化得来
一切皆对象
1.创建模块的过程:
- 创建一个空的名称空间
- 执行内部的代码
- 将得到的名字放到名称空间中
2.类的创建过程相似于模块的创建
类是由type实例化产生的
使用type来产生一个类
一个类是由 类名字 类的父类元祖 类的名称空间 三个部分组成
class Student(object):
school = "北京大学!"
def study(self):
print("学习中...")
print(type(Student)) #<class 'type'> Student 的类型为type
#类是type类型的实例(对象)
#type实例化一个类
#myclass 包含的代码
code = """
name = "张三"
age = 18
def hello(self):
print("hello %s" % self.name)
"""
#类的名字
class_name = "MyClass"
#类的父类们
base_classes = (object,) #必须是个元组
#类的名称空间
namespace = {}
exec(code, {}, namespace)
res = type(class_name, base_classes, namespace)
print(Student)
print(res.name)
print(res.age)
print(res.hello)
class Test(object): #Test = type("Test", (object,), {})
pass
七、__ call __ 方法控制对象的实例化过程
1.定义
调用:在对象被调用时 执行
2.自定义元类的目的
- 可以通过__ call __来控制对象的创建过程
- 可用控制类的创建过程
3.对象实例化模板
- 创建空对象
- 调用初始化方法
- 得到一个完整的对象
class MyMeta(type):
def __call__(self, *args, **kwargs):
obj = object.__new__(self)
self.__init__(obj, *args, **kwargs)
return obj
"""
__call__
调用的意思
在在对象被调用时 执行
函数 类
自定义元类 的目的
1.可以通过__call__ 来控制对象的创建过程
2.可用控制类的创建过程
"""
# 自定义一个元类 元类也是一个类 但是需要继承type
class MyMeta(type):
# self 表示要创建对象的那个类(Person) *args是调用Person类时传入的参数
def __call__(self, *args, **kwargs):
print("MyMte中的 call run'")
print(self,*args,**kwargs)
# 下面的三步是固定写法 一个模板 只要你需要控制对象的创建过程 就应该先把模板写出来
# 1.创建空对象
obj = object.__new__(self)
# 2.调用初始化方法
self.__init__(obj,*args,**kwargs)
# self.__init__(obj)
# 3.得到一个完整的对象
return obj
# 修改Person类的元类为MyMeta
class Person(metaclass=MyMeta):
def __init__(self,name,age):
self.name = name
self.age = age
def __call__(self, *args, **kwargs):
print("call run...")
#调用Person这个对象时 执行的是 Person的类(type)中__call__ 方法
p = Person("张三疯",80)
print(p)
# 当调用对象时 会执行该对象所属类中的__call__方法
# p()
print(p.name)
print(p.age)
# class People:
# def __init__(self,name):
# self.name = name
# pass
#
#
# p = People()
# p.anme = 1
八、通过元类控制类的创建过程
# 要控制类的创建过程 只要找到类所属的类 中的__init__即可
class MyMeta(type):
# self 刚建出来的类
# 第二个 类的名字
# 第三个 类的父类们 元组
# 第四个 这个类传进来的名称空间
def __init__(self,class_name,bases,namespace):
print("============================")
#print(self.__dict__)
# 我要控制 类的名字 必须 是大写开头
if not class_name.istitle():
print("类名 必须大写开头...... ")
# 该代码是主动抛出异常
raise TypeError("类名 必须大写开头...... ")
#要空类的创建 必须包含__doc__这个属性
if not self.__doc__:
raise TypeError("类中必须有文档注释.....")
pass
class Student(metaclass=MyMeta): # Student = MyMeta("Student",(object,),{})
"""
这是文档注释 可以通过__doc__来获取
这是一个学生类
"""
# 在类的__init__中可以控制该类对象的创建过程
def __init__(self,name):
print("-----------------------")
print(self.__dict__)
self.name = name
print(Student.__doc__)
# 元类使用总结:
"""
元类是用于创建类的类
学习元类是为了 能控制类的创建过程 以及 类实例化对象的过程
一.
控制类的创建过程
1.创建一个元类 (需要继承type)
2.覆盖__init__方法 该方法 会将新建的类对象 类名 父类们 名称空间 都传进来 ,
可以利用这些信息在做处理
3.对于需要被控制的类 需要指定metaclass 为上面的元类
二.
控制类实例化对象的过程
1.创建一个元类 (需要继承type)
2.覆盖__call__方法 会将 正在实例化对象的类 调用类是传入的参数 都传进来
3.在__call__方法中 必须要先编写模板代码
3.1创建空对象
3.2调用类的__init__方法来初始化这个空对象
3.3返回该对象
4.加入你需要控制的逻辑
类的三个组成部分
类名 父类们 名称空间
元类 -> 实例化产生 -> 类 -> 实例化产生 -> 对象
"""
九、单例模式
"""
单例模式
一种设计模式(套路)
单个实例
一个类如果只有一个实例 那么该类称之为单例
为什么需要单例
"""
class MyMeta(type):
obj = None
def __call__(self, *args, **kwargs):
if not MyMeta.obj:
obj = object.__new__(self)
self.__init__(obj,*args,**kwargs)
MyMeta.obj = obj
return MyMeta.obj
#打印机类
class Printer(metaclass=MyMeta):
"""
这是一个单例类 请不要直接实例化 使用get方法来获取实例
"""
obj = None
def __init__(self,name,brand,type):
self.name = name
self.brand = brand
self.type = type
def printing(self,text):
print("正在打印 %s" % text)
# 通过该方法来获取对象 可以保证只有一个对象
# 但是这还不够 因为 还是可以通过调用类产生新对象
# 就应该使用元类 来控制实例化的过程 __call__
# 在__call__ 中编写代码 保证每次调用call 都返回同一个实例 即可
@classmethod
def get_printer(cls):
if not cls.obj:
obj = cls("ES005","爱普生","彩色打印机")
cls.obj = obj
print("创建了新的对象")
return cls.obj
# 以下三个对象 的数据完全相同 但是却 占用三分内存空间
# p1 = Printer("ES005","爱普生","彩色打印机")
# p2 = Printer("ES005","爱普生","彩色打印机")
# p3 = Printer("ES005","爱普生","彩色打印机")
# 现在要处理问题就是 如何能够限制该类 只能实例化一个对象
p = Printer.get_printer()
print(p)
p = Printer.get_printer()
print(p)
p = Printer.get_printer()
print(p)
p = Printer.get_printer()
print(p)
p1 = Printer("ES005","爱普生","彩色打印机")
p2 = Printer("ES005","爱普生","彩色打印机")
print(p1)
print(p2)
# print(p1,p2,p3)
# p1.printing("一本小说....")