9.多继承、类的特殊方法、装饰器

1.多继承

当继承的类有同种方法的时候,只会继承前面一个的方法。调用父类方法super()

#1.多继承

class Base:
    def play(self):
        print('这是Base')


class A(Base):
    def play(self):
        print(type(self))
        print('这是A')


class B(Base):
    def play(self):
        print('这是B')


class C(A,B):
    
    #子类调用父类方法
    def play(self):
        #A.play(self)  #第一种方法
        #B.play(self)

        #super().play()     #第二种方法,默认调用第一个父类方法
        #super(C,self).play() #括号不写,默认(C,self)

        #super(A,self).play()  # Base
        #super(B,self).play()   # A   ,  上一层
        #super(Base,self).play()
        print('这是C')

        

c = C()  # (B,A)  C  -> B  -> A  -> Base  ->object

         # (A,B)  C  -> A  -> B  -> Base  ->object

C().__class__.mro()

'''
super, 上一层
1.super(),    (自己类名,自己实例) 例:( C,c )

2. 谁调用我,我就以你为基准。 建立一张调用顺序表
    ‘(B,A)   C  -> B  -> A  -> Base  ->object ’


'''

2.类的特殊方法

#类属性:
    __dict__     # 类的属性(包含一个字典,由类的数据属性组成)
    __doc__     # 类的文档字符串
#类方法:  
    __init__    # 初始化
    __repr__    # 直接返回这个对象  repr() 函数就是调用对象的这个方法
    __str__     # print(obj) 如果类里面定义了__repr__,没有定义__str__ print(obj)也会返回__repr__的内容,或者说__repr__的优先级更高
    __call__    # Obj() 使实例可被调用
    
#运算符方法
    __add__(self,other)     #x+y
    __sub__(self,other)     #x-y 
    __mul__(self,other)     #x*y  
    __mod__(self,other)     #x%y
    __iadd__(self,other)    #x+=y
    __isub__(self,other)    #x-=y 
    __radd__(self,other)    #y+x
    __rsub__(self,other)    #y-x 
    __imul__(self,other)    #x*=y 
    __imod__(self,other)    #x%=y 
    
#和类有关的几个函数  
    delattr()        # 删除对象属性
    getattr()        # 得到某个属性值
    setattr()        # 给对象添加某个属性值
    hasattr()          # 判断对象object是否包含名为name的特性
    isinstance()      # 检查对象是否是类的对象,返回True或False
    issubclass()      # 检查一个类是否是另一个类的子类。返回True或False    
'''
不仅仅是属性,更多是方法

'''

class Rectangle:
    '''这是一个长方形类,它可以计算面积'''
    aaa = 1
    def __init__(self,length,width):     #构造方法
        if isinstance(length,(int,float)) and isinstance(width,(int,float)):
            self.length = length
            self.width = width
        else:
            print('请输入int or float')

    def area(self):
        return self.length * self.width

##    def __str__(self):
##        return  '这个长方形的面积%s'%self.area()

    def __repr__(self):
        return '长:%s  宽:%s'%(self.length,self.width)

    def __call__(self):
        return '我这是一个Rectangle 类,你要干嘛'

    def __add__(self,other):
        return self.area() + other.area()
        
    def __sub__(self,other):
        return '不可以相减'


    
r = Rectangle(2,3)

#类属性

#__dict__ 

r.__dict__   # 打印实例里面的属性 ,{'length': 2, 'width': 3}


#注意  ,共有属性。当不修改时,默认引用(源类 Rectangle ),
                # 修改之后,就会定义在 实例里面
r.aaa = 22
r.__dict__


#__doc__
r.__doc__


#类方法 

#__str__    
#print(r)

#__repr__
r

'%s'%'ssss'   
'%r'%'rrrr'

#print  默认调用__str__   ,没有时__repr__




####  __call__
#r()
r()  # '我这是一个Rectangle 类,你要干嘛'

def dd():
    print('dd')

dir(dd)   #'__call__'



r1 = Rectangle(2,4)
r2 = Rectangle(3,5)

#   __add__(self,other)


#__sub__(self,other)     #x-y 




####
'''
delattr()        # 删除对象属性
getattr()        # 得到某个属性值
setattr()        # 给对象添加某个属性值
hasattr()          # 判断对象object是否包含名为name的特性
isinstance()      # 检查对象是否是类的对象,返回True或False
issubclass()      # 检查一个类是否是另一个类的子类。返回True或Fals
'''

3.装饰器

装饰器(deco):
    装饰函数的参数是被装饰的函数对象,返回原函数对象装饰器本质上是一个Python函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外功能,装饰器的返回值也是一个函数对象
    概括的讲,装饰器的作用就是为已经存在的对象添加额外的功能。
###3.装饰器 ,添加附加功能

#闭包

def fx(x):
    x += 1
    def fy(y):
        return x*y
    
    return fy

