Python中的魔法属性

HUIDBK 2021-04-06 14:31:50
Python 魔法 属性 法属


Python中的魔法属性

魔法属性

在Python中,所有以 __ 双下划线包起来的方法,都统称为 Magic Method,例如类的初始化方法 __init__() ,实例对象创造方法 __new__()等。

魔法属性和方法是Python内置的一些属性和方法,有着特殊的含义。命名时前后加上两个下划线,在执行系统特定操作时,会自动调用。


常见的魔法属性

__doc__

表示类的描述信息


# __doc__
class Foo:
    """ 描述类信息,这是用于测试的类 """
    
    def func(self):
        pass

    
# ipython 测验
In [2]: Foo.__doc__
Out[2]: ' 描述类信息,这是用于测试的类 '
    

__module__ 和 __class__

  • __module__ 表示当前操作的对象在那个模块
  • __class__ 表示当前操作的对象的类是什么

# __module__、__class__
# oop.py
class Student(object):
    
    def __init__(self, name):
        self.name = name
        
        
# main.py
from oop import Student

s = Student()
print(s.__module__)  # 输出 oop 即:输出模块
print(s.__class__)   # 输出 <class 'oop.Student'> 即:输出类

__init__ 、__new__

__init__() 初始化方法 和 __new__(),通过类创建对象时,自动触发执行。__new__ 是用来创建类并返回这个类的实例,而 __init__ 只是将传入的参数来初始化该实例。

  • __new__() 创建对象时调用,会返回当前对象的一个实例

  • __init__() 创建完对象后调用,对当前对象的一些实例初始化,无返回值


# __init__ 、 __new__
class Student(object):

    def __init__(self, name, age):
        print('__init__() called')
        self.name = name
        self.age = age

    def __new__(cls, *args, **kwargs):
        print('__new__() called')
        print(cls, args, kwargs)
        return super().__new__(cls)
  

# ipython 测验
In [26]: s1 = Student('hui', age=21)
__new__() called
<class '__main__.Student'> ('hui',) {'age': 21}
__init__() called

In [27]: s2 = Student('jack', age=20)
__new__() called
<class '__main__.Student'> ('jack',) {'age': 20}
__init__() called


__del__

当对象在内存中被释放时,自动触发执行。

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

# __del__
class Foo:
    def __del__(self):
        print('__del__() called')

        
# ipython 测验
In [29]: f = Foo()

In [30]: del f
__del__() called

__call__

让类的实例的行为表现的像函数一样,你可以调用它们,将一个函数当做一个参数传到另外一个函数中等等。这是一个非常强大的特性,其让Python编程更加舒适甜美。对象后面加括号,触发执行

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

__call__ 在那些 类的实例经常改变状态的时候会非常有效。调用这个实例是一种改变这个对象状态的直接和优雅的做法。用一个实例来表达最好不过了:

# __call__
class Rect(object)
    """
    调用实例对象来改变矩形的位置
    """

    def __init__(self, x, y):

        # x, y代表矩形坐标
        self.x, self.y = x, y

    def __call__(self, x, y):        
        # 改变实体的位置
        self.x, self.y = x, y


# ipython 测验
In [33]: r = Rect(1010)

In [34]: r.x, r.y
Out[34]: (1010)

In [35]: r(00)

In [36]: r.x, r.y
Out[36]: (00)

In [37]: r(100100)

In [38]: r.x, r.y
Out[38]: (100100)

__dict__

类或对象中的所有属性

类的实例属性属于对象;类中的类属性和方法等属于类,即:

# __dict__
class Student(object):

    def __init__(self, name, age):
        self.name = name
        self._age = age

    @property
    def age(self):
        return self._age

    
# ipython 测验
In [47]: # 获取类属性

In [48]: Student.__dict__
Out[48]:
mappingproxy({'__module__''__main__',
              '__init__': <function __main__.Student.__init__(self, name, age)>,
              'age': <property at 0x210e2a005e8>,
              '__dict__': <attribute '__dict__' of 'Student' objects>,
              '__weakref__': <attribute '__weakref__' of 'Student' objects>,
              '__doc__'None})

In [49]: # 获取实例对象的属性

In [50]: s = Student('hui'21)

In [51]: s.__dict__
Out[51]: {'name''hui''_age'21}

In [52]: s2 = Student('jack'20)

In [53]: s2.__dict__
Out[53]: {'name''jack''_age'20}

__str__

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

