python之面向对象4

魔法方法

魔法方法就是面向对象的一些内置方法,在达到某个条件的时候会自动触发,不需要调用!
init
# 在对象实例化的时候会自动触发
# __init__方法

class Person:
    def __init__(self):
        print('实例化之后触发')

res = Person()

str
# 执行打印操作的时候会触发,并且有返回值,返回值只能是字符串类型,没有的话返回None
class Person:
    def __init__(self):
        print('')
    def __str__(self):
        print('执行打印操作的时候触发')
        return '我必须是字符串'
res = Person()
print(res)  
call
# 对象加括号的时候就可以触发,并且可以在括号里加参数
class Person:

    def __call__(self, *args, **kwargs):
        print('对象加括号就可以触发')
        print(args)
        print(kwargs)

res = Person()
res(1 , name='summer')

getattr
# 在对象获取属性名不存在的时候会触发,有返回值
class Person:
    def __getattr__(self, item):
        print('获取不存在的属性名的时候会触发')
        print(item)  # 对象获取的不存在的属性 name
        return '我是getattr'

res = Person()
print(res.name)

getattribute
# 在对象用句点符获取属性的时候会自动触发,无论是否有这个属性。当类内同时有__getattr__ 和 __getattribute__ 会自动选择用__getattribute__方法
class Person:
    def __getattr__(self, item):
        print('获取不存在的属性名的时候会触发')
        print(item)  # 对象获取的不存在的属性 name
        return '我是getattr'
    def __getattribute__(self, item):
        print('获取属性的时候会触发')
        return '我是getattribute'
res = Person()
print(res.age)

image

setattr
# 对象操作属性的时候会触发,eg:对象.name = summer
class Person(object):
    def __init__(self,name):
        self.name = name
    def __setattr__(self, key, value):
        print('我是setattr')
        print(key)   #name
        print(value)  #summer
res = Person('summer')
del
# 对象在删除操作的时候或者程序结束释放内存的时候会触发
class Person(object):
    def __del__(self):
        print('我是删除功能')
res = Person()
del res

enter 和 __exit——
#  __enter__对象被with语法执行的时候会触发,该方法返回什么,as关键字后面的f就打印什么。
# __exit—— 对象被with语法执行并完成with语法子代码,才会触发
class Person(object):
    def __enter__(self):
        print('打印我')
        return 666
    def __exit__(self, exc_type, exc_val, exc_tb):
        print('exit')

res = Person()

with res as f:
    print(f)
魔法方法笔试题
# 题目看下图 如何补全代码 让系统不报错????
class Context:
    # 第一步 with语法执行了类名加括号 那么肯定有__enter__和__exit__方法
    def __enter__(self):
        return self
    # 第二步 __enter__ 被with执行的时候 返回的是什么 f就打印什么
    def __exit__(self, exc_type, exc_val, exc_tb):
        pass
    # 第三步 f.do_something() 其实就是对象.do_something() ,那么我们设置一个给对象的方法
    def do_something(self):
        pass
with Context() as f:
    f.do_something()

image


image

元类

元类推导过程
# 元类推导过程
l1 = [1, 3, 4, 5, 6, 7, 8, 9, 10]
s1 = '充满元气的一天!!!冲冲冲'
d1 ={'name':'summer'}
print(type(l1))  # <class 'list'>
print(type(s1))  # <class 'str'>
print(type(d1))  # <class 'dict'>
# 通过type查看数据类型可以得出一个结论 这些数据类型是类产生的一个个对象
class P:
    pass
res = P()
print(res,type(res))  # <class '__main__.P'>
# 用一切皆对象的编程思想我们是不是可以大胆的猜测一下,类名P是否也是一个对象
print(type(P))  # <class 'type'>
# 通过查看type源码 发现我们自定义的类是由type产生的类

****由此可得出结论:元类简单点讲就是产生类的类,可以产生类也可以控制对象的参数!!

image

产生类的两种方式
# 方式一
class 类名:
    pass

------------

# 方式二
# 利用元类 type
type (类名,类的父类,类的名称空间):
res = type ('cla',(),{})
print(res)  # <class '__main__.cla'> 

**我们学习元类是为了更好的高度定制类,就相当于我学会了怎么制造电脑,那么我就可以通过自己的需求去修改定制我想要的电脑

元类基本使用
# 只由继承了type的类才可以称之为元类!!!
class Myclass(type):
    pass

class Iclass(metaclass=Myclass):
    pass

# 如果想要继承自定义的类 需要使用关键字metaclass等于类名才可以实现 否则的话继承的是type
# __init__ 在类里面是实例化对象的 那么在元类里就是实例化类的
class Myclass(type):
    def __init__(self, what, bases=None, dict=None):
        print(what)  # 类名 Iclass
        print(bases)  # 类的父类 ()
        print(dict)   # 类的名称空间  {'__module__': '__main__', '__qualname__': 'Iclass'}
        # 如果我们想定制类 就可以直接在这里操作相应的方法了
        # 比如想要类名首字母大写的话
        if not what.istitle():
            # 如果继承的类名字母没有大写的话就会打印
            print('首字母必须大写!!!')
        super().__init__(what, bases, dict)

class Iclass(metaclass=Myclass):
    pass
元类进阶
# 元类定制对象参数案例
# 对象加括号触发的是产生这个对象的类的__call__方法
# 类名加括号触发的是产生这个类的__call__方法
# 可以定制对象的参数 要求是必须是关键字参数
class Myclass(type):
    def __call__(self, *args, **kwargs):
        print('我是元类里的call')
        # print(args)  # ('summer', '18')
        # print(kwargs) # {}
        if args:
            raise Exception('参数必须采用关键字形式')
        super().__call__(*args,**kwargs)

class Yclass(metaclass=Myclass):
    def __init__(self, name, age):
        # 在执行双下init方法之前 需要先执行元类的双下call方法
        self.name = name
        self.age = age
        print('我是双下call执行完以后才执行的双下init')

res = Yclass(name = 'summer',age = '18')

双下new方法
class Myclass(type):
    def __call__(self, *args, **kwargs):
        print('')
        obj = self.__new__(self,*args, **kwargs)
        print(obj) # <__main__.Yclass object at 0x000002A5225BB1D0>
		class Yclass(metaclass=Myclass):
    def __init__(self, name, age):
        # 在执行双下init方法之前 需要先执行元类的双下call方法new完对象以后开始执行init
        self.name = name
        self.age = age
        print('')
res = Yclass()

反射实战案例

# 加载配置文件中的大写 组织成字典
import settings
path = dir(settings)
d1 = {}
for i in path:
    if i.isupper():
        # 有字符串和对象这两个关键字就可以用反射了
       a = getattr(settings,i)
       d1[i] = a
print(d1) # {'A': '现在好好敲代码是为了上班更好的摸鱼!!!', 'AGE': '18', 'NAME': 'summer'}

posted @   Hsummer  阅读(40)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示