资讯专栏INFORMATION COLUMN

Python中双下使用方法解析

89542767 / 251人阅读


  在Python这门语言中,有一些比较特殊的使用方法,主要用到的是双下划线开始和结束,正是因为如此,他还有一个比较接地气的名字,叫做双下方法,感兴趣的话,可以详细的为大家进行解答一下。


  前言


  大家在写Python代码的时候有没有这样的疑问。


  为什么数学中的+号,在字符串运算中却变成拼接功能,如'ab'+'cd'结果为abcd;而*号变成了重复功能,如'ab'*2结果为abab。


  为什么某些对象print能输出数据,而print自定义的类对象却输出一堆看不懂的代码<__main__.MyClsobjectat0x105732250>。


  不是因为系统做了特殊定制,而是Python中有一类特殊的方法,在某些特定的场合会自动调用。如,在字符串类str中定义了__add__方法后,当代码遇到字符串相加'ab'+'cd'时,就会自动调用__add__方法完成字符串拼接。


  因为这类特殊方法的方法名都是以双下划线开始和结束,所以又被称为双下方法。


  Python中的双下方法很多,今天我们对它做个详解。

9.png

  1.init方法


  __init__的方法是很多人接触的第一个双下方法。


 class A:
      def __init__(self, a):
          self.a = a

  

       当调用A()实例化对象的时候,__init__方法会被自动调用,完成对象的初始化。


  2.运算符的双下方法


  在类中定义运算符相关的双下方法,可以直接在类对象上做加减乘除、比较等操作。


  这里,定义一个尺子类Rule,它包含一个属性r_len代表尺子的长度。


 class Rule:
      def __init__(self, r_len):
          self.r_len = r_len


  2.1比较运算符


  如果想按照尺子的长度对不同的尺子做比较,需要在Rule类中定义比较运算符。


 class Rule:
      def __init__(self, r_len):
          self.r_len = r_len
      # < 运算符
      def __lt__(self, other):
          return self.r_len < other.r_len
      # <= 运算符
      def __le__(self, other):
          return self.r_len <= other.r_len

      # > 运算符


      def __gt__(self, other):


          return self.r_len > other.r_len


      # >= 运算符


      def __ge__(self, other):


          return self.r_len >= other.r_len


  这里定义了<、<=、>和>=四个比较运算符,这样就可以用下面的代码比较Rule对象了。


  rule1 = Rule(10)
  rule2 = Rule(5)
  print(rule1 > rule2)  # True
  print(rule1 >= rule2)  # True
  print(rule1 < rule2)  # False
  print(rule1 <= rule2)  # False


  当用>比较rule1和rule2的时候,rule1对象会自动调用__gt__方法,并将rule2对象传给other参数,完成比较。


  下面是比较运算符的双下方法


  2.2算术运算符


  可以支持类对象加减乘除。


def __add__(self, other):
      return Rule(self.r_len + other.r_len)


  这里定义了__add__方法,对应的是+运算符,他会把两个尺子的长度相加,并生成新的尺子。


   rule1 = Rule(10)
  rule2 = Rule(5)
  rule3 = rule1 + rule2


  下面是算术运算符的双下方法

