Python 私有属性和名字重整、魔法属性和方法、上下文管理器

系统 1661 0

修改、查看私有属性、名字重整

如下,Test类定义 一个私有属性 __name  实例化一个对象 a ,无法调用该属性,

打印 a.__dict__( 可以检查一个对象的所有属性 )查看 ,发现__name存在并且名字变为  _Test__name (无法调用的原因,名字被改变)

改变规则:私有属性前添加类名,再在类名前添加一个下划线 ( 名字重整

Python 私有属性和名字重整、魔法属性和方法、上下文管理器_第1张图片

我们验证一下,打印修改后的属性,如下

 

这里有个疑问,既然无法直接打印,那我们为什么可以直接修改?

修改测试一下,打印输出,此时__name 并不是私有属性了,此时的 __name 只是添加了一个属性,可以直接调用

这里就没有什么私有公有之说了,所谓的公有私有,是指类中的属性,实例对象无法直接调用

Python 私有属性和名字重整、魔法属性和方法、上下文管理器_第2张图片              

另外补充一下 __dict__属性,Test类也是一个对象,查看其属性:每个魔法属性对应值或函数

 

 

魔法属性、方法

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

如上图,对应的魔法属性:

 

1. __doc__ :表示类的描述信息,help()方法也可以输出类的描述信息

            
              class Test():
    """
    This is a description of a class
    """
    pass


print(Test.__doc__)
print("*" * 15)
print(help(Test))
            
          

Python 私有属性和名字重整、魔法属性和方法、上下文管理器_第3张图片

 

2. __module__  和 __class__ :__module__表示当前操作在哪个模块,__class__表示当前操作的对象的类是什么

            
              # -*- coding:utf-8 -*-


# test.py
class Person(object):
    def __init__(self):
        self.name = 'laowang'
            
          
            
              

from test import Person


# main.py
obj = Person()
print(obj.__module__)  # 输出创建该对象的对应模块  test
print(obj.__class__)  # 输出创建该对象的对应模块中的类    test.Person
            
          

 

3. __init__ :初始化方法(不建议称其为构造方法,可以说__init__ 和 __new__ 方法一起完成了构造方法的功能),通过类创建对象时,自动触发执行

            
              class Person:
    def __init__(self, name):
        self.name = name
        self.age = 18


obj = Person('laowang')  # 自动执行类中的 __init__ 方法

            
          

 

4. __del__:当对象在内存中被释放时,自动触发执行

注:此方法无需定义,因为python是一门高级语言,程序员在使用时,无需关系内存的分配和释放,因为此工作都是交给Python的解释器来执行,所以,__del__的调用是有解释器在进行垃圾回收时自动触发执行的。

            
              class Foo:
    def __del__(self):
        pass
            
          

 

5. __call__:对象后面加括号,触发执行  (用于装饰器)

注:__init__方法的执行是由创建对象触发的,即 对象 = 类名() ; 而对于__call__ 方法执行是由对象后加括号触发的,即

对象()  类()

            
              class Foo:
    def __init__(self):
        pass

    def __call__(self, *args, **kwargs):
        print('__call__')


obj = Foo()  # 执行 __init__
obj()  # 执行 __call__
            
          

 

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__': 
              
                , '__module__': '__main__', 'country': 'China', '__doc__': None, '__weakref__': 
                
                  , 'func': 
                  
                    , '__init__': 
                    
                      }

obj1 = Province('山东', 10000)
print(obj1.__dict__)
# 获取 对象obj1 的属性
# 输出:{'count': 10000, 'name': '山东'}

obj2 = Province('山西', 20000)
print(obj2.__dict__)
# 获取 对象obj1 的属性
# 输出:{'count': 20000, 'name': '山西'}
                    
                  
                
              
            
          

 

7. __str__:如果一个类中定义了__str__方法,那么在打印 对象 时,默认输出该方法的返回值

            
              class Foo:
    def __str__(self):
        return 'laowang'


obj = Foo()
print(obj)
# 输出:laowang
            
          

 

8. __getitem__、__setitem__、__delitem__ :用于索引操作,如字典。以上分别表示获取、设置、删除数据

            
              # -*- coding:utf-8 -*-

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__
            
          

9. __getitem__、__setitem__、__delitem__ :该三个方法用于分片操作,如:列表

            
              # -*- coding:utf-8 -*-

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、上下文管理器

对于系统资源如文件、数据库连接、socket 而言,应用程序打开这些资源并执行完业务逻辑之后,必须做的一件事就是要关闭(断开)该资源。

比如 Python 程序打开一个文件,往文件中写内容,写完之后,就要关闭该文件,否则会出现什么情况呢?极端情况下会出现 "Too many open files" 的错误,因为系统允许你打开的最大文件数量是有限的。

同样,对于数据库,如果连接数过多而没有及时关闭的话,就可能会出现 "Can not connect to MySQL server Too many connections",因为数据库连接是一种非常昂贵的资源,不可能无限制的被创建。

普通版:

            
              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:            # except 未捕获到对应异常,依然会崩
        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)

 

上下文(context)

上下文在不同的地方表示不同的含义,要感性理解。context其实说白了,和文章的上下文是一个意思,通俗一点,理解为环境

 

上下文管理器

任何实现了 __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: 
# 实例化File对象,执行__init__方法,filename属性对应out.txt,w对应mode属性
# with判断其是否是一个上下文管理器(实现对应的方法),然后自动调用 __enter__()方法 
# __enter__()方法返回值是什么,对应的 f 就是什么,而当结束或者出现异常时,会自动调用 __exit__()
# 方法
    print("writing")
    f.write('hello, python')
            
          

这样,你就无需显示地调用 close 方法了,由系统自动去调用,哪怕中间遇到异常 close 方法也会被调用。

 

实现上下文管理器的另外方式(了解)

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 装饰器,更进一步简化上下管理器的实现方式。

 

 

 

 


更多文章、技术交流、商务合作、联系博主

微信扫码或搜索:z360901061

微信扫一扫加我为好友

QQ号联系: 360901061

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描下面二维码支持博主2元、5元、10元、20元等您想捐的金额吧,狠狠点击下面给点支持吧,站长非常感激您!手机微信长按不能支付解决办法:请将微信支付二维码保存到相册,切换到微信,然后点击微信右上角扫一扫功能,选择支付二维码完成支付。

【本文对您有帮助就好】

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描上面二维码支持博主2元、5元、10元、自定义金额等您想捐的金额吧,站长会非常 感谢您的哦!!!

发表我的评论
最新评论 总共0条评论