Python高级语法5:私有属性、魔法属性、with与上下文管理器

简介: Python高级语法5:私有属性、魔法属性、with与上下文管理器

一、私有属性



  • 我们大家知道在类里面定义的属性名前加两个下划线就是私有属性,它是不能在外面被访问的,如下:


class Person(object):
      def __init__(self,name):
            self.__name = name
person = Person("小王")
print(person.__name)
  • 打印结果:报错,__name是私有的,外面是无法访问的


AttributeError: 'Person' object has no attribute '__name'
  • 分析上面报错的原因是:__name被Python改了名字,一种假象而已,我们可以看看Python把它改成了什么,我们通过魔法属性 person.__dict__ 来打印


print(person.__dict__)
  • 打印结果是:


{'_Person__name': '小王'}
  • 看到上面的打印,其实Python是把私有的属性改成了 一个下划线+类名+私有属性_类名私有属性,如上面的__name -> _Person__name,那么我们就可以通过 实例对象.被改后的私有属性名 来打印私有属性,如下


print(person._Person__name)
  • 打印结果是:小王


二、魔法属性



无论人或事物往往都有不按套路出牌的情况,Python的类属性也是如此,存在着一些具有特殊含义的属性,详情如下:

  • 2.1、__doc__ : 表示类的描述信息


class Foo:
     """ 描述类信息,这是用于看片的神奇 """
     def func(self):
           pass
print(Foo.__doc__)
#输出:类的描述信息
  • 2.2、__module____class__
  • __module__ 表示当前操作的对象在那个模块
  • __class__ 表示当前操作的对象的类是什么,也就是打印类对象的名字
  • test.py


class Person(object):
       def __init__(self):
            self.name = 'laowang'
  • main.py


from test import Person
obj = Person()
print(obj.__module__)  # 输出 test 即:输出模块
print(obj.__class__)  # 输出 test.Person 即:输出类
  • 2.3、 __init__ : 初始化方法,通过类创建对象时,自动触发执行


class Person:
      def __init__(self, name):
            self.name = name
            self.age = 18
obj = Person('laowang')  # 自动执行类中的 __init__ 方法
  • 2.4、__del__ :当对象在内存中被释放时,自动触发执行。
    提示:此方法一般无须定义,因为Python是一门高级语言,程序员在使用时无需关心内存的分配和释放,因为此工作都是交给Python解释器来执行,所以,__del__的调用是由解释器在进行垃圾回收时自动触发执行的。


class Foo:
      def __del__(self):
            pass
  • 2.5、__call__ : 对象后面加括号,触发执行
    提示:__init__方法的执行是由创建对象触发的,即:对象 = 类名();而对于__call__方法的执行是由对象后加括号触发的,即:对象() 或者 类()()


class Foo:
      def __init__(self):
             pass
      def __call__(self, *args, **kwargs):
             print('__call__')
obj = Foo()  # 执行 __init__
obj()  # 执行 __call__
  • 2.6、__dict__ : 类或对象中的所有属性,类的实例属性属于对象;类中的类属性和方法等属于类


class Province(object):
        country = 'China'
        def __init__(self, name, count):
             self.name = name
             self.count = count
        def func(self, *args, **kwargs):
             print('func')
# 获取类的属性,即:类属性、方法、
print(Province.__dict__)
# 输出:{'__dict__': <attribute '__dict__' of 'Province' objects>, '__module__': '__main__', 'country': 'China', '__doc__': None, '__weakref__': <attribute '__weakref__' of 'Province' objects>, 'func': <function Province.func at 0x101897950>, '__init__': <function Province.__init__ at 0x1018978c8>}
obj1 = Province('山东', 10000)
print(obj1.__dict__)
# 获取 对象obj1 的属性
# 输出:{'count': 10000, 'name': '山东'}
obj2 = Province('山西', 20000)
print(obj2.__dict__)
# 获取 对象obj1 的属性
# 输出:{'count': 20000, 'name': '山西'}
  • 2.7、__str__: 如果一个类中定义了 __str__ 方法,那么在打印 对象 时,默认输出该方法的返回值


class Foo:
      def __str__(self):
            return '小李'
obj = Foo()
print(obj)
# 输出:小李
  • 2.8、__getitem____setitem____delitem__ : 用于索引操作,如字典。以上分别表示 获取、设置、删除 数据


class Foo(object):
    def __getitem__(self, key):
           print('__getitem__', key)
    def __setitem__(self, key, value):
           print('__setitem__', key, value)
    def __delitem__(self, key):
           print('__delitem__', key)