10.png

  2.3反向算术运算符


  它支持其他类型的变量与Rule类相加。以__radd__方法为例


    def __radd__(self, other):
      return self.r_len + other


  程序执行10+rule1时,会尝试调用int类的__add__但int类类没有定义与Rule类对象相加的方法,所以程序会调用+号右边对象rule1的__radd__方法,并把10传给other参数。


  所以这种运算符又叫右加运算符。它所支持的运算符与上面的算术运算符一样,方法名前加r即可。


  2.4增量赋值运算符


  增量赋值运算符是+=、-=、*=、/=等。


   def __iadd__(self, other):
      self.r_len += other
      return self


   rule1 = Rule(10)
  rule1 += 5


  除了__divmod__方法,其他的跟算数运算符一样,方面名前都加i


  2.5位运算符


  这部分支持按二进制进行取反、移位和与或非等运算。由于Rule类不涉及位运算,所以我们换一个例子。


  定义二进制字符串的类BinStr,包含bin_str属性,表示二进制字符串。


    class BinStr:
      def __init__(self, bin_str):
          self.bin_str = bin_str


    x = BinStr('1010')  #创建二进制字符串对象
  print(x.bin_str) # 1010


  给BinStr定义一个取反运算符~


   # ~ 运算符
  def __invert__(self):
      inverted_bin_str = ''.join(['1' if i == '0' else '0' for i in self.bin_str])
      return BinStr(inverted_bin_str)


  __invert__方法中,遍历bin_str字符串,将每位取反,并返回一个新的BinStr类对象。


   x = BinStr('1011')
  invert_x = ~x
  print(invert_x.bin_str) # 0100


  下面是位运算符的双下方法

12.png

  这部分也支持反向位运算符和增量赋值位运算符,规则跟算数运算符一样,这里就不再赘述。


  3.字符串表示


  这部分涉及两个双下方法__repr__和__format__,在某些特殊场景,如print,会自动调用,将对象转成字符串。


  还是以BinStr为例,先写__repr__方法。

 

def __repr__(self):
      decimal = int('0b'+self.bin_str, 2)
      return f'二进制字符串:{self.bin_str},对应的十进制数字:{decimal}'
  x = BinStr('1011')
  print(x)


  # 输出:二进制字符串:1011,对应的十进制数字:11


  当程序执行print(x)时,会自动调用__repr__方法,获取对象x对应的字符串。


  再写__format__方法,它也是将对象格式化为字符串。


def __format__(self, format_spec):
      return format_spec % self.bin_str
  print('{0:二进制字符串:%s}'.format(x))


  # 输出:二进制字符串:1011


  当.format方法的前面字符串里包含0:时,就会自动调用__format__方法,并将字符串传给format_spec参数。


  4.数值转换


  调用int(obj)、float(obj)等方法,可以将对象转成相对应数据类型的数据。


 def __int__(self):
      return int('0b'+self.bin_str, 2)
  x = BinStr('1011')
  print(int(x))


  当调用int(x)时,会自动调用__int__方法,将二进制字符串转成十进制数字。


  数值转换除了上面的两个外,还有__abs__、__bool__、__complex__、__hash__、__index__和__str__。


  __str__和__repr__一样,在print时都会被自动调用,但__str__优先级更高。


  5.集合相关的双下方法


  这部分可以像集合那样,定义对象长度、获取某个位置元素、切片等方法。


  以__len__和__getitem__为例


 def __len__(self):
      return len(self.bin_str)
  def __getitem__(self, item):
      return self.bin_str[item]
  x = BinStr('1011')
  print(len(x))  # 4
  print(x[0])  # 1
  print(x[0:3])  # 101


  len(x)会自动调用__len__返回对象的长度。


  通过[]方式获取对象的元素时,会自动调用__getitem__方法,并将切片对象传给item参数,即可以获取单个元素,还可以获取切片。


  集合相关的双下方法还包括__setitem__、__delitem__和__contains__。


  6.迭代相关的双下方法


  可以在对象上使用for-in遍历。


 def __iter__(self):
      self.cur_i = -1
      return self
  def __next__(self):
      self.cur_i += 1
      if self.cur_i >= len(self.bin_str):
          raise StopIteration()  # 退出迭代
      return self.bin_str[self.cur_i]
  x = BinStr('1011')
  for i in x:
      print(i)


  当在x上使用for-in循环时,会先调用__iter__方法将游标cur_i置为初始值-1,然后不断调用__next__方法遍历self.bin_str中的每一位。


  这部分还有一个__reversed__方法用来反转对象。


  def __reversed__(self):


      return BinStr(''.join(list(reversed(self.bin_str))))


  x = BinStr('1011')


  reversed_x = reversed(x)


  print(reversed_x)


  # 输出:二进制字符串:1101,对应的十进制数字:13


  7.类相关的双下方法


  做web开发的朋友,用类相关的双下方法会更多一些。


  7.1实例的创建和销毁


  实例的创建是__new__和__init__方法,实例的销毁是__del__方法。


  __new__的调用早于__init__,它的作用是创建对象的实例(内存开辟一段空间),而后才将该实例传给__init__方法,完成实例的初始化。


  由于__new__是类静态方法,因此它可以控制对象的创建,从而实现单例模式。


  __del__方法在实例销毁时,被自动调用,可以用来做一些清理工作和资源释放的工作。


  7.2属性管理


  类属性的访问和设置。包括__getattr__、__getattribute__、__setattr__和__delattr__方法。


  __getattr__和__getattribute__的区别是,当访问类属性时,无论属性存不存在都会调用__getattribute__方法,只有当属性不存在时才会调用__getattr__方法。


  7.3属性描述符


  控制属性的访问,一般用于把属性的取值控制在合理范围内。包括__get__、__set__和__delete__方法。


  class XValidation:


      def __get__(self, instance, owner):


          return self.x


      def __set__(self, instance, value):


          if 0 <= value <= 100:


              self.x = value


          else:


              raise Exception('x不能小于0,不能大于100')


      def __delete__(self, instance):


          print('删除属性')


  class MyCls:


      x = XValidation()


      def __init__(self, n):


          self.x = n


  obj = MyCls(10)


  obj.x = 101


  print(obj.x) # 抛异常:Exception:x不能小于0,不能大于100


  上述例子,通过类属性描述符,可以将属性x的取值控制在[0,100]之前,防止不合法的取值。


