zoukankan      html  css  js  c++  java
  • 面向对象:类中的特殊方法

    一、前言

        类的特殊方法,其实就是遇到类代码特定的语法  然后去执行指定的特殊方法。只是一个对应的映射关系比如:

     

        这么多特殊方法,其实是为了不同的特定语法设计,大家都遵守这个约定。

        python内部根据特殊的语法帮我们映射到特殊的方法,里面的逻辑由我们自己实现

        当然你可以打破这个规定,比如__int__是转换成数字类型,你可以写成相加,但是强烈不推荐这样使用,不然你的代码只有你自己看得懂。别人看起来就费劲。

    二、各种特殊方法

    2.1 类与对象调用自动执行

    __init__

      类()  自动执行该方法,又叫构造函数,利用该特性,我们一般用来做封装

    __call__

      和__init__相对应。__call__是对象()自动运行该方法。

        __init__: 类()

        __call__:   对象()

    class Foo:
        def __call__(self):
            print('1')
    
    obj = Foo()
    obj()
    obj1 =Foo()()  # 也可以写成这种形式
    __call__ 用法

    __del__ 

      在其他语言中都有析构方法,python也有,但是我们在python中使用不到。

      因为python的内存管理机制是在 内存定时刷新,当检测到内存没人引用的时候,就自动销毁这块内存。

    2.2 类型转换语法相关

    __int__ 重点

      我们常常会把数字内容的字符串,转换为数字。 int('123')

      其实是类内部遇到这种形式,执行__int__方法,返回了一个数字。

      我们里面不一定就要返回数字,只是这是一个约定俗成的规定,大家都这样使用,不容易混淆。

    __str__ 重点

      __str__ 有两个作用:

        第一作用:跟__int__一样,遇见类型转换的格式自动执行该方法里面的内容。约定速成,转换为字符串

        第二作用:跟print一起使用,规范化输出,使其输出更明确,易懂。

    class Foo:
        def __init(self, name, age):
            self.name = name
            self.age = age
    
        def __str__(self):
            return self.name
    
    obj = Foo()
    print(obj)  # 其实经历了两个步骤,print(str(obj)). 
                # print 内部有个隐藏的str,要把类型先转换为字符串,
                # str(obj) 去obj类内部去调用__str__
                # 其实就是第一作用的衍生

    __dict__  重点

      __dict__并不算类型转换的一种。这里没地方归位了,先算在这里把。

      将对象和类中封装的内容,以字典的形式返回。对象与类都可以调用。

    class Foo:
        county = 'CN'
    
        def __init__(self, name, age):
            self.name = name
            self.age = age
            self.v = 1
            self.__a = '私有变量a'
    
        def __str__(self):
            return self.name
    
    obj = Foo('li', 18)
    print(obj.__dict__)  # 只打印与对象相关的成员
    print(Foo.__dict__)  # 打印方法,属性,特殊方法等等结果:
    {'name': 'li', 'age': 18, 'v': 1, '_Foo__a': '私有变量a'}
    {'__module__': '__main__', 'county': 'CN', '__init__': <function Foo.__init__ at 0x104edc488>, '__str__': <function Foo.__str__ at 0x104edc510>, '__dict__': <attribute '__dict__' of 'Foo' objects>, '__weakref__': <attribute '__weakref__' of 'Foo' objects>, '__doc__': None}

    还有其他一些关于类型转换,比如float,list 等等自己探索

    2.3 运算符重载语法相关

      obj1 + obj2 ,obj1 += obj2,obj1 - obj2,obj1 < obj2 ,obj = '3'

      上面这些都是运算符相关的。 都是特定的语法 映射到 指定的方法。中间的映射是python内部帮我们去掉用,但是特殊方法实现的逻辑由我们自己撰写。

      obj1 + obj2   映射到 __add__ 我们用这个来做示范。记得在字符串中,两个字符串可以相加吗?其实就是str类中由__eq__方法

    class Foo:
    
        def __init__(self, name,age):
            self.name = name
            self.age = age
    
        def __add__(self, other):
            ‘在内部我们想实现什么就实现什么’
            # self = obj1 (alex,19)
            # other = obj2(eric,66)
            # return self.age + other.age
            #return Foo('tt',99)
            return Foo(obj1.name, other.age)
    
    obj1 = Foo('alex', 19)
    obj2 = Foo('eirc', 66)
    
    r = obj1 + obj2

    2.4 索引与切片语法 重点

    索引语法 __getitem__ __setitem__ __delitem__  

    列表中有三种操作:
    li[3]    # 获取
    li[1] = 2   # 设置
    del li[2]   # 删除
    针对这三种特定的语法,类中有对应的三个特殊方法:__getitem__ __setitem__ __delitem__
    class Foo:
        def __init__(self, name, age):
            self.name = name
            self.age = age
    
        def __getitem__(self, item):
            return item + 10
        
        def __setitem__(self, key, value):
            print('我是设置', key, value)
        
        def __delitem__(self, key):
            print('我是删除', key)
        
    
    obj = Foo('li', 18)
    obj[1]       # 对用__getitem__
    obj[1] = 1   # 对应__setitem__
    del obj[10]  # 对用__delitem__

    切片语法:

      在python2中还有一个特殊方法映射切片语法,在python3中就已经取消了,还是用上面三者进行操作。

    class Foo:
        def __init__(self, name, age):
            self.name = name
            self.age = age
    
        def __getitem__(self, item):
            print(item, type(item))
            # return item + 10
    
    obj = Foo('li', 18)
    obj[1]      
    obj[1:6:3]

    结果:

    1 <class 'int'>
    slice(1, 6, 3) <class 'slice'>

      在上面输出可得知,当用于切片操作时候,传递进去的是 slice类型,这也是一个数据类型。

      我们看源码,可以使用各种方法,比如 help(slice) dir(slice)  或直接看源码。

      能发现三个比较有趣的东西:start,stop,step。 就进行尝试把。我们可以根据item的类型来进行判断。

    class Foo:
        def __init__(self, name, age):
            self.name = name
            self.age = age
    
        def __getitem__(self, item):
            if type(item) is int:
                print('索引处理', item)
            elif type(item) is slice:
                print('切片处理', item)
                print(item.start, item.stop, item.step)
     
    obj = Foo('li', 18)
    obj[1]      
    obj[1:6:3]
    
    运行结果:
    索引处理 1
    切片处理 slice(1, 6, 3)
    1 6 3

    这里讲解只对切片的__getitem__进行讲解,其他两个语法用法是差不多的。自己扩展。

     2.5 __iter__ 对于for语法

      __iter__对应的语法 为 for i in obj:

    在理解这个之前需要理解几个概念:迭代器的概念去目录中查找。

    # 迭代器与可迭代对象

      如果类中有__iter__方法,那这个类生成的对象为 可迭代对象
      对象.__iter__ 的返回值为 迭代器

    # for循环:
      1.如果遇到迭代器,则直接使用迭代器的next方法取值
      2.如果遇到可迭代对象,则需要两步:
          第1步:执行该对象类中的__iter__方法,获取返回值(返回值为迭代器)
          第2步:使用迭代器的next方法进行迭代

    理解了上面的概念以后,我们就可以为我们的对象进行循环了:

    class Foo:
        def __init__(self, name, age):
            self.name = name
            self.age = age
        
        def __iter__(self):
            return iter([1, 2, 3, 4])  # 注意此处需要返回一个迭代器,使用iter()把一个列表转换为迭代器对象
    
    obj = Foo('li', 18)
    for i in obj:
        print(i)
  • 相关阅读:
    try catch finally
    类的小练习
    易混淆概念总结
    C#中struct和class的区别详解
    Doing Homework again
    悼念512汶川大地震遇难同胞——老人是真饿了
    Repair the Wall
    Saving HDU
    JAVA-JSP隐式对象
    JAVA-JSP动作
  • 原文地址:https://www.cnblogs.com/louhui/p/8977051.html
Copyright © 2011-2022 走看看