Python类和继承

本文详细介绍了Python中的类定义、对象创建、静态方法和类方法,包括属性访问、实例化、初始化。同时,讲解了继承的概念,包括单一继承和方法查找的动态约束。还提到了`super()`函数在多态中的应用,以及如何通过`super()`实现方法调用。此外,文章还展示了如何定义和使用静态方法和类方法,以及如何处理类之间的关系和方法重写。
摘要由CSDN通过智能技术生成

1.类的定义

1.1 类的定义和使用:

  1. 类定义
	class <类名>  
	<语句组> 
  1. 类对象及其使用
    执行一个类定义将创建一个类对象 :
  • 属性访问(成员变量)
  • 实例化
  • 实例对象 : 初始化和使用
    创建一个类的实例对象:实例对象名 = 类名(属性),将自动调用 类中的 init() 方法完成初始化
class C:  
    """:arg  
        说明:  
            Python 中提供了一个内置函数 isinstance(),专门用来检查类和对象的关系。  
            isinstance(obj, cls) : 检测对象obj是否为类cls的实例,是则返回True,否则返回False;  
            也可以检测 任何对象 和 任何类型的关系 eg:            isinstance(12, int) : 判断一个变量是否为int型  
    """    
    def __init__(self, m=1, n=1):  
        self._m = m       # _m 表示 该变量是私有的,只能在类中使用  
        self._n = n       # 成员变量,又叫 数据属性  
        self.__x = 10  
    # 定义方法函数,self 表示 本实例对象,self 是约定俗称的写法,可以写其他的my等  
    def m(self, a, b):  
        return self._m * a + self._n * b  
    pass

1.2 静态方法和类方法

  1. 静态方法
  • 定义:def 行前 加修饰符 @staticmethod
  • 静态方法是 普通函数,只是由于某种原因需要定义在类里面。
  • 静态方法的参数可以根据需要定义,不需要特殊的 self 参数
  • 调用:通过 类名.静态方法名() 或者 实例对象.静态方法名()
    eg : Rational1 类 中的 _gcd() 方法即是静态方法。
  1. 定义一个计数器,返回 该类中实例化多少个对象

get_count() 即是一个 类方法:

  • 定义形式为 def 前, 加修饰符 @classmethod
  • 这种方法必须有一个表示其调用类的参数,习惯用 cls 作为参数名,还可以有任意多个其它属性
  • 类方法 也是 类对象的 属性, 可以 以 属性访问形式调用
  • 在类方法执行时,调用它的类将自动约束到方方的cls参数,可以通过这个参数访问该类的其他属性
class Countable:  
    counter = 0  
  
    def __init__(self):  
        Countable.counter += 1  
  
    @classmethod              # 类方法
    def get_count(cls):  
        return Countable.counter  
    pass