文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/127647.html

相关文章

  • Python数据模型

    摘要:本文重点了解数据模型和接口的概念掌握特殊方法的定义,作用和基本用法。一基本概念数据模型是数据特征的抽象,这里是对框架的描述。数据模型规范了自身构建模块的接口,模块包括但不限于序列迭代器函数类和上下文管理器。 导语:本文章记录了本人在学习Python基础之绪论篇的重点知识及个人心得,以加深自己的理解。 本文重点: 1、了解Python数据模型和接口的概念;2、掌握特殊方法的定义,作用和基...

    Flink_China 评论0 收藏0
  • Python学习之路20-数据模型

    摘要:前言数据模型其实是对框架的描述,它规范了这门语言自身构件模块的接口,这些模块包括但不限于序列迭代器函数类和上下文管理器。上述类实现了方法,它可用于需要布尔值的上下文中等。但多亏了它是特殊方法,我们也可以把用于自定义数据类型。 《流畅的Python》笔记。本篇是Python进阶篇的开始。本篇主要是对Python特殊方法的概述。 1. 前言 数据模型其实是对Python框架的描述,它规范了...

    ad6623 评论0 收藏0
  • hexo+css遇到的unexpected token问题

    摘要:问题背景使用模拟实现文档,页面和的语法差异遇到问题。文档中的效果如下分析问题报错信息写的很明确,,是不被期望的。遇到问题时,解决思路可以考虑下转义码标签。 问题背景 使用hexo+css模拟实现weex文档,页面Weex 和 Vue 2.x 的语法差异遇到问题。 问题描述 新建页面,copy进去内容,hexo server运行,控制台报错: FATAL Somethings wrong...

    haoguo 评论0 收藏0
  • win下文件共享多种方式

    摘要:目录自身的文件共享自身的文件共享方式方式方式方式服务器端服务器端客户端客户端自身的文件共享参考查看共享网络映射网络驱动器到本地盘断开网络映射重置所有网络驱动器方式网址服务端中文网服务端中文网它是一个绿 目录 1.Win自身的文件共享  2.FTP方式 3.NFS方式 3.1 服务器端  3....

    不知名网友 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<