In [65]: # __str__
    ...: class Foo(object):
    ...:     pass
    ...:

In [66]: f = Foo()

In [67]: print(f)
<__main__.Foo object at 0x00000210E2715608>

In [68]: class Foo(object):
    ...:
    ...:     def __str__(self):
    ...:         return '< Custom Foo object str >'
    ...:

In [69]: f = Foo()

In [70]: print(f)
< Custom Foo object str >


__getitem__、__setitem__、__delitem__

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

用于切片操作,如列表。


字典示例

# __getitem__、__setitem__、__delitem__
class MyDict(object):

    def __init__(self):
        self.my_dict = dict()

    def __getitem__(self, key):
        print('__getitem__() ', key)
        return self.my_dict.get(key, None)

    def __setitem__(self, key, value):
        print('__setitem__() ', key, value)
        self.my_dict.update(key=value)

    def __delitem__(self, key):
        print('__delitem__() ', key)
        del self.my_dict[key]


# ipython 测验        
In [33]: mdict = MyDict()

In [34]: print(mdict['name'])
__getitem__()  name
None

In [35]: # 新增

In [36]: mdict['name'] = 'hui'
__setitem__()  name hui

In [37]: mdict['age'] = 21
__setitem__()  age 21

In [38]: mdict['name']
__getitem__()  name
Out[38]: 'hui'

In [39]: mdict['age']
__getitem__()  age
Out[39]: 21

In [40]: # 更新

In [41]: mdict['name'] = 'jack'
__setitem__()  name jack

In [42]: mdict['name']
__getitem__()  name
Out[42]: 'jack'

In [43]: # 删除

In [44]: del mdict['age']
__delitem__()  age

In [45]: print(mdict['age'])
__getitem__()  age
None


列表示例

# 切片操作
class MyList(object):

    def __init__(self):
        self.mlist = list()

    def __getitem__(self, index):
        print('__getitem__() called')
        print(index)
        if isinstance(index, slice):
            return self.mlist[index]

    def __setitem__(self, index, value):
        print('__getitem__() called')
        print(index, value)
        if isinstance(index, slice):
            self.mlist[index] = value

    def __delitem__(self, index):
        print('__delitem__() called')
        if isinstance(index, slice):
            del self.mlist[index]
     
    
# ipython 测验
In [70]: mlist = MyList()

In [71]: mlist[0]
__getitem__() called
0

In [72]: mlist[0:-1]
__getitem__() called
slice(0-1None)
Out[72]: []

In [73]: mlist[:] = [1,2,3]
__getitem__() called
slice(NoneNoneNone) [123]

In [74]: mlist[:]
__getitem__() called
slice(NoneNoneNone)
Out[74]: [123]

In [75]: mlist[0:2]
__getitem__() called
slice(02None)
Out[75]: [12]

In [76]: mlist[::-1]
__getitem__() called
slice(NoneNone-1)
Out[76]: [321]

In [77]: mlist[0]
__getitem__() called
0

In [78]: mlist[0:1]
__getitem__() called
slice(01None)
Out[78]: [1]

In [79]: del mlist[0:1]
__delitem__() called

In [80]: mlist[:]
__getitem__() called
slice(NoneNoneNone)
Out[80]: [23]

注意: 当进行 mlist[0] 操作的时候传递并不是一个 slice 对象,不是一个 int 类型的数字,所以不能把索引为 0 的值取出来,改成 mlist[0, 1] 或者在 __getitem__() 的方法中新增数字判断,大家可以尝试一下。


__enter__、__exit__

with 声明是从 Python2.5 开始引进的关键词。你应该遇过这样子的代码:

