day29(双下方法)
今日内容回顾
上周内容回顾
1.写一个类继承目标父类
2.子类中重写父类的方法 eg:重写JSONEncoder方法 支持更多数据类型序列化
面向对象三大核心之封装
封装:就是将类中的方法 或者是数据 隐藏起来不能直接访问
不过前提条件就是类定义阶段有效
class MyClass:
__school='高级中学'
def__choose_course(self):
pass
'__变量名 >>>: _类名__变量名'''
由于python崇尚的是自由、简洁、大方不完全限制程序员的行为 所以有时候我们也会象征的在名字前面加一个下划线
意思就是封装的含义:
class MyClass:
_name = 'jason'
def _study(self):
pass
像这样用一个下划线在变量名开头等同于两个下划线开头 都是不想直接访问、、、、
目的:并不是为了藏起来而是对外提供了访问接口 在接口内就可以定义额外的功能
property就是将方法伪装成数据
面向对象三大核心之多态
比如:一种事物多种形态
水 :固态液态气态 这就是多态 换句话讲就是有多个形态但是都本质还是属于一种东西写代码过程中 针对多个事物不需要考虑具体的特征只需要抽取相似的特征 只要符合该特征就应该有相同的方法
'''鸭子类型'''
比如在linux系统中 一切皆文件
内存可以存取数据 硬盘也可以存取数据
那么在操作内存或者硬盘的时候应该有共同的操作
read()
write()
python基础数据类型的方法
无论是字符串、列表、字典都需要统计长度
len()
面向对象之反射方法
hasattr():判断对象是否含有字符串对应的数据或者功能
getattr():根据字符串获取对应的变量名或者函数名
setattr():根据字符串给对象设置键值对
delattr():根据字符串删除对象对应的键值对
上述方法可以操作对象 也可以操作类、文件、模块等
hasattr():判断对象是否含有字符串对应的数据或者功能
class Foo(object):
def __init__(self,name):
self.name = name
def test(self):
print("%s is testing..."%self.name)
d = Foo("Tom")
choice = input(">>>>:").strip()
# d.choice 行不通,choice是字符串
print(hasattr(d,choice)) # 判断eat方法是否存在
getattr():根据字符串获取对应的变量名或者函数名
class Foo(object):
def __init__(self,name):
self.name = name
def test(self):
print("%s is test......"%self.name)
d = Foo("Tom")
choice = input(">>>>:").strip()
print(getattr(d,choice)) # 打印eat方法在内存中的对象地址
c = getattr(d,choice)
c()
setattr():根据字符串给对象设置键值对
# 第一种,设置方法
def bulk(self):
print("%s is d...."%self.name) # 新加方法
class Foo(object):
def __init__(self,name):
self.name = name
def test(self):
print("%s is test......"%self.name)
d = Foo("Tom")
choice = input(">>>>:").strip()
if hasattr(d,choice):
f = getattr(d,choice)
f()
else:
setattr(d,choice,bulk) # 动态向class里面装入了一个方法
d.bulk(d)
# 这里的b.bluk仅仅是个变量名,随时可以替代,
# 如写成d.talk(d),那么也是没有问题的,不过后面调用的时候choice的input就要变成talk方法
# 第二种,设置(修改)属性
def bulk(self):
print("%s is d...."%self.name) # 新加方法
class Foo(object):
def __init__(self,name):
self.name = name
def test(self):
print("%s is testing..."%self.name)
d = Foo("Tom")
choice = input(">>>>:").strip()
if hasattr(d,choice):
setattr(d,choice,'Dom') # 将已有的str进行修改了,待打印name的时候,name就变了
# 动态传入属性
else:
setattr(d,choice,None) # 动态传入属性
print(getattr(d,choice))
print(d.name)
delattr():根据字符串删除对象对应的键值对
class Foo(object):
def __init__(self,name):
self.name = name
def test(self):
print("%s is test......"%self.name)
d = Foo("Tom")
choice = input(">>>>:").strip()
if hasattr(d,choice):
delattr(d,choice)
print(d.name)
今日内容很详细
利用面向对象编写系统终端功能
# class Wincmd(object):
# def ls(self):
# print('windows系统正在执行ls命令')
#
# def dir(self):
# print('windows 系统正在执行dir命令')
#
# def cd(self):
# print('windows 系统正在执行cd命令')
#
#
# class Linuxcmd(object):
# def ls(self):
# print('linux系统正在执行ls命令')
#
# def dir(self):
# print('linux 系统正在执行命令')
#
# def cd(self):
# print('linux 系统正在执行cd命令')
#
#
# object1 = Wincmd()
# object2 = Linuxcmd()
#
#
# def run(obj):
# while True:
# cmd = input('请输入指令')
# if hasattr(obj, cmd): #:判断对象是否含有字符串对应的数据或者功能
# getattr(obj, cmd)() # 根据字符串获取对应的变量名或者函数名
# else:
# print('cmd command not found')
#
#
# run(object2)
# run(object1)
面向对象各种双下方法
这些双下方法有的不需要刻意调用 达到某个条件就会触发
# 双下__str__
# class Myclass(object):
# def __init__(self, name):
# self.name = name
#
# # 对象被执行打印(print、前端展示)操作的时候自动触发
# # 该方法必须返回字符串类型的数据 很多时候用来更加精准的描述对象
# def __str__(self):
# print('我什么时候锤你')
# return '现在锤你' or # return 'Myclass类产生的:%s’%self.name
#
#
# # 正常定义类触发不了
# object1 = Myclass('zqh')
# # print(object1)#没有双下__str__打印的结果<__main__.Myclass object at 0x01C6A1C0>
# print(object1)#TypeError: __str__ returned non-string (type NoneType)
# #我什么时候锤你 触发了错误因为没有返回字符串 该方法必须反会字符串类型
# # 双下del __del__
# class Myclass(object):
# def __init__(self, name):
# self.name = name
#
# # 对象被执行(可以是被动也可以是主动)删除操作之后自动执行
# def __del__(self):
# print('del什么时候锤你')
#
#
# object2 = Myclass('zqh') # 正常定义类是会触发的
# del object2 # del+对象名
# print('捶我') # 正常执行程序被动删除的时候执行的打印操作
# 被动删除的打印顺序
# 删我
# del什么时候锤你
# 主动删除的打印顺序
# del什么时候锤你
# 捶我
class Myclass(object):
def __init__(self, name):
self.name = name
def __getattr__(self, item):
print('什么时候指行__getattr__方法', item)
# print(type(item)) # 自动将变量名转换字符串 <class 'str'>
return '不好意思没%s这个名字' % item
#object3 = Myclass('zqh')
# print(object3.name)#没有触发
# print(object3.age) # 触发,对象查找不存在名字的时候自动触发 item
# object3.age # 触发,对象查找不存在名字的时候自动触发 item
# print(object3.age)
# 打印结果不好意思没age这个名字
双下__setattr__
class Myclass(object):
def __init__(self, name, key, value):
self.name = name
# 对象在执行添加属性操作的时候自动触发 >>>object4.变量名=变量值
def __setattr__(self, key, value):
# print('什么时候触发__setattr__然后捶你')
# print(key, value)
# if key=='name':#1
# raise Exception('么有资格')#这个判断是你啥都刻有有就不能有名字
# 2
if not key.islower():
raise Exception('名字只能小写')
super().__setattr__(key,value)#判断名字之能小写
object4 = Myclass('zqh')
# name zqh 这里为什么会触发 object4.变量名=变量值 self.name = name\
# 只要是对象点一个东西都会触发
#
print(object4.__dict__)
# 创建只要是对象点一个东西都会触发
object4.Age=18# 报错因为是大写
#key, value 名字和值
# 双下__call__
# class Myclass(object):
# def __init__(self, name):
# self.name = name
# def __call__(self, *args, **kwargs):
# print('__call__神魔时候出发',args,kwargs)
# object5=Myclass('zah')
# # print(object5(123,‘qwer))__call__神魔时候出发 (123, 'qwer') {}
# # object5()#独享加括号穿什么都可以
# # object5()对象被加括号调用的时候自动触发
# 爽下 .__enter__. __exit__
class Myclass(object):
def __init__(self, name):
self.name = name
def __enter__(self):
# 对象被执行with上下文管理语法开始自动触发
print('__enter__什么时候执行')
# 该方法返回什么as后面的变量名就会得到什么
def __exit__(self, exc_type, exc_val, exc_tb):
# 对象被执行with上下文管理语法结束之后自动触发
print('__exit__什么时候执行')
object6 = Myclass('zqh')
with object6 as f:
print(1234567)
print(1234)
# 打印结果
# __enter__什么时候执行
# 1234567
# __exit__什么时候执行
# 1234
双下__getattribute__#更广
class Myclass(object):
def __init__(self, name):
self.name = name
# 只要对象查找名字无论名字是否存在都会执行该方法
# 如果类中有__getattribute__方法 那么就不会去执行__getattr__方法
def __getattribute__(self, item):
print('什么时候执行',item)
object7 = Myclass('zqh')
print(object7.name)
print(object7.age)
笔试题讲解
1.让字典具备句点符查找值的功能
# 1.定义一个类继承字典
class MyDict(dict):
def __getattr__(self, item):
return self.get(item)
def __setattr__(self, key, value):
self[key] = value
'''要区别是名称空间的名字还是数据k:v键值对'''
obj = MyDict({'name':'jason','age':18})
# 1.具备句点符取v
# print(obj.name)
# print(obj.age)
# 2.具备句点符设k:v
# obj['gender'] = 'male'
obj.pwd = 123 # 给字典名称空间添加名字 不是数据k:v
print(obj)
2.补全下列代码 使其运行不报错 (这道题针对性较强)
"""
class Context:
pass
with Context() as ctx:
ctx.do_something()
"""
class Context:
def __enter__(self):
return self # 该方法返回什么as后面的变量名就会得到什么
def __exit__(self, exc_type, exc_val, exc_tb):
pass
def do_something(self):
pass
with Context() as ctx:
ctx.do_something()
元类简介
什么是元类?
答:产生类的类
# type查看的其实是当前对象所属的类名称
我们写的任何一个类就是type产生的 type==元类
'type就是所有类默认的元类!!!'''默认==可改
class MyClass(object):
pass
obj = MyClass()
print(type(obj))
print(type(MyClass)) # <class 'type'>
class Student:
pass
print(type(Student)) # <class 'type'>
class Teacher(MyClass):
pass
print(type(Teacher)) # <class 'type'>
'''type就是所有类默认的元类!!!'''
产生类的两种表现形式(本质是一种)
方式一:、
1.class关键字
class C1(object):
pass
print(C1) # <class '__main__.C1'>
方式二:、、
2.type元类(object_or_name,base,dict)
type(类名,父类,类的名称空间)
res = type('C1', (), {})
print(res) # <class '__main__.C1'>
学习目的:
你知道怎么创建你就可以定制自己想要的类
比如:
掌握生产过程 就可以 在过程中加额外操作
比如:要求类的名字必须首字母大写
比如:要求类的名字必须首字母大写
思考在哪里编写定制化代码
类的产生过程目前还比较懵 元类里面的__init__方法
对象的产生过程呢 类里面的__init__方法
方法:由已知推未知
"""
元类的基本使用
# 元类的基本使用
# 自己写一个类继承type
class MyTypeClass(type):
def __init__(cls, cls_name, cls_bases, cls_dict):
if not cls_name.istitle():
raise Exception('类名首字母记得大写')
super().__init__(cls_name, cls_bases, cls_dict)
# 元类是不能通过继承的方式直接指定的"""想要修改必须 需要通过关键字(metaclass)参数的形式修改
class C1(metaclass=MyTypeClass):
school = '清华大学'
# x限制下各类的定义
class a(metaclass=MyTypeClass):
school = '清华大学'
# zhi接报错
# raise Exception('类名首字母记得大写')
#
#
# Exception: 类名首字母记得大写
元类进阶操作
# 元类进阶操作
# 对象加括号会自动执行产生该对象的类里面的__call__
# 并且该方法返回什么对象加括号就会得到什么
"""类里面的__init__方法和元类里面的__call__方法执行的先后顺序"""
class MyTypeClass(type):
def __call__(self, *args, **kwargs):
print('__call__ run 先执行我')
super().__call__(*args, **kwargs)
class MyClass(metaclass=MyTypeClass):
def __init__(self, name):
print('__init__ run在执行你')
self.name = name
obj = MyClass('jason')
# __call__ run 先执行我
# __init__ run在执行你
class MyTypeClass(type):
def __call__(self, *args, **kwargs):
if args:
raise Exception('采用关键字参数')
return super().__call__(*args, **kwargs)
class MyClass(metaclass=MyTypeClass):
def __init__(self, name):
# print('__init__ run在执行你')
self.name = name
class MyClass1():
def __init__(self, name):
# print('__init__ run在执行你')
self.name = name
a1 = MyClass1(name=111)
print(a1, a1.name, a1.__dict__)
a = MyClass(name=111)
print(a, a.name, a.__dict__)
"""强制规定:类在实例化产生对象的时候 对象的独有数据必须采用关键字参数"""
# 对象产生前期控制了一下
# 如果你想高度定制类的产生过程
# 那么编写元类里面的__init__方法
# 如果你想高度定制对象的产生过程
# 那么编写元类里面的__call__方法
双下new方法
__new__用于产生空对象(类) 骨架
__init__a用于实例化对象(类) 血肉
"""
注意:并不是所有的地方都可以直接调用__new__ 该方法过于底层
如果是在元类的__new__里面 可以直接调用
class Meta(type):
def __new__(cls, *args, **kwargs):
obj = type.__new__(cls,*args,**kwargs)
return obj
如果是在元类的__call__里面 需要间接调用
class Mate(type):
def __call__(self, *args, **kwargs):
obj = object.__new__(self) # 创建一个空对象
self.__init__(obj,*args,**kwargs) # 让对象去初始化
return obj
"""
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 一文读懂知识蒸馏
· 终于写完轮子一部分:tcp代理 了,记录一下