class  Rational1:  
    """:arg  
        1.考虑输入时分母不为0,输入数字有正负之分,我们统一规定输入的分母都为正,分子为正则为正分数,分子为负则为负分数  
        2.对结果进行约分时,我们需要找到醉倒公约数,该方法的定义是局部使用的,可以说是可以分离出来的,我们定义静态方法  
            方法前加入: @staticmethod            方法里去掉   self            静态方法的调用: 类名.静态方法()  或者 实例对象.静态方法()  
        本质上说 静态方法是类里面定义的普通函数,但也是该类的局部函数。  
  
        辗转相除法求2个数的最大公约数:  
        例:求 80 和 75 的最大公约数:  
        80 / 75 = 1......5        75 / 5 = 15......0        5 / 0        则最大公约数为 5  
        30 % 5 = 0        5 % 0    """    
    @staticmethod  
    def _gcd(m, n):     # _ : 方法名前单个下划线:当做内部使用的名字,不能在这个类外使用  
        if m < n:  
            m, n = n, m     # 保证 m > n        while n != 0:  
            m, n = n, m % n  
        return m            # 当 余数为0时, m 的值即为这m/n的最大公约数  
  
    def __init__(self, num, den=1):  
        if not isinstance(num, int) or not isinstance(den, int):  
            raise TypeError  
        if den == 0:  
            raise ZeroDivisionError  
        sign = 1        # 分母正负的标志  
        if num < 0:  
            num, sign = -num, -sign  
        if den < 0:  
            den, sign = -den, -sign  
        g = Rational1._gcd(num, den)  
        # print(f'g:{g}')  
  
        self._num = sign * (num // g)  
        self._den = den // g  
  
    def print(self):  
        print(str(self._num) + '/' + str(self._den))  
  
#   成员变量是私有的,只能在本类中使用,不能 对象.成员变量名 调用,如果要使用成员变量可以定义实例方法  
    def num(self):  
        return self._num  
  
    def den(self):  
        return self._den  
  
#   有理数的运算,Python中的特殊方法名:都以2个下划线开始,并以2个下划线结束。  
#     +  
    def __add__(self, another):  
        den = self._den * another.den()     # 通分  
        num = (self._num * another.den() + self._den * another.num())  
        return Rational1(num, den)  
  
#     -  
    def __sub__(self, another):  
        num = self.num * another.den() - self._den * another.num()  
        den = self._den * another.den()  
        return Rational1(num, den)  
  
    # *  
    def __mul__(self, another):  
        return Rational1(self._num * another.num(), self._den * another.den())  
  
    # 整除 : //    def __floordiv__(self, another):  
        if another.num() == 0:  
            raise ZeroDivisionError  
        return Rational1(self._num * another.den(), self._den * another.den())  
  
#   比较有理数对象相等或不等  
#     == : __eq__  
    def __eq__(self, another):  
        return self._num * another.den() == self._den * another.num()  
  
#     < : __lt__  
    def __lt__(self, another):  
        return self._num * another.den() < self._den * another.num()  
  
#     > : __gt__  
    def __gt__(self, another):  
        return self._num * another.den() > self._den * another.num()  
  
#     != : __ne__  
    def __ne__(self, another):  
        return self._num * another.den() != self._den * another.num()  
  
#     <= : __le__  
    def __le__(self, another):  
        return self._num * another.den() <= self._den * another.num()  
  
#     >= : __ge__  
    def __ge__(self, another):  
        return self._num * another.den() >= self._den * another.num()  
  
#   定义把类的对象 转化成 字符串: __str__ , 内置 str 将会调用它  
    def __str__(self):  
        return str(self._num) + "/" + str(self._den)  
  
    def print(self):  
        print(type(self._num), type(self._den))  
        print(self._num, "/", self._den)  
    pass

2.继承

2.1 继承的定义:

class <类名>(BaseClass, ...):  
    <语句组>  

通过继承定义出的新类称为 派生类(或者 字类),被继承的已有类,称为 基类(或者 父类),一个新定义的 派生类 可以继承多个 基类。

(BaseClass, …), 括号里面的"参数"是指定的基类,可以有一个或多个。

class MyStr(str):  
    ''':arg  
        MyStr 类 继承了 str 类,派生类里面没有任何操作  
    '''    
    pass

# issubclass(cls1, cls2) : 判断 cls2 是否为 cls1 的基类(父类),若是,则返回 True,否则返回 Falses = MyStr(1234)             # 创建 MyStr 类型的对象  
print(issubclass(MyStr, str))  
print(isinstance(s, MyStr))  
print(isinstance(s, str))   # 派生类对象也是基类的对象

2.2 继承常见的形式

派生类经常需要重新定义 init 函数,完成该类实例的初始化。
常见情况是要求 派生类的对象可以作为基类的对象,用在要求基类对象的环境中。

  1. 常见形式:
class DerivedClass(BaseClass):  
    def __init__(self, ...):        
	    BaseClass.__init__(sefl, ...) # 调用 基类(父类) 的 __init__ 函数  
        .......     # 初始化的其他操作  
    # 派生类的其他语句和函数定义  

以上语句,初始化时调用 基类 的 init 方法,对基类对象的所有 数据属性(成员变量)进行初始化。

  1. 方法查找
    派生类的实例对象调用一个方法时,派生类和父类都有该方法时或者仅有一方有该方法,该怎样寻找哪?
    如果从一个派生类的实例对象出发去调用方法,Python 解释器需要确定应该调用按个函数。
    查找过程是 从该实例对象所属的类开始查找,没有找到则查找该实例对象对应类的基类中查找,如果最终都没有
    查找到函数属性,那就是属性无定义。
class B:  
    def f(self):  
        self.g()  
  
    def g(self):  
        print('B.g called.')    # 基类(父类)中定义有 g() 方法  
  
  
class C(B):                     # 派生类 C 继承 基类 B    def g(self):                # 派生类中 也定义了 g()        print('C.g called.')  
  
  
x = B()             # 创建 B 的实例对象 xx.f()               # 调用 f() 函数  
  
y = C()             # y 是 类C 的实例对象  
y.f()               # 此时类B中的f() 里的 g() 是调用 类B 还是 类C 里的哪?
  1. 静态约束 和 动态约束

执行情况:y 是 类C 的实例化对象,Python解释器先从 类C 中查找f(), 一遍之后没有找到,则去基类
B 中去查找,查找到之后,则执行 基类的 f() 方法, 此时出现问题:
基类 f() 里有一个 g(),我们该执行 类B 还是 类C 里的 g() 哪?

  1. 因为 y 是 类C 的实例对象,因为 派生类中没有 f() ,则调用 基类中的f()
  2. 基类中的self则指向是实例对象 y, 因此 self.g() 即是调用 y.g(),故调用 C类中的g() 方法。
    以上即是 动态约束(大多数面向对象的语言都是这样的)。

静态约束(静态绑定):上例中 self.g() 直接调用 类f 里的g()方法,则为静态约束。

  1. 标准函数 super()

Python 中提供了一个内置函数 super(), 就是要求从这个类的 直接基类开始做属性检索,而不是从这个类本身开始查找。
采用 Super函数 而不是直接写基类名字,产生的查找更加的灵活。super() 函数的使用分为2种:

  • 不带参数的调用形式
    super().m(…) 这种形式只能出现在方法函数的定义里,在函数调用时,当前实例将被作为被调用函数的self实参。
  • 带参数的调用
    super(C, obj).m(…) 这种写法要求从指定的类C的基类开始查找函数属性m, 调用里出现的 obj 必须是类C的一个实例。Python解释器找到函数m,将用 obj 作为该函数
    的self实参。这种写法可以出现在程序的任何地方,并不要求一定出现在类的方法函数里。
class C1:  
    def __init__(self, x, y):  
        self.x = x  
        self.y = y  
  
    def m1(self):  
        print(self.x, self.y)  
  
  
class C2(C1):  
    def m1(self):  
        super().m1()            # 从基类查找 函数 m()        print("这是派生类")  
  
  
c = C2(10, 20)      # class C2 没有定义 init方法,初始化时直接调用 基类 C1 的init方法  
c.m1()              # 调用 class C2 的 m1()

[完]

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值