with open('foo.txt'as bar:
    # do something with bar
    pass

with 声明的代码段中,我们可以做一些对象的开始操作和退出操作,还能对异常进行处理。这需要实现两个魔术方法: __enter__ 和 __exit__。

__enter__(self):

定义了当使用 with 语句的时候,会话管理器在块被初始创建时要产生的行为。请注意,__enter__ 的返回值与 with 语句的目标或者 as 后的名字绑定。

__exit__(self, exception_type, exception_value, traceback):

定义了当一个代码块被执行或者终止后,会话管理器应该做什么。它可以被用来处理异常、执行清理工作或做一些代码块执行完毕之后的日常工作。如果代码块执行成功,exception_type,exception_value,和traceback 将会为 None 。否则,你可以选择处理这个异常或者是直接交给用户处理。如果你想处理这个异常的话,请确保__exit__ 在所有语句结束之后返回 True。如果你想让异常被会话管理器处理的话,那么就让其产生该异常。


__copy__、__deepcopy__

有时候,尤其是当你在处理可变对象时,你可能想要复制一个对象,然后对其做出一些改变而不希望影响原来的对象。这就是Python的copy所发挥作用的地方。

__copy__(self):

定义了当对你的类的实例调用 copy.copy() 时所产生的行为。copy.copy() 返回了你的对象的一个浅拷贝——这意味着,当实例本身是一个新实例时,它的所有数据都被引用了——例如,当一个对象本身被复制了,它的数据仍然是被引用的(因此,对于浅拷贝中数据的更改仍然可能导致数据在原始对象的中的改变)。

__deepcopy__(self, memodict={}):

定义了当对你的类的实例调用 copy.deepcopy()时所产生的行为。copy.deepcopy() 返回了你的对象的一个深拷贝——对象和其数据都被拷贝了。memodict 是对之前被拷贝的对象的一个缓存——这优化了拷贝过程并且阻止了对递归数据结构拷贝时的无限递归。当你想要进行对一个单独的属性进行深拷贝时,调用copy.deepcopy(),并以 memodict 为第一个参数。


这些魔术方法的用例看起来很小,并且确实非常实用. 它们反应了关于面向对象程序上一些重要的东西在Python 上,并且总的来说 Python 总是一个简单的方法去找某些事情,即使是没有必要的。这些魔法方法可能看起来不是很有用,但是一旦你需要它们,你会感到庆幸它们的存在。


其他魔法方法

由于魔法属性、方法太多了在这就不一一描述和展示了,其他的就以表格形式呈现吧。

用于比较的魔术方法

方法 作用
__cmp__(self, other) 比较方法里面最基本的的魔法方法
__eq__(self, other) 定义相等符号的行为,==
__ne__(self,other) 定义不等符号的行为,!=
__lt__(self,other) 定义小于符号的行为,<
__gt__(self,other) 定义大于符号的行为,>
__le__(self,other) 定义小于等于符号的行为,<=
__ge__(self,other) 定义大于等于符号的行为,>=

数值计算的魔术方法

单目运算符和函数

方法 作用
__pos__(self) 实现一个取正数的操作
__neg__(self) 实现一个取负数的操作
__abs__(self) 实现一个内建的 abs() 函数的行为
__invert__(self) 实现一个取反操作符(~操作符)的行为
__round__(self, n) 实现一个内建的 round() 函数的行为
__floor__(self) 实现 math.floor() 的函数行为
__ceil__(self) 实现 math.ceil() 的函数行为
__trunc__(self) 实现 math.trunc() 的函数行为

双目运算符或函数

方法 作用
__add__(self, other) 实现一个加法
__sub__(self, other) 实现一个减法
__mul__(self, other) 实现一个乘法
__floordiv__(self, other) 实现一个 // 操作符产生的整除操作
__div__(self, other) 实现一个 / 操作符代表的除法操作
__truediv__(self, other) 实现真实除法
__mod__(self, other) 实现一个 % 操作符代表的取模操作
__divmod__(self, other) 实现一个内建函数 divmod()
__pow__(self, other) 实现一个指数操作( ****** 操作符)的行为
__lshift__(self, other) 实现一个位左移操作**(<<)**的功能
__rshift__(self, other) 实现一个位右移操作**(>>)**的功能
__and__(self, other) 实现一个按位进行与操作**(&)**的行为
__or__(self, other) 实现一个按位进行或操作的行为
__xor__(self, other) 异或运算符相当于 ^

增量运算

方法 作用
__iadd__(self, other) 加法赋值
__isub__(self, other) 减法赋值
__imul__(self, other) 乘法赋值
__ifloordiv__(self, other) 整除赋值,地板除,相当于 //= 运算符
__idiv__(self, other) 除法赋值,相当于 /= 运算符
__itruediv__(self, other) 真除赋值
__imod_(self, other) 模赋值,相当于 %= 运算符
__ipow__(self, other) 乘方赋值,相当于 **= 运算符
__ilshift__(self, other) 左移赋值,相当于 <<= 运算符
__irshift__(self, other) 左移赋值,相当于 >>= 运算符
__iand__(self, other) 与赋值,相当于 &= 运算符
__ior__(self, other) 或赋值
__ixor__(self, other) 异或运算符,相当于 ^= 运算符

类型转换

方法 作用
__int__(self) 转换成整型
__long__(self) 转换成长整型
__float__(self) 转换成浮点型
__complex__(self) 转换成 复数型
__oct__(self) 转换成八进制
__hex__(self) 转换成十六进制
__index__(self) 如果你定义了一个可能被用来做切片操作的数值型,你就应该定义__index__
__trunc__(self) math.trunc(self) 使用时被调用 __trunc__ 返回自身类型的整型截取
__coerce__(self, other) 执行混合类型的运算

公众号

新建文件夹X

大自然用数百亿年创造出我们现实世界,而程序员用几百年创造出一个完全不同的虚拟世界。我们用键盘敲出一砖一瓦,用大脑构建一切。人们把1000视为权威,我们反其道行之,捍卫1024的地位。我们不是键盘侠,我们只是平凡世界中不凡的缔造者 。

版权声明
本文为[HUIDBK]所创,转载请带上原文链接,感谢
https://mdnice.com/writing/3a552207f3da4ecaa0121ceb82cafae5

  1. Docker | 多图预警 | 配置Docker下Python开发环境
  2. Docker | multi graph warning | configuring Python development environment under docker
  3. 课程学习记录之python迭代器和生成器
  4. Python_学习之流程控制
  5. Python_学习之运算符
  6. Python_学习之基础数据类型
  7. Python_学习之虚拟环境的搭建
  8. Python iterator and generator of course learning record
  9. Python_ Process control of learning
  10. Python_ Learning operators
  11. Python_ Basic data types of learning
  12. Python_ The construction of virtual learning environment
  13. 一个非常简单好用的 Python 图形界面库
  14. 我就是这样学 Python 的
  15. 零基础,从一个抢票程序,提升自己的Python技能
  16. A very simple and easy to use Python graphical interface library
  17. That's how I learned python
  18. 商业数据分析从入门到入职(9)Python网络数据获取
  19. Zero basis, improve your Python skills from a ticket grabbing program
  20. 商业数据分析从入门到入职(8)Python模块、文件IO和面向对象
  21. 商业数据分析从入门到入职(7)Python基础数据结构及其操作
  22. 商业数据分析从入门到入职(6)Python程序结构和函数
  23. Business data analysis from entry to entry (9) Python Network Data Acquisition
  24. Business data analysis from entry to entry (8) Python module, file IO and object oriented
  25. Business data analysis from entry to entry (7) Python basic data structure and its operation
  26. Business data analysis from entry to entry (6) Python program structure and function
  27. 简简单单实现 Python Web 的登录注册页面,还包含一半逻辑。
  28. Simple implementation of Python web login registration page, but also contains half of the logic.
  29. 什么是pip?Python新手入门指南
  30. What is PIP? Getting started with Python
  31. Python uses for... Else to jump out of double nested loop
  32. Python基础之:Python中的内部对象
  33. 人工智能入门:Python实现机器学习
  34. The foundation of Python: inner objects in Python
  35. Introduction to artificial intelligence: machine learning in Python
  36. Python基础之:Python中的内部对象
  37. The foundation of Python: inner objects in Python
  38. Python 小技之 Office 文件转 PDF
  39. 还在为多张Excel汇总统计发愁?Python 秒处理真香!
  40. 用 Python 制作音乐聚合下载器
  41. Spark Delta Lake 0.4.0 发布,支持 Python API 和部分 SQL
  42. How to transfer office files to PDF
  43. Are you still worried about multiple excel summary statistics? Python second processing really fragrant!
  44. Making music aggregate downloader with Python
  45. Spark delta Lake 0.4.0 is released, supporting Python API and part of SQL
  46. Python信息搜集
  47. Python information gathering
  48. Python - 关于类(self/cls) 以及 多进程通讯的思考
  49. Python - thinking about class (self / CLS) and multi process communication
  50. Python - 关于类(self/cls) 以及 多进程通讯的思考
  51. Python - thinking about class (self / CLS) and multi process communication
  52. Python信用评分卡建模(附代码)
  53. Python credit score card modeling (with code)
  54. 学Python需要学数据库吗?Python学习教程!
  55. Do you need to learn database to learn Python!
  56. Python私有变量如何定义?Python学习教程!
  57. How to define Python private variables? Python tutorial!
  58. Python数据分析入门(六):Pandas的函数应用
  59. Introduction to Python data analysis (6): function application of pandas
  60. 学Python需要学数据库吗?Python学习教程!