obj = Foo()
result = obj['k1']      # 自动触发执行 __getitem__
obj['k2'] = 'laowang'   # 自动触发执行 __setitem__
del obj['k1']           # 自动触发执行 __delitem__
  • 2.9、__getslice____setslice____delslice__: 该三个方法用于分片操作,如:列表
class Foo(object):
     def __getslice__(self, i, j):
            print('__getslice__', i, j)
     def __setslice__(self, i, j, sequence):
            print('__setslice__', i, j)
     def __delslice__(self, i, j):
            print('__delslice__', i, j)
obj = Foo()
obj[-1:1]                   # 自动触发执行 __getslice__
obj[0:1] = [11,22,33,44]    # 自动触发执行 __setslice__
del obj[0:2]                # 自动触发执行 __delslice__


三、with与上下文管理器”



  • 3.1、对于 系统资源如文件、数据库连接、socket 而言,应用程序打开这些资源并执行完业务逻辑之后,必须做的一件事就是要关闭(断开)该资源
    比如 Python 程序打开一个文件,往文件中写内容,写完之后,就要关闭该文件,否则会出现什么情况呢?极端情况下会出现 "Too many open files" 的错误,因为系统允许你打开的最大文件数量是有限的。
    同样,对于数据库,如果连接数过多而没有及时关闭的话,就可能会出现 "Can not connect to MySQL server Too many connections",因为数据库连接是一种非常昂贵的资源,不可能无限制的被创建。
  • 3.2、看看如何正确关闭一个文件。
  • 普通版:打开文件之后直接进行读写操作


def m1():
     f = open("output.txt", "w")
     f.write("python之禅")
     f.close()
  • 这样写有一个潜在的问题,如果在调用 write 的过程中,出现了异常进而导致后续代码无法继续执行,close 方法无法被正常调用,因此资源就会一直被该程序占用者释放。那么该如何改进代码呢?
  • 进阶版: 看着不够简洁哈,后面还有高级版


def m2():
     f = open("output.txt", "w")
     try:
          f.write("python之禅")
     except IOError:
          print("oops error")
     finally:
          f.close()
  • 改良版本的程序是对可能发生异常的代码处进行 try 捕获,使用 try/finally 语句,该语句表示如果在 try 代码块中程序出现了异常,后续代码就不再执行,而直接跳转到 except 代码块。而无论如何,finally 块的代码最终都会被执行。因此,只要把 close 放在 finally 代码中,文件就一定会关闭
  • 高级版: 这么看起来就非常爽了


def m3():
     with open("output.txt", "r") as f:
            f.write("Python之禅")
  • 一种更加简洁、优雅的方式就是用 with 关键字。open 方法的返回值赋值给变量 f,当离开 with 代码块的时候,系统会自动调用 f.close() 方法, with 的作用和使用 try/finally 语句是一样的。那么它的实现原理是什么?在讲 with 的原理前要涉及到另外一个概念,就是上下文管理器(Context Manager)
  • 3.3、上下文管理器(Context Manager)
  • 什么是上下文(context)?
  • 看,一篇文章,给你摘录一段,没前没后,你读不懂,因为有语境,就是语言环境存在,一段话说了什么,要通过上下文(文章的上下文)来推断。
  • app点击一个按钮进入一个新的界面,也要保存你是在哪个屏幕跳过来的等等信息,以便你点击返回的时候能正确跳回,如果不存肯定就无法正确跳回了。
  • 看这些都是上下文的典型例子,理解成环境就可以,(而且上下文虽然叫上下文,但是程序里面一般都只有上文而已,只是叫的好听叫上下文。。进程中断在操作系统中是有上有下的,不过不这个高深的问题就不要深究了。。。)
  • 上下文管理器
    任何实现了 __enter__()__exit__() 方法的对象都可称之为上下文管理器,上下文管理器对象可以使用 with 关键字。显然,文件(file)对象也实现了上下文管理器。
    那么文件对象是如何实现这两个方法的呢?我们可以模拟实现一个自己的文件类,让该类实现 __enter__()__exit__()方法。


class File():
     def __init__(self, filename, mode):
            self.filename = filename
            self.mode = mode
     def __enter__(self):
            print("entering")
            self.f = open(self.filename, self.mode)
            return self.f
     def __exit__(self, *args):
            print("will exit")
            self.f.close()
  • __enter__()方法返回资源对象,这里就是你将要打开的那个文件对象,__exit__()方法处理一些清除工作。
    因为 File 类实现了上下文管理器,现在就可以使用 with 语句了。
