• guxh的python笔记八:特殊方法


     1,类的特殊方法  

    新建一个类,本章内容中的特殊方法如果不创建类或新增方法,默认使用的就是下面的类:

    class Foo:
        """this is Foo"""
        typecode = 'd'
    
        def __init__(self, x):
            self.x = x
    
        def run(self):
            return self.x
    
    f = Foo(1)
    

      

    __doc__:类的描述信息

    print(f.__doc__)  # this is Foo
    

      

    __module_:对象所属modul,如果是当前执行文件的即__main__,如果是import的,可以查看所属的module

    print(f.__module__)  # __main__
    
    import pandas as pd
    df = pd.DataFrame()
    print(df.__module__)  # pandas.core.frame
    

      

    __class__:对象所属类,等效于type

    print(f.__class__)   # <class '__main__.Foo'>
    print(type(f))       # <class '__main__.Foo'>
    

      

    __dir__:

    函数不带参数时,返回当前范围内的变量、方法和定义的类型列表;

    for i in dir():
        print(i)
    
    输出为:
    Foo
    __annotations__
    __builtins__
    __cached__
    __doc__
    __file__
    __loader__
    __name__
    __package__
    __spec__
    f
    

    带参数时,返回参数的属性、方法列表。

    for i in dir(Foo):
        print(i)
    
    输出为:
    __class__
    __delattr__
    __dict__
    __dir__
    __doc__
    __eq__
    __format__
    __ge__
    __getattribute__
    __gt__
    __hash__
    __init__
    __init_subclass__
    __le__
    __lt__
    __module__
    __ne__
    __new__
    __reduce__
    __reduce_ex__
    __repr__
    __setattr__
    __sizeof__
    __str__
    __subclasshook__
    __weakref__
    run
    typecode
    

    类的实例比类多了实例属性:

    print(set(dir(f)) - set(dir(Foo))) # {'x'} 
    print(set(dir(Foo)) - set(dir(f))) # set()
    

    __mro__:打印类的层次结构

    >>> FileNotFoundError.__mro__
    (<class 'FileNotFoundError'>, <class 'OSError'>, <class 'Exception'>, <class 'BaseException'>, <class 'object'>)
    

    __dict__:打印类/实例的属性

    dict只能使用obj.__dict__,不能使用dict(obj),因为后者会被视为字典的初始化

    打印所有实例的属性(不包括类属性):

    f = Foo(1)
    print(f.__dict__)   # {'x': 1}

    打印所有类属性(不包括实例的属性):

    for k, v in Foo.__dict__.items():
        print(k, v)
    
    输出为:
    __module__ : __main__
    __doc__ : this is Foo
    typecode : d
    __init__ : <function Foo.__init__ at 0x000001AC45314620>
    __dict__ : <attribute '__dict__' of 'Foo' objects>
    __weakref__ : <attribute '__weakref__' of 'Foo' objects> 

    注意__dir__和__dict__的区别:前者显示类/实例所有的属性/方法(如果是实例显示的是类+实例的属性/方法),后者显示类/实例属性键值对(类和属性只会分别显示自己特有的)

     __call__:让类的实例变为可调用

    class Foo:
    
        def __call__(self, *args, **kwargs):
            return 1
    
    print(Foo()())   # 1,第一次()是实例化,第二次()是调用
    

      

    __get__、__set__、__delete__:描述符协议,属性的设置/取值/删除

    __getattr__、__setattr__、__delattr__:动态属性的设值/取值/删除,详见类的属性

    __getattribute__:获取已经存在的属性值,__getattr__是获取不存在的属性值的方法

    __getitem__、__setitem__、__delitem__:[]运算符,分量的获取/设置/删除

    class Foo:
    
        def __init__(self, components):
            self._components = sorted(components)
    
        def __setitem__(self, key, value):
            self._components[key] = value
    
        def __getitem__(self, item):
            return self._components[item]
    
        def __repr__(self):
            return '<Foo: {}>'.format(self._components)

    访问与设置分量:

    f = Foo([3, 5, 1, 9])   # <Foo: [1, 3, 5, 9]>
    print(f)
    print(f[1])   # 3
    f[0] = 10
    print(f)      # <Foo: [10, 3, 5, 9]>
    

      

    __enter__,__exit__:上下文管理器,先触发__enter__,再触发with代码块,最后触发__exit__

    class Foo:
    
        def __enter__(self):
            return 'enter获取的内容'   # 可以没有返回内容
    
        def __exit__(self, exc_type, exc_val, exc_tb):
            print('exit时只需的内容')
    
    
    with Foo() as f:
        print(f)   # f获取的是__enter__返回的结果
    
    输出为:
    enter获取的内容
    exit时只需的内容
    

      

    __slot__:存储实例属性方式改为元组方式

    缺省存储实例属性是字典方式,在__dict__中,改为元组方式可以节省空间,但是属性范围受到slot元组限制

    class Foo:
        __slots__ = ('x', 'y')
    

      

    __reversed__:反向迭代协议,让序列类型对象支持反向迭代,如果没有该协议,可以先把对象变成列表再用列表的反向迭代协议

    class Foo:
        def __init__(self, components):
            self.components = [x*x for x in components]
    
        def __reversed__(self):
            return reversed(self.components)    # 委托给self.components背后的生成器
    
    f = Foo([1, 3, 5, 7, 9])
    for i in reversed(f):
        print(i)
    

    __format__: 

    _formats = {'ymd': '{d.year}-{d.month}-{d.day}',
                'mdy': '{d.month}/{d.day}/{d.year}'}
    
    class Foo:
    
        def __init__(self, year, month, day):
            self.year = year
            self.month = month
            self.day = day
    
        def __format__(self, code):
            if code == '':
                code = 'ymd'
            fmt = _formats[code]
            return fmt.format(d=self)
    
    f = Foo(2019, 1, 25)
    print(format(f))           # 2019-1-25
    print(format(f, 'mdy'))    # 1/25/2019
    

    __new__:可以实例化时跳过构造函数

    class Date:
    
        def __init__(self, year, month, day):
            self.year = year
            self.month = month
            self.day = day
    
    >>>d = Date.__new__(Date)
    >>>d
    <__main__.Date object at 0x10b353400>
    >>>d.year
    AttributeError: 'Date' object has no attribute 'year'
    

    __metaclass__:待补充

     __init__:略

    __del__:略

    __str__:略

    __repr__:返回的内容最好符合obj = eval(repr(obj)),即返回内容可以直接用来实例化

    没有定义__repr__或者__str__时,返回的是对象的内存地址:

    class User:
        def __init__(self, user_id):
            self.user_id = user_id
    u = User(3)
    print(u)     # <__main__.User object at 0x000002E85D7383C8>

    使用猴子补丁定义__repr__,再打印u:

    def repr(instance):
        return 'User({})'.format(instance.user_id)
    User.__repr__ = repr
    u = User(3)
    print(u)     # User(3)

    u的repr返回内容可以直接拿来实例化:

    u1 = eval(repr(u)) 
    print(u1)       # User(3)
    print(u is u1)  # False,u和u1不是同一个实例
    

    __contain__:in测试首先调用的特殊方法,下面自建了一个类似字典的Dict类,但是in测试测的是key,而不是values:

    class Dict:
    
        def __init__(self, **kwargs):
            self.map = kwargs
    
        def __contains__(self, item):
            if item in self.map.values():
                return True
    
    d = Dict(a=1, b=2) 
    print('a' in d)  # False
    print(1 in d)  # True
    

    2,操作需要支持的特殊方法

    序列:__len__,__getitem__

    切片:__getitem__

    迭代/元组拆包:1)__iter__;2)__getitem__(index从0开始)

    可散列:__hash__,__eq__

    in测试:1)__contains__;2)__iter__;3)__getitem__

    描述符:__set__,__get__,__delete__ (可部分实现)

    动态属性存取:__getattr__、__setattr__、__delattr__

    []分量存取:__getitem__、__setitem__、__delitem__

    运算符+= :1)__iadd__,2)__add__

    上下文管理器:__enter__,__exit__

     反向迭代:__reversed__

  • 相关阅读:
    CS01、CS02保存时增强的BADI(BOM_UPDATE)
    爱课程网(icourses.cn)的课件下载
    Java获取电脑盘符(最后一个盘符)
    打包后,配置文件找不到,json文件转java 实体对象
    前端vue history模式,后端nginx配置
    springboot 项目整合jsp文件,部署jar包
    安装node.js遇到的问题
    docker
    set up phpmyadmin with docker
    各类网络知识汇总
  • 原文地址:https://www.cnblogs.com/guxh/p/10263208.html
Copyright © 2020-2023  润新知