zoukankan      html  css  js  c++  java
  • python面向对象中的一些特殊__方法__

    1. __doc__

    表示类的描述信息

    class Foo:
        """ 描述类信息"""
    
        def func(self):
            pass
    
    print (Foo.__doc__)
    #输出:类的描述信息

    2. __module__ 和  __class__ 

    __module__ 表示当前操作的对象在那个模块

    __class__     表示当前操作的对象的类是什么

    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
    
    class C:
    
        def __init__(self):
            self.name = 'maple'
    
    lib/aa.py
    from lib.aa import C
    
    obj = C()
    print (obj.__module__)  # 输出 lib.aa,即:输出模块
    print (obj.__class__ )     # 输出 lib.aa.C,即:输出类

    3. __init__

    构造方法,通过类创建对象时,自动触发执行。

    class Foo:
    
        def __init__(self, name):
            self.name = name
            self.age = 18
    
    
    obj = Foo('maple') # 自动执行类中的 __init__ 方法

    4. __del__

    析构方法,当对象在内存中被释放时,自动触发执行。

    注:此方法一般无须定义,因为Python是一门高级语言,程序员在使用时无需关心内存的分配和释放,因为此工作都是交给Python解释器来执行,所以,析构函数的调用是由解释器在进行垃圾回收时自动触发执行的。

    class Foo:
    
        def __del__(self):
            pass

    5. __call__

    对象后面加括号,触发执行。

    注:构造方法的执行是由创建对象触发的,即:对象 = 类名() ;而对于 __call__ 方法的执行是由对象后加括号触发的,即:对象() 或者 类()()

    class Foo:
    
        def __init__(self):
            pass
        
        def __call__(self, *args, **kwargs):
    
            print ('__call__')
    
    
    obj = Foo() # 执行 __init__
    obj()       # 执行 __call__

    6. __dict__

    类或对象中的所有成员

    class Province:
    
        country = 'China'
    
        def __init__(self, name, count):
            self.name = name
            self.count = count
    
        def func(self, *args, **kwargs):
            print ('func')
    
    # 获取类的成员,即:静态字段、方法、
    print (Province.__dict__)
    # 输出:{'country': 'China', '__module__': '__main__', 'func': <function func at 0x10be30f50>, '__init__': <function __init__ at 0x10be30ed8>, '__doc__': None}
    
    obj1 = Province('HeBei',10000)
    print (obj1.__dict__)
    # 获取 对象obj1 的成员
    # 输出:{'count': 10000, 'name': 'HeBei'}
    
    obj2 = Province('HeNan', 3888)
    print (obj2.__dict__)
    # 获取 对象obj1 的成员
    # 输出:{'count': 3888, 'name': 'HeNan'}

    7. __str__

    如果一个类中定义了__str__方法,那么在打印 对象 时,默认输出该方法的返回值

    class Foo:
    
        def __str__(self):
            return 'maple'
    
    
    obj = Foo()
    print (obj)
    # 输出:maple

    8、__getitem__、__setitem__、__delitem__

    用于索引操作,如字典。以上分别表示获取、设置、删除数据

    class Foo(object):
     
        def __getitem__(self, key):
            print ('__getitem__',key)
     
        def __setitem__(self, key, value):
            print ('__setitem__',key,value)
     
        def __delitem__(self, key):
            print ('__delitem__',key)
     
     
    obj = Foo()
     
    result = obj['k1']      # 自动触发执行 __getitem__
    obj['k2'] = 'maple'   # 自动触发执行 __setitem__
    del obj['k1']           # 自动触发执行 __delitem__

    9、__getslice__、__setslice__、__delslice__

    该三个方法用于分片操作,如:列表

    class Foo(object):
     
        def __getslice__(self, i, j):
            print ('__getslice__',i,j)
     
        def __setslice__(self, i, j, sequence):
            print ('__setslice__',i,j)
     
        def __delslice__(self, i, j):
            print ('__delslice__',i,j)
     
    obj = Foo()
     
    obj[-1:1]                   # 自动触发执行 __getslice__
    obj[0:1] = [11,22,33,44]    # 自动触发执行 __setslice__
    del obj[0:2]                # 自动触发执行 __delslice__

    10. __iter__ 

    用于迭代器,之所以列表、字典、元组可以进行for循环,是因为类型内部定义了 __iter__ 

    class Foo(object):
        pass
    
    
    obj = Foo()
    
    for i in obj:
        print (i)
        
    # 报错:TypeError: 'Foo' object is not iterable
    
    第一步
    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
    
    class Foo(object):
        
        def __iter__(self):
            pass
    
    obj = Foo()
    
    for i in obj:
        print (i)
    
    # 报错:TypeError: iter() returned non-iterator of type 'NoneType'
    
    第二步
    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
    
    class Foo(object):
    
        def __init__(self, sq):
            self.sq = sq
    
        def __iter__(self):
            return iter(self.sq)
    
    obj = Foo([11,22,33,44])
    
    for i in obj:
        print (i)
    
    第三步

    以上步骤可以看出,for循环迭代的其实是  iter([11,22,33,44]) ,所以执行流程可以变更为:

    obj = iter([11,22,33,44])
     
    for i in obj:
        print (i)
    obj = iter([11,22,33,44])
    
    while True:
        val = obj.next()
        print (val)
    
    For循环语法内部

    11. __new__ 和 __metaclass__

    阅读以下代码:

    class Foo(object):
     
        def __init__(self):
            pass
     
    obj = Foo()   # obj是通过Foo类实例化的对象

    上述代码中,obj 是通过 Foo 类实例化的对象,其实,不仅 obj 是一个对象,Foo类本身也是一个对象,因为在Python中一切事物都是对象

    如果按照一切事物都是对象的理论:obj对象是通过执行Foo类的构造方法创建,那么Foo类对象应该也是通过执行某个类的 构造方法 创建。

    print type(obj) # 输出:<class '__main__.Foo'>     表示,obj 对象由Foo类创建
    print type(Foo) # 输出:<type 'type'>              表示,Foo类对象由 type 类创建

    所以,obj对象是Foo类的一个实例Foo类对象是 type 类的一个实例,即:Foo类对象 是通过type类的构造方法创建。

    那么,创建类就可以有两种方式:

    a). 普通方式

    class Foo(object):
     
        def func(self):
            print ('hello maple')

    b).特殊方式(type类的构造函数)

    def func(self):
        print ('hello maple')
     
    Foo = type('Foo',(object,), {'func': func})
    #type第一个参数:类名
    #type第二个参数:当前类的基类
    #type第三个参数:类的成员

    ==》 类 是由 type 类实例化产生

    那么问题来了,类默认是由 type 类实例化产生,type类中如何实现的创建类?类又是如何创建对象?

    答:类中有一个属性 __metaclass__,其用来表示该类由 谁 来实例化创建,所以,我们可以为 __metaclass__ 设置一个type类的派生类,从而查看 类 创建的过程。

    class MyType(type):
    
        def __init__(self, what, bases=None, dict=None):
            super(MyType, self).__init__(what, bases, dict)
    
        def __call__(self, *args, **kwargs):
            obj = self.__new__(self, *args, **kwargs)
    
            self.__init__(obj)
    
    class Foo(object):
    
        __metaclass__ = MyType
    
        def __init__(self, name):
            self.name = name
    
        def __new__(cls, *args, **kwargs):
            return object.__new__(cls, *args, **kwargs)
    
    # 第一阶段:解释器从上到下执行代码创建Foo类
    # 第二阶段:通过Foo类创建obj对象
    obj = Foo()

    12.__repr__

    在python解释器环境下,会默认显示对象的repr表示。

    >>> class Student:
    ...     def __init__(self, name, age):
    ...         self.name = name
    ...         self.age = age
    ...     def __repr__(self):
    ...         return self.name
    ... 
    >>> s1 = Student('张三', 24)
    >>> s1
    张三

    总结:

    str函数或者print函数调用的是obj.__str__()
    repr函数或者交互式解释器调用的是obj.__repr__()

    注意:
    如果__str__没有被定义,那么就会使用__repr__来代替输出。
    __str__和__repr__方法的返回值都必须是字符串。

    13.__format__

    class Student:
        def __init__(self, name, age):
            self.name = name
            self.age = age
    
        __format_dict = {
            'n-a': '名字是:{obj.name}-年龄是:{obj.age}',  # 名字是:maple-年龄是:18
            'n:a': '名字是:{obj.name}:年龄是:{obj.age}',  # 名字是:maple:年龄是:18
            'n/a': '名字是:{obj.name}/年龄是:{obj.age}',  # 名字是:/年龄是:18
        }
    
        def __format__(self, format_spec):
            if not format_spec or format_spec not in self.__format_dict:
                format_spec = 'n-a'
            fmt = self.__format_dict[format_spec]
            print(fmt) #{obj.name}:{obj.age}
            return fmt.format(obj=self)
    
    s1 = Student('maple', 24)
    ret = format(s1, 'n/a')
    print(ret)  # maple/24

    14.__item__

    class Foo:
        def __init__(self, name):
            self.name = name
    
        def __getitem__(self, item):
            print(self.__dict__[item])
    
        def __setitem__(self, key, value):
            print('obj[key]=maple赋值时,执行我')
            self.__dict__[key] = value
    
        def __delitem__(self, key):
            print('del obj[key]时,执行我')
            self.__dict__.pop(key)
    
        def __delattr__(self, item):
            print('del obj.key时,执行我')
            self.__dict__.pop(item)
    
    
    f1 = Foo('sb')
    print(f1.__dict__)
    f1['age'] = 18
    f1.hobby = '泡妞'
    del f1.hobby
    del f1['age']
    f1['name'] = 'maple'
    print(f1.__dict__)

    15.__new__

    其实__init__是在类实例被创建之后调用的,它完成的是类实例的初始化操作,而 __new__方法正是创建这个类实例的方法

    class Person:
    
        def __new__(cls, *args, **kwargs):
            print('调用__new__,创建类实例')
            return super().__new__(Person)
    
        def __init__(self, name, age):
            print('调用__init__,初始化实例')
            self.name = name
            self.age = age
    
        def __str__(self):
            return '<Person: {}({})>'.format(self.name, self.age)
    
    p1 = Person('张三', 24)
    print(p1)

    输出:

    调用__new__,创建类实例
    调用__init__,初始化实例
    <Person: 张三(24)>

    __new__方法在类定义中不是必须写的,如果没定义的话默认会调用object.__new__去创建一个对象(因为创建类的时候默认继承的就是object)。

    如果我们在类中定义了__new__方法,就是重写了默认的__new__方法,我们可以借此自定义创建对象的行为。

    举个例子:

    重写类的__new__方法来实现单例模式。

    class Singleton:
        # 重写__new__方法,实现每一次实例化的时候,返回同一个instance对象
        def __new__(cls, *args, **kw):
            if not hasattr(cls, '_instance'):
                cls._instance = super().__new__(Singleton)
            return cls._instance
    
        def __init__(self, name, age):
            self.name = name
            self.age = age
    
    
    s1 = Singleton('张三', 24)
    s2 = Singleton('李四', 20)
    print(s1, s2)  # 这两实例都一样
    print(s1.name, s2.name)

    16.__enter__和__exit__

    一个对象如果实现了__enter__和___exit__方法,那么这个对象就支持上下文管理协议,即with语句

    class A:
        def __enter__(self):
            print('进入with语句块时执行此方法,此方法如果有返回值会赋值给as声明的变量')
            return 'oo'
    
        def __exit__(self, exc_type, exc_val, exc_tb):
            print('退出with代码块时执行此方法')
            print('1', exc_type)
            print('2', exc_val)
            print('3', exc_tb)
    
    with A() as f:
        print('进入with语句块')
        # with语句中代码块出现异常,则with后的代码都无法执行。
        # raise AttributeError('sb')
        print(f) #f打印出oo
    print('嘿嘿嘿')

    上下文管理协议适用于那些进入和退出之后自动执行一些代码的场景,比如文件、网络连接、数据库连接或使用锁的编码场景等

    17.__len__

    拥有__len__方法的对象支持len(obj)操作。

    class A:
        def __init__(self):
            self.x = 1
            self.y = 2
    
        def __len__(self):
            return len(self.__dict__)
    
    a = A()
    print(len(a))

    18.__hash__

    拥有__hash__方法的对象支持hash(obj)操作。

    class A:
        def __init__(self):
            self.x = 1
            self.x = 2
    
        def __hash__(self):
            return hash(str(self.x) + str(self.x))
    
    a = A()
    print(hash(a))

    19.__eq__

    拥有__eq__方法的对象支持相等的比较操作

    class A:
        def __init__(self,x,y):
            self.x = x
            self.y = y
    
        def __eq__(self,obj):
            # 打印出比较的第二个对象的x值
            print(obj.x)
            if self.x +self.y == obj.x+obj.y:
                return True
            else:
                return False
    
    a = A(1,2)
    b = A(2,1)
    print(a == b)

    20.描述符(__get__,__set__,__delete__)

    1 描述符是什么:描述符本质就是一个新式类,在这个新式类中,至少实现了__get__(),__set__(),__delete__()中的一个,这也被称为描述符协议
    __get__():调用一个属性时,触发
    __set__():为一个属性赋值时,触发
    __delete__():采用del删除属性时,触发

    class Foo(): #在python3中Foo是新式类,它实现了三种方法,这个类就被称作一个描述符
        def __get__(self, instance, owner):
            pass
        def __set__(self, instance, value):
            pass
        def __delete__(self, instance):
            pass
    
    定义一个描述符

    2 描述符是干什么的:描述符的作用是用来代理另外一个类的属性的(必须把描述符定义成这个类的类属性,不能定义到构造函数中)

    #描述符Str
    class Str:
        def __get__(self, instance, owner):
            print('Str调用')
        def __set__(self, instance, value):
            print('Str设置...')
        def __delete__(self, instance):
            print('Str删除...')
    
    #描述符Int
    class Int:
        def __get__(self, instance, owner):
            print('Int调用')
        def __set__(self, instance, value):
            print('Int设置...')
        def __delete__(self, instance):
            print('Int删除...')
    
    class People:
        name=Str()
        age=Int()
        def __init__(self,name,age): #name被Str类代理,age被Int类代理,
            self.name=name
            self.age=age
    
    #何地?:定义成另外一个类的类属性
    
    #何时?:且看下列演示
    
    p1=People('ffm',18)
    
    #描述符Str的使用
    p1.name
    p1.name='maple'
    del p1.name
    
    #描述符Int的使用
    p1.age
    p1.age=18
    del p1.age
    
    #我们来瞅瞅到底发生了什么
    print(p1.__dict__)
    print(People.__dict__)
    
    #补充
    print(type(p1) == People) #type(obj)其实是查看obj是由哪个类实例化来的
    print(type(p1).__dict__ == People.__dict__)
    
    描述符应用之何时?何地?

    3 描述符分两种
    一 数据描述符:至少实现了__get__()和__set__()

    class Foo:
        def __set__(self, instance, value):
            print('set')
        def __get__(self, instance, owner):
            print('get')

    二 非数据描述符:没有实现__set__()

    class Foo:
        def __get__(self, instance, owner):
            print('get')

    4 注意事项:
    一 描述符本身应该定义成新式类,被代理的类也应该是新式类
    二 必须把描述符定义成这个类的类属性,不能为定义到构造函数中
    三 要严格遵循该优先级,优先级由高到底分别是
    1.类属性
    2.数据描述符
    3.实例属性
    4.非数据描述符
    5.找不到的属性触发__getattr__()

    类属性>数据描述符

    数据描述符>实例属性

    实例属性>非数据描述符

    非数据描述符>找不到

    利用描述符原理完成一个自定制的@staticmethod

    class StaticMethod:
        def __init__(self,func):
            self.func=func
    
        def __get__(self, instance, owner): #类来调用,instance为None,owner为类本身,实例来调用,instance为实例,owner为类本身,
            def feedback(*args,**kwargs):
                print('在这里可以加功能啊...')
                return self.func(*args,**kwargs)
            return feedback
    
    class People:
        @StaticMethod# say_hi=StaticMethod(say_hi)
        def say_hi(x,y,z):
            print('------>',x,y,z)
    
    People.say_hi(1,2,3)
    
    p1=People()
    p1.say_hi(4,5,6)
    
    自己做一个@staticmethod
  • 相关阅读:
    Centos系统通过tar.gz包安装Mysql5.7
    每日编程系列——洗牌
    每日编程系列——硬币找零
    每日编程系列———计算糖果
    每日编程系列———买苹果
    每日编程系列———最大奇约数
    Java包装类缓存
    每日编程系列——数字翻转
    Java自动装箱和拆箱
    Java中日志框架使用
  • 原文地址:https://www.cnblogs.com/angelyan/p/10366961.html
Copyright © 2011-2022 走看看