Python从进阶到高级—通俗易懂版(三)

# ==================================
# Author : Mikigo
# Env    :deepin 20.4 os
# ==================================

1、破解私有属性

私有属性就是在类的内部能访问,外部不能访问。

在 Python 中没有专门的语句进行私有化,而通过在属性或方法前面加“两个下划线”实现。

举例:

class Test:

    def __init__(self):
        self.__mi = "Mikigo" 

    def __ki(self):
        print("Mikigo")
        
    def go(self):
        print(self.__mi)
Test().go()
Mikigo

你看,在类的内部访问私有属性是可以正常拿到的,方法也是一样的。

现在我们访问私有属性试试:

Test().__mi
Traceback (most recent call last):
  File "/tmp/pycharm_project_609/123.py", line 6, in <module>
    print(Test().__mi)
AttributeError: 'Test' object has no attribute '__mi'

从外部进行私有属性访问是不行的,人家是私有的。

Test().__ki()
Traceback (most recent call last):
  File "/tmp/pycharm_project_609/123.py", line 9, in <module>
    Test().__ki()
AttributeError: 'Test' object has no attribute '__ki'

私有方法也无法访问,没问题哈。

有同学要问了,我就是想访问,越是私有的我越想看,怎么才能看到别人的隐私,快说!

泄露天机了哈,这是 Python 一种很奇妙的结构化处理,为什么说是结构化处理,实际上 Python 拿到双下划线之后,对其进行了变形,在前面加了一个下划线和类名,我们通过这种方式可以访问:

print(Test()._Test__mi)
Test()._Test__ki()
Mikigo
Mikigo

你看,这样就可以正常访问了,但是既然作者不希望使用者调用这个方法,我们也尽量不要去强行使用它,强扭的瓜不甜。

所以说,从语言的角度是没有绝对的安全,任何语言都是这样,更多的是一种编程上的约束。

通常在大多数实践中,我们更倾向于使用一个下划线来表示私有属性,这不是真正的私有,而是一种更友好的编程规范,社区称之为 “受保护的”属性,它向使用着表达了这是一个私有的方法,但是你仍然可以使用它,这就是社区,这就是开源,respect~。

2、对象的自省机制

自省(introspection),即自我反省,而对象的自省实际上就是查看对象实现了哪些属性或方法。

简单讲就是,告诉别人:我是谁,我能干啥

Python 的常用的自省函数有四个:dir()、type()、 hasattr()、isinstance()

(1)isinstance() 和 type() 前面也提到过,这里不讲了。

(2)dir() 是最为常用的一个自省函数:

引用前面的 Test 类

print(dir(Test))
['_Test__ki', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'go']

除了 _Test__kigo 方法以外,其他的方法都是魔法函数,即最开始我们提到的协议,你看随便一个对象就实现了这么多协议,是不是很神奇。

(3)hasattr() 主要用于判断对象中是否包含某个属性,返回布尔值。

print(hasattr(Test, "go"))
print(hasattr(Test, "wo"))
True
False

很简单,不多讲哈。

其他还有一些自省函数可以了解一下,偶尔用到也挺好的:

  • __doc__ 获取到文档字符串;
  • __name__ 获取对象的名称;
  • __dict__ 包含了类里可用的属性名-属性的字典;
  • __bases__ 返回父类对象的元组;但不包含继承树更上层的其他类。

3、super

super 函数是用于调用父类的一个方法。

class A:

    def mi(self):
        print("=== mi ===")

class B(A):

    def ki(self):
        super().mi()
B().ki()
=== mi ===

super 的使用方法是很简单的,但是如果涉及到多继承的情况下,就要小心处理。

准确的讲它不是调用父类的方法,而是调用的 MRO 顺序上的下一个方法。

4、上下文管理器

在讲到上下文管理器的时候,经常有同学一脸懵,然后我说 with 的时候,就会脱口而出 with open

没错,with 语句用得最多的也是这个,它是 Python 提供的一种处理资源回收的神奇方法,如果没有 with 我们可能需要多写很多代码。

大家都知道打开一个文件之后是需要关闭的,但是在操作文件的过程中很容易报错,这时候我们需要进行异常处理,要保证无论是否存在异常的情况下,文件都能正常的被关闭,我们几乎只能使用try里面的finally来处理:

f = open("test.txt", "w")
try:
    f.write(some_txt)
except:
    pass
finally:
    f.close()

如果用 with 语句处理就会很简单:

with open("test.txt", "w") as f:
    f.write(some_txt)

对比起来,哪个更好不用多说,自己品。

在《流畅的 Python》这本书里面提到:

在任何情况下,包括CPython,最好显式关闭文件;而关闭文件的最可靠方式是使用with语句,它能保证文件一定会被关闭,即使打开文件时抛出了异常也无妨。

那我们如何实现一个上下文管理器呢?

  • 基于类实现上下文管理器

要实现上下文管理器,需要实现两个魔法函数:__enter____exit__

看名称就知道了,enter 就是进入的时候要做的事情,exit 就是退出的时候要做的事情,很好记有没有。

class Context:

    def __init__(self, file_name):
        self.file_name = file_name
        self.f = None

    def __enter__(self):
        print("进入 with")
        self.f = open(self.file_name, "r")
        return self.f

    def __exit__(self, exc_type, exc_val, exc_tb):
        print("退出 with")
        if self.f:
            self.f.close()

然后我们就可以使用 with 语句

with Context("test.txt") as f:
    print(f.read())
进入 with
我是一个测试文件
退出 with

完美哈,一个上下文管理器的类就轻松搞定。

  • 基于 contextlib 实现上下文管理器

还有种通过标准库实现上下文管理器的方法:

from contextlib import contextmanager

@contextmanager
def context_test(file_name):
    print("进入 with")
    try:
        f = open(file_name, "r")
        yield f
    finally:
        print("退出 with")
        f.close()

来用 with 玩耍一下

with context_test("test.txt") as f:
    print(f.read())
进入 with
我是一个测试文件
退出 with

利用生成器的原理,yield 之前是进入,yield 之后是退出,同样可以实现一个上下文管理器,稍微理解一下哈。

上下文管理器是 Python 提供给我们的一个非常方便且有趣的功能,经常被用在打开文件、数据库连接、网络连接、摄像头连接等场景下。如果你经常做一些固定的开始和结尾的动作,可以尝试一下。

posted @ 2022-10-21 11:37  mikigo  阅读(104)  评论(0编辑  收藏  举报