'''
fx(1)(2)
temp = fx(1)
temp(2)
'''


def f1(func):
    print('f1 running')
    def f2(y):
        print('f2 running')
        return func(y)+1
    return f2
    

def gun(m):
    print('gun running')
    return m*m

'''
f1(gun)
temp = f1(gun)
temp(5)
'''


@f1
def gun2(m):
    print('gun running')
    return m*m

'''
1.  @f1  ->   f1( gun2 )   -> f2
2.  f2  ,等待调用
3.  gun2   (5)  ->  当参数 5传入 --> f2(5)
4.  f2(5), 开始运行  ->  print('f2 running') ->  func(y): func = gun2  y = 5  ->{{func(y) 等于 gun2(5)}}
5.  gun2(5) 开始运行  -> print('gun running') ->  25
6.  25 +1  -> 26
 
'''



##测试时间

'''
import time   
def run_time(func):
    def new_fun(*args,**kwargs):
        t0 = time.time()
        print('star time: %s'%(time.strftime('%x',time.localtime())) )
        back = func(*args,**kwargs)
        print('end time: %s'%(time.strftime('%x',time.localtime())) )
        print('run time: %s'%(time.time() - t0))
        return back
    return new_fun

'''


import time  #不要纠结

def run_time(func):
    def new_fun():
        t0 = time.time()
        print('star time: %s'%(time.strftime('%x',time.localtime())) )
        func()
        print('end time: %s'%(time.strftime('%x',time.localtime())) )
        print('run time: %s'%(time.time() - t0))
        
    return new_fun



@run_time
def test():
    for i in range(1,10):
        for j in range(1,i+1):
            print('%dx%d=%2s'%(j,i,i*j),end = ' ')
        print ()

        
##########  留个映像,用的不是很多

4.类装饰器

@property 
    装饰过的函数返回的不再是一个函数,而是一个property对象
    装饰过后的方法不再是可调用的对象,可以看做数据属性直接访问。

@staticmethod #(静态方法)
    把没有参数的函数装饰过后变成可被实例调用的函数,      
    函数定义时是没有参数的,可以不接收参数

@classmethod (类方法)
    把装饰过的方法变成一个classmethod类对象,既能能被类调用又能被实例调用。
    注意参数是cls代表这个类本身。而是用实例的方法只能被实例调用。     
        
一般来说,要使用某个类的方法,需要先实例化一个对象再调用方法。
而使用@staticmethod或@classmethod,就可以不需要实例化,直接类名.方法名()来调用。
这有利于组织代码,把某些应该属于某个类的函数给放到那个类里去,同时有利于命名空间的整洁
##类装饰器
class Test_Class():
    def __init__(self,func):
        self.func = func

    def __call__(self):
        print('')
        return self.func


@Test_Class
def  test():
    print('这是一个测试')

test()  #    self.func : test 函数体
test()()

# 1. @Test_Class : Test_Class( test ) -> 相当于:t = Test_Class( test )
# 2. test() -> 相当于: t() 调用实例的call方法 -> 返回 self.func函数体
# 3. test()() 调用test()

###python自带3个,类的内置装饰器
class Rectangle:
    '''这是一个长方形类,它可以计算面积'''
    aaa = 1
    def __init__(self,length,width):     #构造方法
        if isinstance(length,(int,float)) and isinstance(width,(int,float)):
            self.length = length
            self.width = width
        else:
            print('请输入int or float')

    @property  # 可以把方法,当成属性一样调用  , r.area
    def area(self):
        return self.length * self.width
    
    @staticmethod   #静态方法, 不用self了,实例可以直接调用
    def func():
        print('可以调用吗?')

    @classmethod   #将实例,还原成了类cls   self实例
    def show(cls):
        print(cls)
        print('show fun')


r = Rectangle(2,3)

5.作业

1.测试type 和 isinstance 那个的速度更快

import time

def run_time(func):
    def new_fun():
        t0 = time.time()
        print(t0)
        func()
        t1 = time.time() - t0
        return t1
    return new_fun

@run_time
def test_type():
    for i in range(100):
        i = i*2
        type(i) == int
    print('结束')

@run_time
def test_isinstance():
    for i in range(100):
        i = i*2
        isinstance(i,(int,float))
    print('结束')

def test():
    a=test_type()   #t1
    b=test_isinstance()  #t1
    if a>b:
        print('isinstance更快')
    else:
        print('type更快')
    
View Code

2.实现一个正方形类的加减乘除(就那些魔术方法,能写多少写多少)

class Square(object):
    def __init__(self,length):
        self.length = length
        self.area = length**2

    def __add__(self,other):   #  __add__ 
        return self.area + other.area

    def __sub__(self,other):
        return self.area - other.area

    def __mul__(self,other):
        return self.area * other.area

    def __truediv__(self,other):
        return self.area / other.area
View Code
原文地址:https://www.cnblogs.com/woaixuexi9999/p/9215609.html