day04.11

面向对象的双下方法

__str__:

对象被执行打印(print、前端展示)操作的时候自动触发,该方法必须返回字符串类型的数据,很多时候用来更加精准的描述对象!!!

复制代码
class Myclass(object):
    def __init__(self,name):
        self.name = name
    def __str__(self):
        print('到底什么时候触发')
        return '对象:%s'%self.name
obj = Myclass('kkk')
print(obj)    # <__main__.Myclass object at 0x0000016B0DE4E240>   不使用__str__方法的时候
print(obj)    # 返回一个__str__的返回值   对象:kkk
print(Myclass)    # 对类并不适用,只适用于对象
复制代码

__del__:

对象被执行(被动、主动)删除操作之后自动执行!!!

复制代码
class Myclass(object):
    def __init__(self,name):
        self.name = name
    def __del__(self):
'''对象被执行(被动、主动)删除操作之后自动执行'''
print('del什么时候执行') obj = Myclass('kkk') del obj # del什么时候执行>>>hhh 先执行删除操作,直接调用了__del__方法 print('hhh') # hhh>>>del什么时候执行 删除操作后,自动执行__del__
复制代码

__getattr__:

对象查找不存在名字的时候自动触发!!!类似于异常处理的情况,避免代码报错。

复制代码
class Myclass(object):
    def __init__(self,name):
        self.name = name
    def __getattr__(self, item):
        '''对象查找不存在的名字的时候自动触发'''
        print('__getattr__方法',item)    # item就是指对象想要查找的名字,它的类型是str
        return '查找不到%s名字'%item
obj = Myclass('kkk')
print(obj.name)    # 不触发
print(obj.age)    # 触发    __getattr__方法  age
复制代码

__setattr__:

对象在执行添加属性操作(操作名称空间的时候)的时候自动触发!!!

复制代码
class Myclass(object):
    def __init__(self,name):
        self.name = name
    def __setattr__(self, key, value):
        '''对象在执行添加属性操作的时候自动触发>>>相当于obj.变量名 = 变量值'''
        # print('__setattr__方法')    # __setattr__方法
        # print(key,value)    # name kkk
        if key == 'gender':    # 可以用来筛选和限制一些对象的功能
            raise Exception('没有gender这个对象')
        if not key.islower():
            raise Exception('只能使用小写')
obj = Myclass('kkk')
print(obj.__dict__)    # {}
复制代码

__call__:

对象被加括号调用的时候自动触发!!!并且该方法返回什么,对象加括号就会返回什么。

复制代码
class Myclass(object):
    def __init__(self,name):
        self.name = name
    def __call__(self, *args, **kwargs):
        '''对象被添加括号调用的时候自动触发'''
        print('__call__方法',args,kwargs)
        return '__call__使得对象也有类似于类的功能'

obj = Myclass('KKK')
print(123,444)    # __call__方法 (123, 444) {}
复制代码

__enter__和__exit__:

__enter__:对象被执行with语法时开始自动触发,该方法返回什么as后面的变量名就会得到什么!!!

__exit__:对象被执行with语法结束之后自动触发!!!

复制代码
class Myclass(object):
    def __init__(self,name):
        self.name = name
   def __enter__(self):
       '''对象被执行with上下文管理语法开始自动触发 '''
       print('__enter__方法')
   def __exit__(self,exc_type,exc_val,exc_tb):
       '''对象被执行with上下文管理语法结束之后自动触'''
       print('__exit__方法')

obj = Myclass('KKK')
with obj as f:
    print(123)
print(321)
'''
__enter__方法
123
__exit__方法
321
'''
复制代码

__getattribute__:

只要对象查找名字,无论名字是否存在都会执行该方法!!!如果类中有__getattribute__方法,那么就不会去执行__getattr__方法。

复制代码
class Myclass(object):
    def __init__(self, name):
        self.name = name
   def __getattribute__(self,item):
       '''只要对象查找名字无论名字是否存在都会执行该方法'''
       print('__getattribute__方法',item)
       return 'xxxx'