with File('out.txt', 'w') as f:
         print("writing")
         f.write('hello, python')
  • 提示:File('out.txt', 'w')去执行的时候就会去调用里面的_enter__方法返回一个操作文本的对象,当在进行写的操作的时候,如果出现了异常,会自动调用__exit__,释放响应的资源,这样,你就无需显示地调用 close 方法了,由系统自动去调用,哪怕中间遇到异常 close 方法也会被调用。
  • 3.4、实现上下文管理器的另外方式Python 还提供了一个 contextmanager 的装饰器,更进一步简化了上下文管理器的实现方式。通过 yield 将函数分割成两部分,yield 之前的语句在 __enter__ 方法中执行,yield 之后的语句在 __exit__ 方法中执行。紧跟在 yield 后面的值是函数的返回值。


from contextlib import contextmanager
@contextmanager
def my_open(path, mode):
      f = open(path, mode)
      yield f
      f.close()
  • 调用


with my_open('out.txt', 'w') as f:
        f.write("hello , the simplest context manager")


  • 总结: Python 提供了 with 语法用于简化资源操作的后续清除操作,是 try/finally 的替代方法,实现原理建立在上下文管理器之上。此外,Python 还提供了一个 contextmanager 装饰器,更进一步简化上下管理器的实现方式。
目录
相关文章
|
29天前
|
人工智能 Ubuntu IDE
【Python】基础:环境配置与基础语法
本文介绍了Python编程语言及其环境配置方法。Python由Guido van Rossum于1991年创建,以其简洁、易学和强大的功能著称。文章详细讲解了Python的主要特点、Windows和Ubuntu下的安装配置步骤、基础语法、控制流、函数、文件操作、模块使用及面向对象编程等内容,帮助读者快速入门Python编程。
55 4
|
8天前
|
机器学习/深度学习 数据挖掘 开发者
Python编程入门:理解基础语法与编写第一个程序
【10月更文挑战第37天】本文旨在为初学者提供Python编程的初步了解,通过简明的语言和直观的例子,引导读者掌握Python的基础语法,并完成一个简单的程序。我们将从变量、数据类型到控制结构,逐步展开讲解,确保即使是编程新手也能轻松跟上。文章末尾附有完整代码示例,供读者参考和实践。
|
18天前
|
存储 Python Perl
python正则语法
本文介绍了正则表达式的基础知识及其在 Python 中的应用。首先解释了为什么要使用正则表达式,通过一个判断手机号的示例展示了正则表达式的简洁性。接着详细介绍了 `re` 模块的常用方法,如 `match()`、`search()`、`findall()`、`finditer()` 等,并讲解了正则表达式的基本语法,包括匹配单个字符、数字、锚字符和限定符等。最后,文章还探讨了正则表达式的高级特性,如分组、编译和贪婪与非贪婪模式。
16 2
|
24天前
|
存储 程序员 开发者
Python编程入门:从零开始掌握基础语法
【10月更文挑战第21天】本文将带你走进Python的世界,通过浅显易懂的语言和实例,让你快速了解并掌握Python的基础语法。无论你是编程新手还是想学习一门新的编程语言,这篇文章都将是你的不二之选。我们将一起探索变量、数据类型、运算符、控制结构、函数等基本概念,并通过实际代码示例加深理解。准备好了吗?让我们开始吧!
|
1月前
|
索引 Python
python-类属性操作
【10月更文挑战第11天】 python类属性操作列举
17 1
|
1月前
|
存储 C语言 索引
Python 语法及入门 (超全超详细) 专为Python零基础 一篇博客让你完全掌握Python语法
本文全面介绍了Python的基础知识,包括Python的诞生背景、为什么学习Python、Python的应用场景、Python环境的安装、Python的基础语法、数据类型、控制流、函数以及数据容器的使用方法,旨在为Python零基础读者提供一篇全面掌握Python语法的博客。
42 0
Python 语法及入门 (超全超详细) 专为Python零基础 一篇博客让你完全掌握Python语法
|
1月前
|
存储 数据可视化 数据处理
【Python篇】快速理解Python语法:全面指南
【Python篇】快速理解Python语法:全面指南
46 1
|
2月前
|
Java Linux C++
30天拿下Python之基础语法
30天拿下Python之基础语法
29 4
|
2月前
|
存储 API 索引
让 Python 的属性查找具有 C 一级的性能
让 Python 的属性查找具有 C 一级的性能
16 0
|
2月前
|
Python
Python中类属性与实例属性的区别
了解这些区别对于编写高效、易维护的Python代码至关重要。正确地使用类属性和实例属性不仅能帮助我们更好地组织代码,还能提高代码运行的效率。
26 0