Python编程学习13:python魔法方法

在python中,有一些内置好的特定的方法(总是被双下划线包围,如__init__),这些方法在进行特定的操作时会自动被调用,称之为魔法方法

 

1. 构造  __init__ 方法,相当于Java中的构造方法,在实例化的时候会自动调用。__new__方法,在__init__之前被调用,返回的是对象,极少去重写它。当继续一个不可变类型,但是又需要对它进行修改时,可以重新__new__

 

2. __del__ 析构,销毁对象。垃圾回收(即对某个对象的所有引用都被删除)时才会调用__del__方法,del x只是删除x的引用

 

3. 对象的算术运算

 

4. 简单定制: 类的方法名和属性名一样时,属性会覆盖方法。

import time as t

class MyTimer:
    def __init__(self):
        self.prompt = '未开始计时!'
        self.lasted = []
        self.start = 0
        self.stop = 0
    
    def __str__(self):
        return self.prompt
    
    __repr__ = __str__
    
    # 开始计时
    def start(self):
        self.start = t.localtime()
        print('计时开始...')
    
    # 停止计时
    def stop(self):
        self.stop = t.localtime()
        print('计时结束...')
    
    # 内部方法,计算运行时间
    def _calc(self):
        self.lasted = []
        self.prompt = '总共运行了'
        for index in range(6):
            self.lasted.append(self.stop[index]  - self.start[index])
            self.prompt += str(self.lasted[index])

 

5.  属性方法

class C:
    def __init__(self, size=10):
        self.size = size
    def getSize(self):
        return self.size
    def setSize(self,value):
        self.size = value
    def delSize(self):
        del self.size
    x = property(getSize, setSize, delSize)

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)

注意:在python中实例的属性访问都会经过__getattribute__,如果属性找不到则就会调用__getattr__

 

死循环陷阱

class Rectangle:
    def __init__(self, width=0, height=0):
        self.width = width    # 自动触发__setattr__
        self.height = height
    
    def __setattr__(self, name, value):
        if name == 'square':
            self.width = value
            self.height = value
        else:
            self.name = value  # 再次触发__setattr__,无限递归
    
    def getArea(self):
        return self.width * self.width

 

 

解决方法:

class Rectangle:
    def __init__(self, width=0, height=0):
        self.width = width
        self.height = height
    
    def __setattr__(self, name, value):
        if name == 'square':
            self.width = value
            self.height = value
        else:
            super().__setattr__(name,value)  # 调用基类的__setattr__
#             self.__dict__[name] = value
    
    def getArea(self):
        return self.width * self.width

 

6. 描述符

 

class MyDecriptor:
    def __init__(self, fget=None, fset=None, fdel=None):
        self.fget = fget
        self.fset = fset
        self.fdel = fdel
    
    def __get__(self, instance, owner):
        print('getting...')
        return self.fget(instance)
    
    def __set__(self, instance, value):
        print('setting...')
        self.fset(instance, value)
    
    def __delete__(self, instance):
        print('deleting...')
        self.fdel(instance)

class C:
    def __init__(self):
        self._x = None
    def getX(self):
        return self._x
    
    def setX(self, value):
        self._x = value
    def delX(self):
        del self._x
    
    x = MyDecriptor(getX, setX, delX)

 

 

 

7. 定制容器

class CountList:
    def __init__(self, *args):
        self.values = [x for x in args]
        self.count = {}.fromkeys(range(len(self.values)),0)
    
    def __len__(self):
        return len(self.values)
    
    def __getitem__(self,key):
        self.count[key] += 1      # 某元素被访问一次,则计数加1
        return self.values[key]

c1 = CountList(1,3,5,7,9)
c2 = CountList(2,4,6,8,10)

 

 

 

8. 迭代器

class Fibs:
    def __init__(self, n=10):
        self.n = n
        self.a = 0
        self.b = 1
        
    def __iter__(self):
        return self
    
    def __next__(self):
        self.a, self.b = self.b, self.a+self.b
        if self.a > self.n:
            raise StopIteration
        return self.a

fibs = Fibs(20)
for each in fibs:
    print(each)

1
1
2
3
5
8
13

 

9. __call__方法

对象通过提供__call__(slef, [,*args [,**kwargs]])方法可以模拟函数的行为,如果一个对象x提供了该方法,就可以像函数一样使用它,也就是说x(arg1, arg2...) 等同于调用x.__call__(self, arg1, arg2)。

class DistanceForm(object):
  def __init__(self, origin):
    self.origin = origin
    print("origin :"+str(origin))
  def __call__(self, x):
    print("calling,  x :"+str(x+1))

 

 

本文参考:小甲鱼python基础教程

 

 

 

 

 

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值