obj = Myclass('zzz')
print(obj.name)
复制代码

元类

元类简介:

引入:
#
type功能查看的其实是当前对象所属的类名称 print(type(123)) # <class 'int'> print(type([12, 33, 44])) # <class 'list'> print(type({'name':'jason','pwd':123})) # <class 'dict'>

type就是所有类默认的元类!!!

复制代码
# 一切皆对象!!!
class MyClass(object):
    pass
obj = MyClass()
print(type(obj))    # 返回当前对象所属的类   <class '__main__.MyClass'>
print(type(MyClass))  # 返回当前类所属的类   <class 'type'>

# type就是所有类默认的元类!!!
class Student:
    pass
print(type(Student))  # <class 'type'>
复制代码

产生类的两种表现形式

这两种表现形式的本质都是一样的。

方式1:class关键字

class C1(object):
    pass
print(C1)  # <class '__main__.C1'>

 

方式2:type元类

# 元类创建的语法结构>>>:type(类名,父类,类的名称空间)
res = type('C1', (), {})
print(res)  # <class '__main__.C1'>

元类的使用场景

元类能够控制类的创建,这就为我们提供了一种可以高度自定义控制类的一种方式!!!就可以在类的制定过程中添加自己想要的功能。

参考类产生对象的__init__方法>>>:在"继承"元类的基础上修改功能。

元类是不能通过继承的方式直接指定的,修改的过程不单单是继承方法,还需要使用关键字metaclass!!!

元类的使用方法

复制代码
# 需要通过关键字参数的形式修改
class MyTypeClass(type):
    pass
# class C1(MyTypeClass):
#     pass
# print(C1)
# print(type(C1))    # <class 'type'>
class C1(metaclass=MyTypeClass):
    pass
print(type(C1))    # <class '__main__.MyTypeClass'>
复制代码

eg:

复制代码
class MyTypeClass(type):
    def __init__(cls, cls_name, cls_bases, cls_dict):
        # print(cls, cls_name, cls_bases, cls_dict)
        if not cls_name.istitle():
            raise Exception("类名的首字母必须大写")
        super().__init__(cls_name, cls_bases, cls_dict)

class C1(metaclass=MyTypeClass):
    school = '清华大学'

# 无法定义会报错
# class a(metaclass=MyTypeClass):
#     school = '清华大学'
复制代码

元类的进阶

类加括号

类加括号会执行元类的里面的__call__,该方法返回什么,其实类加括号就会得到什么!!!

复制代码
# 类加括号会执行元类的里面的__call__,该方法返回什么,其实类加括号就会得到什么
class MyTypeClass(type):
    def __call__(self, *args, **kwargs):
        print('__call__ run')    # __call__ run
        return 123
        # super().__call__(*args, **kwargs)


class MyClass(metaclass=MyTypeClass):
    def __init__(self, name):
        print('__init__ run')    # __init__ run
        self.name = name


obj = MyClass('jason')
print(obj)    # 123
复制代码

元类定制对象的产生过程

类在实例化产生对象的时候,对象的独有数据必须采用关键字参数>>>:obj = MyClass(name='jason')

复制代码
# 定制对象的产生过程
class MyTypeClass(type):
    def __call__(self, *args, **kwargs):
        # print('__call__ run')
        # print(args,kwargs)
        if args:
            raise Exception('必须全部采用关键字参数')
        super().__call__(*args, **kwargs)


class MyClass(metaclass=MyTypeClass):
    def __init__(self, name):
        # print('__init__ run')
        self.name = name


# obj = MyClass('jason')    # 报错,没有采用关键字参数
obj2 = MyClass(name='jason')
复制代码

总结:

如果你想高度定制类的产生过程,那么编写元类里面的__init__方法!!!
如果你想高度定制对象的产生过程,那么编写元类里面的__call__方法!!!

 

posted @   *sunflower*  阅读(81)  评论(0编辑  收藏  举报
(评论功能已被禁用)
相关博文:
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?
点击右上角即可分享
微信分享提示