zoukankan      html  css  js  c++  java
  • Python学习笔记(七)——魔法方法

    1.构造和析造

    魔法方法就是被双下划线包围的方法

    __init__()方法

    __init__方法默认没有参数,返回值为none。类实例化对象需有明确的初始化步骤要重写函数

    >>> class Rectangle:
        def __init__(self,x,y):
            self.x = x
            self.y = y
        def getPeri(self):
            return (self.x+self.y)*2
        def getArea(self):
            return self.x * self.y
    
    
    >>> rect = Rectangle(3,4)
    >>> rect.getPeri()
    14
    >>> rect.getArea()
    12
    >>> #init返回值一定是None
    >>> class A:
        def __init__(self):
            return "A"
    
    
    >>> a = A()
    Traceback (most recent call last):
      File "", line 1, in 
        a = A()
    TypeError: __init__() should return None, not 'str'
    

    __new__()方法

    __new__()方法在实例化对象时返回一个实例对象,参数是cls,是第一个被调用的方法

    >>> class CapStr(str):
        def __new__(cls,string):
            string = string.upper()
            return str.__new__(cls,string)
    
    
    >>> a = CapStr("I love FishC.com")
    >>> a
    'I LOVE FISHC.COM'
    

    __del__()方法

    __del__()方法在对象将要被销毁时被调用

    >>> class C:
        def __init__(self):
            print("我是init方法,我被调用了")
        def __del__(self):
            print("我是del方法,我被调用了")
    
    >>> c1 = C()
    我是init方法,我被调用了
    >>> c2 = c1
    >>> c3 = c2
    >>> del c3
    >>> del c2
    >>> del c1
    我是del方法,我被调用了
    

    对象生成后,所有对它的引用都被del之后,才会启动垃圾回收机制

    关于垃圾回收机制

    2.算数运算

    运算符 对应的魔法方法 中文注释
    + __ add__(self, other) 加法
    - __ sub__(self, other) 减法
    * __ mul__(self, other) 乘法
    / __ truediv__(self, other) 真除法
    // __ floordiv__(self, other) 整数除法
    % __ mod__(self, other) 取余除法
    divmod(a, b) __ divmod__(self, other) 把除数和余数运算结果结合
    ** __ pow__(self, other[,modulo]) self的other次方再对modulo取余
    << __ lshift__(self, other) 按位左移
    >> __ rshift__(self, other) 按位右移
    & __ and__(self, other) 按位与操作
    ^ __ xor__(self, other) 按位异或操作(同为0,异为1)
    __ or__(self, other) 按位或操作(有1则1)

    反运算的魔方方法

    >>> class Nint(int):
        def __radd__(self,other):
            return int.__sub__(self,other)
    
    
    >>> a = Nint(5)
    >>> b = Nint(3)
    >>> a + b
    8
    >>> 1 + b
    2
    >>> #此处执行了3-1,self是3,other是1
    

    3. 简单定制(计时器)

    time模块

    import time as t
    
    class MyTimer():
        def __init__(self):
            self.unit = ['年','月','日','小时','分','秒']
            self.prompt = "未开始计时!"
            self.lasted = []
            self.begin = 0
            self.end = 0
        # 调用实例直接显示结果
        def __str__(self):
            return self.prompt
    
        __repr__ = __str__
    
        # 计算两次计时器对象之和
        def __add__(self, other):
            prompt = "总共运行了"
            result = []
            for index in range(6):
                result.append(self.lasted[index] + other.lasted[index])
                if result[index]:
                    prompt += (str(result[index]) + self.unit[index])
            return prompt
    
        # 开始计时
        def start(self):
            self.begin = t.localtime()
            self.prompt = "提示:请先调用stop()停止计时!"
            print("计时开始")
    
    
        # 停止计时
    
        def stop(self):
            if not self.begin:
                print("提示:请先调用start()进行计时")
            else:
                self.end = t.localtime()
                self._calc()
                print("计时结束")
    
        # 内部方法,计算运行时间
        def _calc(self):
            self.lasted = []
            self.prompt = "总共运行了"
            for index in range(6):
                self.lasted.append(self.end[index] - self.begin[index])
                if self.lasted[index]:
                    self.prompt += (str(self.lasted[index]) + self.unit[index])
            # 为下一轮计时初始化变量
            self.begin = 0
            self.end = 0
            print(self.prompt)
    
    >>> t1 = MyTimer()
    >>> t2 = MyTimer()
    >>> t1.start()
    计时开始
    >>> t2.start()
    计时开始
    >>> t1.stop()
    总共运行了1分21秒
    计时结束
    >>> t2.stop()
    总共运行了15秒
    计时结束
    >>> t1
    总共运行了1分21秒
    >>> t2
    总共运行了15秒
    >>> t1+t2
    '总共运行了1分36秒'
    

    利用perf_counter()和process_time()

    import time as t
    
    class MyTimer:
        def __init__(self):
            self.prompt = "未开始计时"
            self.lasted = 0.0
            self.begin = 0
            self.end = 0
            self.default_timer = t.perf_counter
    
        def __str__(self):
            return self.prompt
        __repr__ = __str__
        def __add__(self,other):
            result = self.lasted + other.lasted
            prompt = "总共运行了%0.2f秒" % result
            return prompt
        def start(self):
            self.begin = self.default_timer()
            self.prompt = "提示:请先调用stop()停止计时"
            print("计时开始!")
        def stop(self):
            if not self.begin:
                print("提示:请先调用start()开始计时")
            else:
                self.end = self.default_timer()
                self._calc()
                print("计时结束")
        def _calc(self):
            self.lasted = self.end - self.begin
            self.prompt = "总共运行了%0.2f秒" % self.lasted
            print(self.prompt)
            self.begin = 0
            self.end = 0
    
        def set_timer(self,timer):
            if timer == 'process_time':
                self.default_timer = t.process_time
            elif timer == 'perf_counter':
                self.default_timer = t.perf_counter
            else:
                print("输入无效")
    
    
    t1 = MyTimer()
    t1.set_timer('perf_counter')
    t1.start()
    t.sleep(5.2)
    t1.stop()
    t2 = MyTimer()
    t2.set_timer('perf_counter')
    t2.start()
    t.sleep(5.2)
    t2.stop()
    print(t1 + t2)
    
    
     >>> 
    计时开始!
    总共运行了5.23秒
    计时结束
    计时开始!
    总共运行了5.21秒
    计时结束
    总共运行了10.44秒
    >>>
    

    4.属性访问

    魔法方法 含义
    __ getattr__(self, name) 定义当用户试图获取一个不存在的属性时的行为
    __ getattribute__(self, name) 定义当该类的属性被访问时的行为
    __ setattr__(self, name, value) 定义当一个属性被设置时的行为
    __ delattr__(self, value) 定义当一个属性被删除时的行为

    避免属性魔法方法的死循环:

    使用super()调用基类、给特殊属性__dict__赋值

    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)
               self.__dict__[name] = value
    
        def getArea(self):
            return self.width * self.height
    
    >>> r1 = Rectangle(4,5)
    >>> r1.getArea()
    20
    >>> r1.square = 10
    >>> r1.getArea()
    100
    >>>
    

    5. 描述符

    将某种特殊类型的类的实例指派给另一个类的属性

    __get__(self,instance,owner) 访问属性,返回属性的值
    __set__(self,instance,value) 在属性分配中调用,不返回任何内容
    __delete__(self,instance) 控制删除操作,不返回任何值
    >>> class Mydecript:
    	def __get__(self,instance,owner):
    		print("getting...",self,instance,owner)
    	def __set__(self,instance,value):
    		print("setting...",self,instance,value)
    	def __delete__(self,instance):
    		print("deleting...",self,instance)
    
    	
    >>> class Test:
    	x = Mydescript()
    
    	
    Traceback (most recent call last):
      File "", line 1, in 
        class Test:
      File "", line 2, in Test
        x = Mydescript()
    NameError: name 'Mydescript' is not defined
    >>> class Test:
    	x = Mydecript()
    #Mydecript是x的描述类
    	
    >>> test = Test()
    >>> test.x
    getting... <__main__.Mydecript object at 0x030EAFB0> <__main__.Test object at 0x03108050> 
    >>> test.x = "X-man"
    setting... <__main__.Mydecript object at 0x030EAFB0> <__main__.Test object at 0x03108050> X-man
    >>> del test.x
    deleting... <__main__.Mydecript object at 0x030EAFB0> <__main__.Test object at 0x03108050>
    

    例题:温度的转换

    class Celsius:
        def __init__(self,value = 26.0):
            self.value = float(value)
    
        def __get__(self,instance,owner):
            return self.value
    
        def __set__(self,instance,value):
            self.value = float(value)
    
    class Fahrenheit:
        def __get__(self,instance,owner):
            return instance.cel * 1.8 + 32
    
        def __set__(self,instance,value):
            instance.cel = (float(value) - 32) / 1.8
            
    class Temperature:
        cel = Celsius()
        fah = Fahrenheit()
    
        
    >>> temp = Temperature()
    >>> temp.cel
    26.0
    >>> temp.cel = 30
    >>> temp.fah
    86.0
    >>> temp.fah = 100
    >>> temp.cel
    37.77777777777778
    >>> 
    

    6.定制序列

    Python魔法方法详解

    例题:编写一个不可变的自定义列表,要求记录列表中每个元素被访问的次数

    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
            return self.values[key]
    
          
    >>> c1 = CountList(1,3,5,7,9)
    >>> c1[1]
    3
    >>> c2 = CountList(2,4,6,8,10)
    >>> c2[1]
    4
    >>> c1[1]+c2[1]
    7
    >>> c1.count
    {0: 0, 1: 2, 2: 0, 3: 0, 4: 0}
    >>> c2[1]
    4
    >>> c2.count
    {0: 0, 1: 3, 2: 0, 3: 0, 4: 0}
    >>> 
    

    7.迭代器

    迭代器是实现了__next__()方法的对象,不能回退

    >>> string = "FishC"
    >>> it = iter(string)
    >>> next(it)
    'F'
    >>> next(it)
    'i'
    >>> next(it)
    's'
    >>> next(it)
    'h'
    >>> next(it)
    'C'
    >>> next(it)
    Traceback (most recent call last):
      File "", line 1, in 
        next(it)
    StopIteration
    >>> string = "FishC"
    >>> it = iter(string)
    >>> while True:
    	try:
    		each = next(it)
    	except StopIteration:
    		break
    	print(each)
    
    	
    F
    i
    s
    h
    C
    >>> for each in string:
    	print(each)
    
    	
    F
    i
    s
    h
    C
    >>> 
    

    例题:使用迭代器实现斐波那契数列

    >>> class Fibs:
    	def __init__(self,n=10):
    		self.a = 0
    		self.b = 1
    		self.n = n
    	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()
    >>> for each in fibs:
    	print(each)
    
    	
    1
    1
    2
    3
    5
    8
    
  • 相关阅读:
    第 1 章 代码无错便是优?——简单工厂模式
    [转载]由浅入深探究mysql索引结构原理、性能分析与优化
    jquery中 $.expr使用实例介绍
    jQuery UI Widget(1.8.1)工作原理
    asp.net url重写
    CJL.0.1.js
    React Context 的用法
    小程序组件使用
    深入理解es5中Object.defineProperty()
    React合成事件
  • 原文地址:https://www.cnblogs.com/lelezuimei/p/11328687.html
Copyright © 2011-2022 走看看