Python — magic method

Python 中内置的特定的方法, 这些方法在进行特定的操作时,会自动被调用。

__init__(self, [ ])  # 类的构造函数, 用于初始化实例变量 不允许做任何形式的return

__new__(cls, [ ]) # 类的内置方法  对象实例化过程中第一个被调用的方法

  由于__init__()方法不能够返回一个非None的值,因此在实例化对象时不能够通过该方法对不可变对象(str、tuple)进行改变,此使可以重写__new__()方法,在__new__()方法中对不可变对象进行处理,返回需要的结果。

(构造方法__init__() 与 __new__())

 1 class A(str):
 2     def __init__(self, string):
 3         super().__init__()
 4         # 在 __init__()中 即使对 string 进行操作也不能够返回一个有效的值
 5 
 6     def __new__(cls,string):
 7         string = string.upper()
 8         return str.__new__(cls, string)
 9         #能够返回值
10     
11 a = A('yi jing beng pan le ')
12 print(a)
13 
14 ###################################3
15 YI JING BENG PAN LE 

__del__(self)       # 当对象的引用为 0 时调用 该方法, 并不是del 时调用该方法 (析构方法)

  示例代码如下,这是在IDLE中运行的结果,但是在jupyter notebook中运行的结果并不相同 在第二次实例化对象时仍然调用了 该方法。。。。。。。。。。

 1 >>> class A():
 2     def __init__(self):
 3         print('nothing')
 4     def __del__(self):
 5         print('del BIF 被调用了')
 6 
 7         
 8 >>> a = A()
 9 nothing
10 >>> b = a
11 >>> del a
12 >>> del b
13 del BIF 被调用了
14 >>> 

工厂函数:

  工厂函数即是类对象,在调用该函数时会生成一个实例对象。

 

算术运算的 内置方法。对象可以进行算术运算,可通过修改这些方法,改变对象的行为

  重写__add__()方法,要避免在算术运算方法中加入算术运算方法,避免出现无限递归的调用

 

1 >>> class new_int(int):
2     def __add__(self, x):
3         return int.__sub__(self, x)
4 
5     
6 >>> a = new_int(10)
7 >>> b = new_int(12)
8 >>> a + b
9 -2

以下两种方式的区别:在try_int(第8行)定义的__add__()方法中使用 int()工厂函数进行了类型转换,由于工厂函数即是类对象的实例化,因此int(self)相当于重新实例化一个对象,进行加法操作,此时不会再调用c或d的__add__()方法。因此不会出现递归调用。

 1 >>> class new_int(int):
 2     def __add__(self, x):
 3         return self + x
 4 
 5     
 6 >>> class try_int(int):
 7     def __add__(self, x):
 8         return int(self) + int(x)
 9 
10     
11 >>> a = new_int(10)
12 >>> b = new_int(10)
13 >>> a + b
14 Traceback (most recent call last):
15   File "<pyshell#10>", line 1, in <module>
16     a + b
17   File "<pyshell#3>", line 3, in __add__
18     return self + x
19   File "<pyshell#3>", line 3, in __add__
20     return self + x
21   File "<pyshell#3>", line 3, in __add__
22     return self + x
23   [Previous line repeated 991 more times]
24 RecursionError: maximum recursion depth exceeded
25 >>> c = try_int(10)
26 >>> d = try_int(10)
27 >>> c + d
28 20
29 >>> 

 

反运算符的变量顺序。

 

__str__() 与 __repr__()方法:

  __str__():当需要打印输出对象时(print(object)),调用的方法。__repr__()直接输入对象名称返回值。

 

 1 class test():
 2     def start(self):
 3         self.start = 10
 4         
 5 t = test()
 6 t.start()
 7 t.start()
 8 
 9 ######################################
10 ---------------------------------------------------------------------------
11 TypeError                                 Traceback (most recent call last)
12 <ipython-input-71-6aae66d56b58> in <module>
13       5 t = test()
14       6 t.start()
15 ----> 7 t.start()
16 
17 TypeError: 'int' object is not callable

 

再一次强调,属性名与方法名重复会发生覆盖现象。请注意只有第七行报错:TypeError,原因时再第六行执行代码后会产生 第三行的同名变量,而后定义的变量会覆盖方法。

 

 

定义一个定时器的类,并通过重载其内部方法实现,定时器开始,结束,结果显示,及定时器对象的 加 (+,将两个定时器的时间相加并显示)操作。

  需要注意,三个类方法在实例化后的调用顺序,如在start() 调用之前调用 stop()、未调用stop()而调用 + 操作,通过实例变量 message,对当前操作进度进行记录,并通过对时间的判断进行错误提醒,有点类似于状态机的状态码。

# 通过重定义内置方法 定制类

import datetime

class Mytimer():
    num = 0
    
    def __init__(self):
        self.__class__.num += 1
        self.start_time = 0
        self.stop_time = 0
        self.time_sec = 0
        self.message = '未开始计时!'
    
    # 重定义 __str__ 以及 __repr__内置函数 用于控制输出
    def __str__(self):
        return self.message
    
    __repr__ = __str__
    
    def __add__(self, time):
        if self.time_sec and time.time_sec:
            add_result = self.time_sec + time.time_sec
            self.message = '总共计时时间为:' + str(add_result)
        else:
            self.message = '计时未结束!'
        return self.message
    
    def start(self):
        self.start_time = datetime.datetime.now()
        print('计时开始!')
        self.message = '未结束计时!'
    
    def stop(self):
        if self.start_time:
            self.stop_time = datetime.datetime.now()
            delta_time = self.stop_time - self.start_time
            self.time_sec = delta_time.total_seconds()
            self.message = '计时结果为:' + str(self.time_sec) +'S'
            print('计时结束!')
        else:
            print('Plz run start first!')

t = Mytimer()
t1 = Mytimer()

定义类方法时需要注意实例变量与 函数的局部变量的区别,由于函数的局部变量生存空间仅限于该函数内部,因此需要在函数之间调用的变量需要设置未实例变量。实例变量与类变量之间由于作用对象不同,相互没有影响,类变量用于描述这个抽象类的属性,而实例变量用于描述实例化对象的属性。注意实例变量名与方法名不能相同,否则在__init__()初始化后会导致与变量名相同的函数被覆盖。

 

posted @ 2019-02-27 18:55  已经崩盘了  阅读(339)  评论(0编辑  收藏  举报