day26 面向对象的常用方法 和 元类的使用
1. 面向对象中的常用方法 *****
isinstance() # 判断某个对象是不是某个类的实例
# 判断stu对象是不是Student类的实例
是不是子类
issubclass()
class Person:
pass
class Student(Person):
pass
stu = Student()
#判断 两个对象是不是同一个类型
print(type(1) == type(1))
# 判断stu对象是不是Student类的实例
print(isinstance(stu,Student))
# 是不是子类
# issubclass()
# 判断一个类是不是 另一个类子类 (所有类都是object的子类或子子类)
print(issubclass(Student,Person))
print(isinstance(type,type))
不仅能判断父类,还能判断父类的父类
2. 反射 *****
反射 其实说的是反省
简单的说就是对象具备一种修正错误的能力
hasattr 是否存在某个属性
getattr 获取某个属性的值
setattr 设置某个属性的值
delattr 删除某个属性
class Student:
def __init__(self,name,sex,age):
self.name = name
self.age = age
self.sex = sex
def study(self):
print("学生正在学习...")
stu = Student("矮根","woman",38)
print(stu.name)
stu.name = "高根"
print(stu.name)
del stu.name
print(stu.name)
# 当你获取到一个对象 但是并不清楚搞对象的内部细节时 就需要使用反射了
def test(obj):
if hasattr(obj,"name"):
print(getattr(obj,"name","没有name属性"))
test(stu)
setattr(stu,"school","beijing")
delattr(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 *****
__str__
前后带杠杠的都是特殊的内置函数,会在某些时机自动执行,一般情况我们不应该直接调用他们
当我们需要自定义打印显示内容时,就需要实现__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([1,2,3,5].__str__())
print(t)
# 在讲一个对象转换字符串时 本质就是在调用这个对象 __str__方法
print(str(t))
del ****
当对象被从内存中删除时,自动执行
另一种情况是,程序员手动删除了这个对象,也会自动执行
什么时候使用它
在python中有自动内存管理机制,所有python自己创建的数据,不需要我们做任何操作
但是有一种情况,我们使用python打开了一个不属于python管理的数据
比如打开了一个文件,这个文件一定是操作系统在打开 会占用系统内存 而python解释器无法操作系统内存的
所以 当你的python解释器运行结束后 文件依然处于打开状态 这时候就需要使用__del__来关闭系统资源
__del__也称之为析构函数
分析构造 并拆除这个对象
该方法其实就是一个通知性质,仅仅是告诉程序员,对象即将被删除
分析构造并拆除这个对象
class Student:
def __del__(self):
print("对象被删除了....")
stu = Student()
# 手动删除 立即执行__del__
del stu
import time
time.sleep(5)
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):
self.file.write(text)
# 该方法其实就是一个通知性质 仅仅是告诉程序员 对象即将被删除
def __del__(self):
# 在这里关闭系统的文件 妥妥的
self.file.close()
tf = TextFile("2.今日内容.txt")
print(tf.read())
# tf.file.close() # 不需要手动关闭了 在对象删除时会自动关闭
tf.read()
exec ****
execute的缩写
表示执行的意思
其作用 是帮你解析执行python代码 并且将得到的名称 存储到制定的名称空间 解释器内部也是调用它来执行代码的
参数一需要一个字符串对象,表示需要被执行的python语句
参数二是一个字典,会把字典放在全局名称空间中
参数三也是一个字典,会把字典放在局部名称空间中
exec('')
globalsdic = {}
localsdic = {}
exec("""
aaaaaaaaaaaaaaaaaaaa = 1
bbbbbbbbbbbbbbbbbbbbbbbbbbbb = 2
def func1():
print("我是func1")
""",globalsdic,localsdic)
# 如果同时制定了 全局和局部 则 会字符串中包含名称 解析后存到局部中
# print(globalsdic)
print(localsdic)
localsdic["func1"]()
在字符串中定义好函数后,要用后面的字典名称去调用函数,直接在全局空间或者局部名称空间,用函数名调用会找不到
元类 ****
一切皆对象
元类是指用于产生类的类,type就是元类
所有的自定义类都是通过type实例化得来的
使用type可以发现,类其实是type类型的实例(对象)
创建模块的过程
1.创建一个空的名称空间
2.执行其内部的代码
3.将得到的名字放到名称空间中
# class也是一个对象
class Student(object):
school = "北京大学!"
def study(self):
print("学习中...")
# 使用type可以发现 类其实是type类型的实例(对象)
print(type(Student))
我们可以自己调用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)
1.类是由type实例化产生的
2.我们可以使用type来产生一个类
3.一个类由类名字,类的父类元组,类的名称空间三个部分组成
class Test(object): #就相当于Test = type("Test",(object,),{})
pass
自定义元类,元类也是一个类
def Person(metaclass = MyMeta)
call
调用的意思
在对象被调用(加括号时)时,执行
函数 类
自定义元类的目的
1.可以通过__call__来控制对象的创建过程
2.可以控制类的创建过程
class MyMeta(type):
def __call__(self,*args,**kwargs):
print('from Mymeta call run')
print(self,*args,*kwargs)
#下面三步是创建对象的固定写法,一个模板,只有你需要控制对象的创建过程,就必须先把模板写出来
obj = object.__new__(self)
self.__init__(obj,*args,**kwargs)
return obj
class Person(metaclass=Mymeta):
def __init(self,name,age):
self.name = name
self.age = age
def __call__(self,*args,**kwargs):
print('Peson call run...')
#调用Person这个对象时 执行的是 Person的类(type)中__call__ 方法
p = Person("张三疯",80)
print(p)
# 当调用对象时 会执行该对象所属类中的__call__方法
p()
print(p.name)
print(p.age)
# 要控制类的创建过程 只要找到类所属的类 中的__init__即可
class MyMeta(type):
#要自己完成__init__函数完成类的创建
#self 表示要建出来的类
#第二个参数 类的名字
#第三个参数 类的父类们,元组形式
#第四个参数 这个类传进来的名称空间
def __init__(self,class_name,bases,namespace): # (在--init__中不实现赋值操作,python也会自动按位置传参)
print('==========')
#print(self.__dict__)
# 我要控制 类的名字 必须 是大写开头
if not class_name.istitle():
print("类名 必须大写开头...... ")
# 该代码是主动抛出异常
raise TypeError("类名 必须大写开头...... ")
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 __init__(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
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("一本小说....")
day26 面向对象的常用方法 和 元类的使用的更多相关文章
- 面向对象高级C(元类补充及单例模式)
元类有关知识点补充 #类的名称空间 类的名称空间不能用类似字典的方法修改,例如School类里面有name属性xxx,那么我用School.__dict__['name'] = 'yyy'就会报错&q ...
- 面向对象高级B(元类)
元类 python一切皆对象,类实际上也是一个一个对象 类是一个对象,那他一定是由一个类实例化得到,这个类就叫元类 如何找元类 class Person: def __init__(self, nam ...
- python中面向对象元类的自定义用法
面向对象中的常用方法 1.instance 和 issubclass instance :判断两个对象是不是一类 issubclass :判断某个类是不是另一个类的子类 #两个常用方法的使用 clas ...
- Python面向对象篇之元类,附Django Model核心原理
关于元类,我写过一篇,如果你只是了解元类,看下面这一篇就足够了. Python面向对象之类的方法和属性 本篇是深度解剖,如果你觉得元类用不到,呵呵,那是因为你不了解Django. 在Python中有一 ...
- Python全栈开发之9、面向对象、元类以及单例
前面一系列博文讲解的都是面向过程的编程,如今是时候来一波面向对象的讲解了 一.简介 面向对象编程是一种编程方式,使用 “类” 和 “对象” 来实现,所以,面向对象编程其实就是对 “类” 和 “对象” ...
- python面向对象( item系列,__enter__ 和__exit__,__call__方法,元类)
python面向对象进阶(下) item系列 __slots__方法 __next__ 和 __iter__实现迭代器 析构函数 上下文管理协议 元类一.item系列 把对象操作属性模拟成字典的 ...
- 【转】python面向对象中的元类
type() 动态语言和静态语言最大的不同,就是函数和类的定义,不是编译时定义的,而是运行时动态创建的. 比方说我们要定义一个Hello的class,就写一个hello.py模块: class Hel ...
- Python之面向对象元类
Python之面向对象元类 call方法: class People: def __init__(self,name): self.name=name # def __call__(self, *ar ...
- 面向对象:元类、异常处理(try...except...)
元类: python中一切皆对象,意味着: 1. 都可以被引用,如 x = obj 2. 都可以被当做函数的参数传入 3. 都可以被当做函数的返回值 4. 都可以当做容器类的元素(列表.字典.元祖.集 ...
随机推荐
- 41.纯 CSS 绘制一支栩栩如生的铅笔
原文地址: https://segmentfault.com/a/1190000015153865 感想: 不难 HTML code: <div class="pencil" ...
- MySQL 5.7 时间显示修改(log_timestamps UTC)
https://blog.csdn.net/leshami/article/details/78952842 在MySQL 5.7版本中,日志记录时间发生了变化,使用了UTC方式来记录日志时间,也就是 ...
- 复习 HTML
1.<b></b>:加粗 <i></b>:斜体 <u></u>:文字下划线 <s></s>:文字删除线 ...
- Flex+BlazeDS+java通信详细笔记2-推送
前台是Air,后台是java 在运行之前,先要在IE地址栏输入http://127.0.0.1:8080/PushDemo/TickCacheServlet?cmd=start 激活它. 地址:htt ...
- markdown的试用
因为markdown,我接触到latex,因为latex,我花了几个月去看相关的书籍 我看了以下相关的资料 1.<LaTeX入门> 刘海洋 2.英文 TeX - LaTeX Stack E ...
- poi excel 设置边框字体行高行宽
final HSSFSheet sheet = wb.createSheet(sheetName + "_" + n); System.out.println("s ...
- python内置函数使用
print(abs(1)) #绝对值,正数就是自己 ",''])) #计算可迭代对象中是否为真,其中一个为假,就显示为假 print(all('')) # If the iterable i ...
- sql server 字符串字节长度
SQL Server 字符个数,字节长度,len不是你想要的字节数,datalength才能得到字节数 select len('娜娜123') ,datalength('娜娜123') 5 ...
- 机器学习-文本数据-文本的相关性矩阵 1.cosing_similarity(用于计算两两特征之间的相关性)
函数说明: 1. cosing_similarity(array) 输入的样本为array格式,为经过词袋模型编码以后的向量化特征,用于计算两两样本之间的相关性 当我们使用词频或者TFidf构造出 ...
- 【平台兼容性】jeecg3.7 兼容weblogic 部署改造方案
MyEclipse 配置 WebLogic 10.3.3请参考: https://my.oschina.net/aini3884/blog/895689 常见问题: 1. problem: cvc-e ...