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

一、前言

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

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

    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)

原文地址:https://www.cnblogs.com/louhui/p/8977051.html

时间: 2024-10-08 18:01:31

面向对象:类中的特殊方法的相关文章

php面向对象类中常用的魔术方法

php面向对象类中常用的魔术方法 1.__construct():构造方法,当类被实例化new $class时被自动调用的方法,在类的继承中可以继承与覆盖该方法,例: //__construct() class construct{ public function __construct(){ $this->var = "this is var"; } } class con2 extends construct{ public function __construct(){ $

基类中的虚方法到底有什么作用?

只有基类的方法加上关键字virtual后才可以被override,从而实现面向对象最重要的特征--多态性,即基类可以使用派生类的方法. C#中指出:普通的方法重载:指的是类中两个以上的方法(包括隐藏的,继承而来的方法)取的名字相同,只要使用的参数类型或者参数个数不同,编译器便知道在何种情况下应该调用哪个方法.   而在派生类中重新定义此虚函数时要求的是:方法名称.返回值类型.参数表中的参数个数.类型.顺序都必须与基类中的虚函数完全一致. 简单一点说就是子类中override的方法能够覆盖积累中的

Effective Java 第三版——16.在公共类中使用访问方法而不是公共属性

Tips <Effective Java, Third Edition>一书英文版已经出版,这本书的第二版想必很多人都读过,号称Java四大名著之一,不过第二版2009年出版,到现在已经将近8年的时间,但随着Java 6,7,8,甚至9的发布,Java语言发生了深刻的变化. 在这里第一时间翻译成中文版.供大家学习分享之用. 16. 在公共类中使用访问方法而不是公共属性 有时候,你可能会试图写一些退化的类(degenerate classes),除了集中实例属性之外别无用处: // Degene

PHP中的面向对象OOP中的魔术方法

一.什么是魔术方法: PHP为我们提供了一系列用__开头的函数,这些函数无需自己手动调用,会在合适的时机自动调用,这类函数称为魔术函数.例如: function __construct(){} 在new一个新对象时自动调用此函数 二.PHP中都有那些魔术方法,以及它们的作用:1.__construct():构造函数,new对象时自动调用 eg: class Person{ public $name; public $age; function __construct($name,$age){ $

Java线程状态及Thread类中的主要方法

要想实现多线程,就必须在主线程中创建新的线程对象. 任何线程一般具有5种状态,即创建,就绪,运行,阻塞,终止. 创建状态: 在程序中用构造方法创建了一个线程对象后,新的线程对象便处于新建状态,此时,他已经有了相应的内存空间和其他资源,但还处于不可运行状态. 就绪状态: 新建线程对象后,调用该线程的start()方法可以启动线程.当线程启动时,线程进入就绪状态.此时,线程将进入线程队列排队,等待CPU服务,这表明它已经具备了运行条件.-------(运行start()方法只是进入就绪状态,并没有开

14 在公有类中使用访问方法而非公有域

class Point{ public double x; public double y; } 对于可变的类来说,应该用包含私有域和公有设值方法的类来代替: class Point{ private double x; private double y; Point(double x, double y) { this.x = x; this.y = y; } double getX() { return x; } void setX(double x) { this.x = x; } dou

StringBuilder类中的重要方法

下面的API注解包含了StringBuilder类中的重要方法 append(boolean b):将 boolean 参数的字符串表示形式追加到序列. append(char c):将 char 参数的字符串表示形式追加到此序列. append(char[] str):将 char 数组参数的字符串表示形式追加到此序列. append(char[] str,int offset,int len):将 char 数组参数的子数组的字符串表示形式追加到此序列. append(CharSequenc

PHP通过反射方法调用执行类中的私有方法

PHP 5 具有完整的反射 API,添加了对类.接口.函数.方法和扩展进行反向工程的能力. 下面我们演示一下如何通过反射,来调用执行一个类中的私有方法: <?php //MyClass这个类中包含了一个名为myFun的私有方法class MyClass {        private $tmp = 'hello';        private function myFun()    {        echo $this->tmp . ' ' . 'world!';    }} //通过类

问题1、java.lang中String类和Object类中的equals方法比较

String类中的equals方法重写了Object类中的equals方法,下面通过代码来比较二者的不同之处: 一.String类 1. String s1 = "String"; String s2 = "String"; System.out.println(s1 == s2 ); System.out.println(s1.equals(s2));