![08db19569a6840f8d5a7a808fcb9faf2.png](https://img-blog.csdnimg.cn/img_convert/08db19569a6840f8d5a7a808fcb9faf2.png)
如果说Python的世界里,程序员就是上帝与造物主,万物皆为对象,那么类就是产生对象的母体,而类的私有方法可以说是造物主为了母体在生产对象时更加高效与便捷而创造的魔法师。
造物主为每一个类都配置了这么一个魔法师,以便于类更好的描述这个世界。
关于类的私有方法,我们通常见到它们都是被两个下划线包裹起来,显得那么卓然而立,孤傲不群像个中世纪的魔法师一样穿一身华丽的衣袍把自己裹起来,再带个宽檐帽。不过在计算机世界里这身袍子和宽檐帽有点不值钱,几个下划线就打发了。
这么看起来法师带的宽檐帽倒是挺像两个下划线的。
今天,我们主要讲Python类的私有方法。
主要知识点:
- 类的私有方法理解
- 类的私有成员变量
- 常用私有方法介绍
类的私有方法理解
类的私有方法理解class Student: def __init__(self): """初始化方法""" self.name = '龙傲天' def show_name(self): print(self.name) student = Student()student.show_name()
通过以上的代码我们看到了程序员设计了一个Student的类,并且写了两个方法。
__init__ 很明显就是私有方法,作用是在类进行实例化时自动进行一些初始化的操作(例如设置成员变量信息),这个我们在前一章已经简单的提到了。
私有方法不需要显式的调用,意思是它不需要通过实例化对象名 ojb.方法名() 这样的方式调用,二是在我们操作实例对象的时候,根据不同的情景自动运行。
show_name方法就是普通方法,用于在被显式调用 obj.show_name() 时打印当前成员变量 name,
我们先来看看代码运行结果。
![07b2776f61f85e4f1dc3326cd2c77ccd.png](https://img-blog.csdnimg.cn/img_convert/07b2776f61f85e4f1dc3326cd2c77ccd.png)
__init__ 方法在这其中发挥了很大的用处,不过我们从实例化对象的使用上基本没感受到它的存在。
那么__init__方法是不是类在被实例化的时候自动调用的第一个方法呢?将来可能在面试Python程序员时考官会问到这种无聊的问题,我们可以先回答他说不是。
__new__才是最早被自动调用的内部方法,实际上是由 __new__ 来调用的 __init__。
这个问题我们需要将来在讲高级教程时深入到类的生命周期时去讲,在这里我们记住 __new__ 比 __init__ 更早被调用就是了。
事实上,我们在编程时为什么要使用私有方法,我就算不用初始化方法一样可以用其他普通方法给对象设置成员变量啊,私有方法它究竟能带来什么好处?这才是萦绕在我们心头的一个问题,作者你说魔法就魔法了,它怎么个魔法,你来个例子吧。
光说不练假把式,我们来个实际例子。
__add__ 方法
![d5485a4d3b43377b178e9a20e6e9d7a9.png](https://img-blog.csdnimg.cn/img_convert/d5485a4d3b43377b178e9a20e6e9d7a9.png)
以上代码,我们设计了两个几乎一摸一样的类,除了名字不同之外。
然后在初始化类的时候分别传入了参数进去,一个是数字1、一个是数字2。A和B两个类分别接收到这些参数并作为自己的成员变量value。
然后重点来了,首先我们重写了__add__这个私有方法,它的作用是当对象被用来做 “左加” 时(左加可以视为两个类型相加),自动被调用。
我们看到两个类的__add__方法里都写着用自己的成员变量value+obj.value,这个obj默认就是被加的对象,而obj.value自然就表示是被加的对象里成员变量value。
那么我们可以通过简单的对象的加法 a+b 得到结果 3,是不是很神奇?
至于说后面两种成员变量相加和显式调用方法相加两种方式我就不详细介绍了,仅仅是用来举例。
我们可以看到用私有方法可以让代码变得更加优雅,少量但是简单容易理解的代码完成复杂的事情,这也是Python这门语言一直以来的追求之一。
其实在这里有个疑点,那就是为什么我说我们是重写了__add__这个私有方法呢?因为它本身就存在,我们相当于用自定义的代码覆盖了类的私有方法,下面我们来看看如果不重写方法会是什么样的。
![26379a2c75dc707b8057fc3f625c12b3.png](https://img-blog.csdnimg.cn/img_convert/26379a2c75dc707b8057fc3f625c12b3.png)
哦豁,报错提示我们,不支持加法操作。
通过这个简单的例子,我们可以这么理解,在Python的私有方法里,很多是需要重写特定的代码才能实现我们想要的效果的,它被定义成私有方法只是在特定的位置会被调用,但并不意味着它已经自动帮我们写好了代码,这些操作都需要我们自己去写代码实现。
通过 __add__ 方法我们了解到了Python私有方法的魅力所在,那么接下来我们就多介绍一些常用的私有方法吧。
__setattr__和___getattr__
这两个双胞胎通常一起出现在私有方法里,作用是用于设置类的成员变量,而类的所有成员变量其实是存在一个叫做___dict___的成员变量里,还是用代码来说明一切吧。
![7262a4e84c9a53bcbc22b1e2680c203d.png](https://img-blog.csdnimg.cn/img_convert/7262a4e84c9a53bcbc22b1e2680c203d.png)
当我们在向对象的成员变量进行取值和赋值时,实际上是调用了对象的 __setattr__和__getattr__ 方法。
当我们对这两个方法分别进行重写时,实际上是在对 __dict__这个类的内部成员变量进行操作。
没错,类同样由内部成员变量,比如这个 __dict__,顾名思义,它实质上就是一个字典,用于存储所有的成员变量信息。
至于__setattr__和__getattr__ 的参数,我们现在可以简单的理解它的格式是固定的。
__setattr__需要两个参数,分别是键和值,__getattr__只需要键,参数多了少了都会报错,这是由Python类的语法所规定好的,我们不能去随意更改。
绝大部分的私有方法的参数类型和格式都是预设的,我们不能随意增减,最多能定义变量名而已。
__doc__
这个私有成员变量用于表示类的描述信息
class Foo: """ 我是Foo类的描述信息,可以用过__doc__获取到 """ print(Foo.__doc__)
![d40c51b20f6732091aa7234cb79f1564.png](https://img-blog.csdnimg.cn/img_convert/d40c51b20f6732091aa7234cb79f1564.png)
__str__
如果在类里实现了该方法,当打印对象时,会输出该方法内的return值。
class Foo: def __str__(self): return 'Foo class信息'foo = Foo()print(foo)
![1d8e8475b2aeff4a360b9950aba20ebd.png](https://img-blog.csdnimg.cn/img_convert/1d8e8475b2aeff4a360b9950aba20ebd.png)
__repr__
该方法实现的功能和__str__是一样的,如果两个方法同时存在是,程序只会调用__str__,在没有__str__时才会调用__repr__。
![f3385952ebb036f2100be39c73eb9199.png](https://img-blog.csdnimg.cn/img_convert/f3385952ebb036f2100be39c73eb9199.png)
我们在最开始说到可以通过__add__来进行加法,那么有没有比较操作符相关的私有方法呢,当我希望对比两个对象的时候。当然有!我们可以通过操作比较运算符的一系列方法来实现目的。
比较运算符的私有方法
![41f4217f968aaa7a8c04aaa5eead706e.png](https://img-blog.csdnimg.cn/img_convert/41f4217f968aaa7a8c04aaa5eead706e.png)
以上是比较运算符的私有方法介绍,我们来尝试写一个可以工作的。
def __gt__(self, obj): return self.value > obj.value
以上这段代码的意思是返回当前类的value值是否大于目标类的value值,理论上来说会返回一个布尔值对象 (True或者False)。
来看看全部代码和结果。
![c1bab8f63bc46df2ef5fd6f9f74353e9.png](https://img-blog.csdnimg.cn/img_convert/c1bab8f63bc46df2ef5fd6f9f74353e9.png)
嗯,程序如实的反应了正确的比较结果,下面我们来皮一下,修改一下__gt__的输出结果。
![04f8f0d57b057981b334d03c49a3d456.png](https://img-blog.csdnimg.cn/img_convert/04f8f0d57b057981b334d03c49a3d456.png)
通过以上代码我们可以发现,当我们在返回的比较表达式前面加上一个not语句后,就把结果反过来了。原来为真的变成了假,原来是假的变成了真。真亦假来假亦真,是不是有种禅意,阿基米德的棺材板都按不住了。
![5550a6ad8f705758d00ebbcb16064171.png](https://img-blog.csdnimg.cn/img_convert/5550a6ad8f705758d00ebbcb16064171.png)
输出结果我们可以看到,重写了__gt__ 方法的内容后,我们强行篡改了原本正确的逻辑,同样我们也可以通过修改别的私有方法去篡改原本符合直觉的逻辑。
在这里不是鼓励大家去故意干这样的事情,而是为了提醒大家,在用到私有方法时,需要注意代码的正确性,否则很容易在进行对象操作时出现问题。
加减乘除的私有方法
之前提到的用于进行加法的__add__私有方法,那么它的兄弟姐们还有以下。
__add__ # 用于加法 __sub__ # 用于减法__mul__ # 用于乘法__truediv__ #用于除法
以下是这几个方法的实现代码案例,感兴趣的朋友可以自行运行研究。
# 加法 def __add__(self, obj): return self.value+obj.value # 减法 def __sub__(self, obj): return self.value-obj.value # 乘法 def __mul__(self,obj): return self.value*obj.value # 除法 def __truediv__(self,obj): return self.value/obj.value
总结
聪明的你一定会想到,我们可以对这些私有方法进行重写,然后优化其输出结果,比如对所有除法进行自动四舍五入操作再返回,避免每次做除法都需要四舍五入。
关于Python类的私有方法暂时就讲到这,其实本章知识也只能起一个抛砖引玉的作用,要延展开来讲还需要讲很多东西,包括对象的生命周期,如何进行垃圾回收,元类等等。
这些余下的内容我们将在另一个系列《Pyton进阶教程》中提到,在基础教程里就不让再给大家添加更多的困惑了。
我们在现阶段只需要明白Pyhton类的私有方法能干以下几件事情。
- 新建当前类本身不支持的操作
- 重写类的基本操作
- 让类的代码变得优雅
- 更好的抽象现实世界
类的私有方法有很多好处,但是我们并不是为了使用而使用,仅仅在恰当的时候使用它即可,其实很多时候我们完全不需要它们一样可以设计类,只不过我们需要做的它们正确的用处就是了。
欢迎关注我 “纸飞机编程”,获取更多有趣的python教程信息。