zoukankan      html  css  js  c++  java
  • python:类3——魔法方法

     一、魔法方法特点

    • 被双上下滑线包围
    • 魔法方法是面向对象的Python的一切,如果你不知道魔法方法,说明你还没能意识到面向对象的Python的强大(不是说Python脚本)
    • 通过对制定方法的重写,完全可以让python根据个人的用途去实现!

    二、魔法方法

    http://bbs.fishc.com/forum.php?mod=viewthread&tid=48793&extra=page%3D1%26filter%3Dtypeid%26typeid%3D403


    1、构造相关

    __init__(self [,...])构造方法

    • 不写时,会默认存在一个无参的,写了会覆盖
    • 必须返回None,不能写 return,否则返回TypeError;因此不要对init做返回;

    __new__(cls[, ...])

    • 对象实例化时调用的第一个方法,在init之前,它有个很大的不同第一个参数不是self,而是这个类cls,返回一个对象,cls后边的参数会原封不动的传给__init__()方法
    • 平时极少重写,当继承一个不可变类型又需要修改的时候,需要重写new
    class CapStr(str):                #继承str类是不可变得
        def __new__(cls, string):          #重写new,第一个传入class,叫其他名字也无所谓,只是为了区分
            string = string.upper()         #全部变大写
            return str.__new__(cls, string)    变完大写后,把它作为参数去调用基类的new方法
    
    a = CapStr('I love Money')          #得到的a为大写

    __del__(self)析构

    • delete缩写,当没有任何变量引用这个变量后,垃圾回收机制会自动销毁时调用它
    • 并非执行del x 就立马是调用x.__del__();

     


     2、表现类 

    __str__        和print()对应

    __repr__

    >>> class A():
    ...   def __str__(self):    #给print()用
    ...     return "hahaha"
    ... 
    >>> a = A()
    >>> a
    <__main__.A object at 0x7f85993317f0>
    >>> print(a)
    hahaha

    打印时,返回字符串,需要return 字符串,不可以是别的类型

    __str__ = __repr__

    >>> class A():
    ...   def __repr__(self):    #给obj对象用
    ...     return "hahaha"
    ... 
    >>> a = A()
    >>> a
    hahaha
    >>> print(a)
    hahaha
    >>> 

    3、有关算数运算的魔法方法

    在python2.2之前类和类型是分开的;类是属性和方法的封装;类型是像整型、浮点型、字符串等这些;但Python2.2之后,对二者进行统一,做法是将int、float、string、list、tuple等这些bif统统转化为工厂函数

    int('123')在以前是调用int函数,把参数转化为整型;现在是用参数实例化一个int对象。并且对象可以做加法!

    调用__add__(),因此可以重写,但重写没有多大意义吧

     

     下边写法会进入无线递归:

    改进:

     推荐第一种写法

    上表中的魔法方法加上r,就是反运算符:a + b,如果a对象的add方法没有实现或者不支持相应的操作的时候,那么python就会自动找到对象b的__radd__(self, other)方法

    1为什么没有__add__()方法??

    在减法中,为了实现目的,可以修改为 def __radd__(self, other):  return int.__sub__(other, self)

    一元操作符

    __neg__(self)         定义正号的行为:+x

    __pos__(self)          定义符号的行为:-x

    __abs__(self)          定义当被abs()调用时的行为

    __invert__(self)       定义按位取反的行为:~x


    4、属性访问

    点;bif

    __getattr__(self, name)

    • 定义当用户试图获取一个不存在的属性时的行为

    __getattribute__(self, name)

    • 定义当该类的属性被访问时的行为

    __setattr__(self, name, value)

    • 定义当一个属性被设置时的行为

    __delattr__(self, name)

    • 定义当一个属性被删除时的行为
    >>> class C:
    ...     def __getattribute__(self, name):
    ...         print("getattribute")  
    ...         return super().__getattribute__(name)
    ...     def __getattr__(self, name):
    ...         print("getattr")
    ...     def __setattr__(self, name, value):
    ...         print("setattr")
    ...         super().__setattr__(name, value)
    ...     def __delattr__(self, name):
    ...         print("delattr")
    ...         super().__delattr__(name)
    ... 
    >>> c = C()
    >>> c.x
    getattribute
    getattr
    >>> c.x = 1
    setattr
    >>> c.x
    getattribute
    1
    >>> del c.x
    delattr

    定义一个矩形类,且修改__setattr__()方法,如果为一个叫square的属性赋值,那么说明这是一个正方形,值就是正方形的边长,宽和高等于边长。 

      1 class Rextangle():
      2     def __init__(self, width=0, height=0):
      3         self.width = width
      4         self.height = height
      5 
      6     def __setattr__(self, name, value):
      7         if name == 'square':
      8             self.width = value
      9             self.height = value
     10         else:
     11第一种        self.width = value    #报错,无限递归
     12             self.height = value    #报错,无限递归
      第二种    self.name = value     #报错,无限递归
      第三种    super().__setattr__(name, value)  #正确(推荐)
      第四种    self.__dict__[name] = value     #正确 13 def getArea(self): 14 return self.width * self.height

    r = Rectangle(4, 5)    初始化是,有self.widthself.height赋值,回去调用被改写了的__setattr__()方法
    r.getArea()        返回20
    r.square = 10
    r.width r.height   返回10
    r.getArea()        返回100
    r.__dict__         返回{'width':10, 'height':10}  因此会有“第四种”

     5、描述符

    描述符就是将某种特殊类型的类的实例指派给另一个类的属性。

    • __get__(self, instance, owner)    用于访问属性时调用,它返回属性值
    • __set__(self, instance, value)     将在属性分配操作中调用,不返回任何内容
    • __delete__(self, instance)              控制删除操作,不返回任何内容

    这三个方法跟4里的属性访问方法很相似:python中__get__,__getattr__,__getattribute__的区别:主要看例子

      1 class MyDecriptor():
      2     def __get__(self, instance, owner):
      3         print("getting...", self, instance, owner)
      4 
      5     def __set__(self, instance, value):
      6         print("setting...", self, instance, value)
      7 
      8     def __delete__(self, instance):
      9         print("deleting...", self, instance)
    
    In [51]: class Test():
        ...:     x = MyDecriptor()         #将类的实例指派给Test类的属性x,此时MyDecriptor()实例里的属性、方法就是x的描述符
        ...:     
    
    In [52]: test = Test()              #实例化Test类
    
    In [53]: test.x                  #调用了描述符的__get__()
    getting... <yu412.MyDecriptor object at 0x7fa160356dd8> <__main__.Test object at 0x7fa1602a4f98> <class '__main__.Test'>
    
    In [54]: test                    #实例
    Out[54]: <__main__.Test at 0x7fa1602a4f98>
    
    In [55]: Test                    #类
    Out[55]: __main__.Test
    
    In [56]: test.x = "X-man"             #调用__set__()          
    setting... <yu412.MyDecriptor object at 0x7fa160356dd8> <__main__.Test object at 0x7fa1602a4f98> X-man
    
    In [57]: del test.x                 #调用__delete__()
    deleting... <yu412.MyDecriptor object at 0x7fa160356dd8> <__main__.Test object at 0x7fa1602a4f98>

    利用以上原理可以轻松实现property()方法

    练习:

    先定义一个温度类,然后定义两个描述符类用于描述摄氏度和华氏度两个属性;要求两个属性会自动进行转换,也就是说你可以给摄氏度这个属性赋值,然后打印的华氏度属性是自动转换后的结果

     


    6、定制容器

    http://www.cnblogs.com/daduryi/p/6737186.html 

    _len__()、__getitem__()、__setitem__()和__delitem__()

    __iter__()——返回迭代器本身

    __next__()——决定迭代器的规则

  • 相关阅读:
    PAT(B) 1037 在霍格沃茨找零钱(Java)
    PAT(B) 1043 输出PATest(Java)统计
    PAT(B) 1063 计算谱半径(Java)
    绘制虚线
    contentMode
    数字签名是什么
    动态设置 button的 name 的话 闪动的问题 解决
    setValuesForKeysWithDictionary 的用法
    获得 当前时间
    iOS 键盘类型
  • 原文地址:https://www.cnblogs.com/daduryi/p/6824486.html
Copyright © 2011-2022 走看看