面向对象:类中的特殊方法

一、前言

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

 

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

    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)

 

posted @ 2018-05-01 18:47  娄先生  阅读(1173)  评论(0编辑  收藏  举报
levels of contents