Python -- 面向对象进阶

目录

1.类方法、静态方法

1.1 类方法

1.2 静态方法

2.单例设计模式

2.1 __new__和__init__方法

3.继承

3.1 单继承

3.2 多继承

4.对象相关的运算符和内置函数

4.1 身份运算符

 5.多态的使用


1.类方法、静态方法

1.1 类方法

  • 第一个形参是类对象的方法

  • 需要用装饰器@classmethod来标识其为类方法,对于类方法,第一个参数必须是类对象,一般以cls作为第一个参数。

 class Dog(object):
     __type = "狗"
 
     # 类方法,用classmethod来进行修饰
     @classmethod
     def get_type(cls):
         return cls.__type
 print(Dog.get_type())

使用场景:

  • 当方法中 需要使用类对象 (如访问私有类属性等)时,定义类方法

  • 类方法一般和类属性配合使用

1.2 静态方法

  • 需要通过装饰器@staticmethod来进行修饰,静态方法既不需要传递类对象也不需要传递实例对象(形参没有self/cls)

  • 静态方法 也能够通过 实例对象类对象 去访问。

 class Dog(object):
     type = "狗"
 
     def __init__(self):
         name = None
 
     # 静态方法    
     @staticmethod
     def introduce():  # 静态方法不会自动传递实例对象和类对象
         print("犬科哺乳动物,属于食肉目..")
 
 dog1 = Dog()
 Dog.introduce()    # 可以用 实例对象 来调用 静态方法
 dog1.introduce()    # 可以用 类对象 来调用 静态方法

使用场景:

  • 当方法中 既不需要使用实例对象(如实例对象,实例属性),也不需要使用类对象 (如类属性、类方法、创建实例等)时,定义静态方法

  • 取消不需要的参数传递,有利于 减少不必要的内存占用和性能消耗

注意:

  • 类中定义了同名的方法时,调用方法会执行最后定义的方法

 class Dog:
 
     def demo_method(self):
         print("对象方法")
 
     @classmethod
     def demo_method(cls):
         print("类方法")
 
     @staticmethod
     def demo_method():  # 被最后定义
         print("静态方法")
 
 dog1 = Dog()
 Dog.demo_method()  # 结果: 静态方法
 dog1.demo_method()  # 结果: 静态方法

2.单例设计模式

2.1 __new____init__方法

 class A(object):
     def __init__(self):
         print("这是 init 方法")
 
     def __new__(cls):
         print("这是 new 方法")
         return object.__new__(cls)
 
 A()

总结

  • __new__至少要有一个参数cls,代表要实例化的类,此参数在实例化时由Python解释器自动提供

  • __new__必须要有返回值,返回实例化出来的实例,这点在自己实现__new__时要特别注意,可以return父类__new__出来的实例,或者直接是object的__new__出来的实例

  • __init__有一个参数self,就是这个__new__返回的实例,__init____new__的基础上可以完成一些其它初始化的动作,__init__不需要返回值

举个常见的单例模式例子,我们日常使用的电脑上都有一个回收站,在整个操作系统中,回收站只能有一个实例,整个系统都使用这个唯一的实例,而且回收站自行提供自己的实例。因此回收站是单例模式的应用。

确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例,这个类称为单例类,单例模式是一种对象创建型模式。

 # 实例化一个单例
 class Singleton(object):
     __instance = None
     __is_first = True
 
     def __new__(cls, age, name):
         if not cls.__instance:
             cls.__instance = object.__new__(cls)
         return cls.__instance
 
     def __init__(self, age, name):
         if self. __is_first: # 不会再创建第二个对象
             self.age = age
             self.name = name
             Singleton. __is_first = False
 
 
 a = Singleton(18, "张三")
 b = Singleton(28, "张三")
 
 print(id(a))
 print(id(b))
 
 print(a.age) # 18
 print(b.age) # 18
 
 a.age = 19
 print(b.age)

3.继承

在现实生活中,继承一般指的是子女继承父辈的财产,父辈有的财产,子女能够直接使用。

程序里的继承

继承是面向对象软件设计中的一个概念,与多态、封装共为面向对象的三个基本特征。继承可以使得子类具有父类的属性和方法或者重新定义、追加属性和方法等。

 

  • 在程序中,继承描述的是多个类之间的所属关系。

  • 如果一个类A里面的属性和方法可以复用,则可以通过继承的方式,传递到类B里。

  • 那么类A就是基类,也叫做父类;类B就是派生类,也叫做子类。

 class Animal:
     def __int__(self):
         pass
     """动物类"""
     def sleep(self):
         print('正在睡觉')
 
 
 class Dog(Animal):
     """Dog类继承自Animal类"""
     def __init__(self):
         pass
 
 class Cat(Animal):  # 定义类时,在括号后面传入父类的类名,表示子类继承父类
     """Cat类继承自Animal类"""
     def __int__(self):
         pass
 
 # Dog 和 Cat 都继承自Animal类,可以直接使用Animal类里的sleep方法
 dog = Dog()
 dog.sleep()
 
 cat = Cat()
 cat.sleep()

在Python中,继承可以分为单继承、多继承和多层继承。

3.1 单继承

子类只继承一个父类。

继承概念:子类用于父类的所有的方法和属性。

 继承语法:

 class 类名(父类名):
     pass
  • 子类继承自父类,可以享受父类中已经封装好的方法,不需要再次定义

  • 子类中应该根据职责,封装子类特有的属性和方法。

继承的传递性

Dog类继承自Animal,XiaoTianQuan又继承自Dog类,那么XiaoTianQuan类就具有了Animal类里的所有属性和方法。

子类拥有父类以及父类的父类中封装的所有属性和方法。

思考:

XiaoTianQuan能否调用Animal的run()方法?XiaoTianQUan能够调用Cat里的方法?

3.2 多继承

子类可以拥有多个父类,并且具有所有父类的属性和方法。

 

语法格式:

 class 子类名(父类名1,父类名2...)     pass

多继承的使用注意事项:

思考:

如果不同的父类中存在同名的方法,子类对象在调用方法时,会调用哪个父类的方法?说明:开发中,应该尽量避免这种容易产生混淆的情况。如果多个父类之间存在同名的属性后者方法,应该尽量避免使用多继承。

4.对象相关的运算符和内置函数

对象相关的内置函数

Python中的身份运算符用来判断两个对象是否相等;isinstance用来判断对象和类之间的关系;issublcass用啊里判断类与类之间的关系。

4.1 身份运算符

身份运算符用来比较两个对象的内存地址,看这两个对象是否是同一个对象。

class Person(object):
    def __init__(self, name, age):
        self.name = name
        self.age = age


p1 = Person('张三', 18)
p2 = Person('张三', 18)
p3 = p1

print(p1 is p2)  # False
print(p1 is p3)  # True

 isinstance

instance内置函数,用来判断一个实例对象是否是由某一个类(或者它的子类)实例化创建出来的。

class Person(object):
    def __init__(self, name, age):
        self.name = name
        self.age = age


class Student(Person):
    def __init__(self, name, age, score):
        super(Student, self).__init__(name, age)
        self.score = score


class Dog(object):
    def __init__(self, name, color):
        self.name = name
        self.color = color


p = Person('tony', 18)
s = Student('jack', 20, 90)
d = Dog('旺财', '白色')

print(isinstance(p, Person))  # True.对象p是由Person类创建出来的
print(isinstance(s, Person))  # True.对象s是有Person类的子类创建出来的
print(isinstance(d, Person))  # False.对象d和Person类没有关系

 issubclass

issubclass 用来判断两个类之间的继承关系。

class Person(object):
    def __init__(self, name, age):
        self.name = name
        self.age = age


class Student(Person):
    def __init__(self, name, age, score):
        super(Student, self).__init__(name, age)
        self.score = score


class Dog(object):
    def __init__(self, name, color):
        self.name = name
        self.color = color


print(issubclass(Student, Person))  # True
print(issubclass(Dog, Person))  # False

 5.多态的使用

面向对象的三大特性:

  • 封装:这是定义类的准则,根据对象的特点,将行为和属性抽象出来,封装到一个类中。

  • 继承:这是设计类的技巧。父类与子类,主要体现在代码的重用,不需要大量的编写重复代码。

  • 多态:不同的子类调用相同的父类方法,产生不同的执行结果,可以增加代码的外部灵活度。多态是以继承和重写父类方法为前提的,它是一种调用方法的技巧,不会影响到类的内部设计。

场景:

  • 提供三个类:缉毒犬、军犬、人

  • 缉毒犬-->追查毒品,军犬-->攻击假人,人-->让小狗干活

  • 设计类来完成功能。

 代码实现:

class ArmyDog(object):

    def bite_enemy(self):
        print('追击敌人')

class DrugDog(object):

    def track_drug(self):
        print('追查毒品')

class Person(object):

    def work_with_army(self, dog):
        dog.bite_enemy()

    def work_with_drug(self, dog):
        dog.track_drug()

ad = ArmyDog()
dd = DrugDog()

p = Person()
p.work_with_army(ad)
p.work_with_drug(dd)

思考:这段代码设是否有问题?

新增需求:此时,又多了一个犬种,就又需要在Person类里新建一个方法,让这个方法操作新的狗。

class XiaoTianDog(object):

    def eat_moon(self):
        print('哮天犬把月亮吃了')

class Person(object):

    def work_with_xiaotian(self, dog):  # 添加方法
        dog.eat_moon()

 Person 类总是不断的添加新的功能,每次都需要改动Person类的源码,程序的扩展性太差了!

  • 最好是提供一个父类 Dog,具备 work 的功能,其他小狗继承它,这样只要是小狗类,则行为被统一起来了,我们人类完全可以保证,只要是小狗的子类,找它干活肯定不会有问题。

  • 这样人只要一个方法就能逗任意种类的狗玩,哪怕是添加新的狗,人的类都不需要修改。

代码实现:

 class Dog(object):
 
     def work(self):  # 父类提供统一的方法,哪怕是空方法
         pass
 
 class ArmyDog(Dog):   # 继承 Dog
 
     def work(self):  # 子类重写方法,并且处理自己的行为
         print('追击敌人')
 
 class DrugDog(Dog):
 
     def work(self):
         print('追查毒品')
 
 class Person(object):
 
     def work_with_dog(self, dog):
         dog.work()    # 使用小狗可以根据对象的不同而产生不同的运行效果, 保障了代码的稳定性
 
 # 子类对象可以当作父类来使用
 dog = Dog()
 ad = ArmyDog()
 dd = DrugDog()
 
 
 p = Person()
 p.work_with_dog(dog)
 p.work_with_dog(ad)  # 同一个方法,只要是 Dog 的子类就可以传递,提供了代码的灵活性
 p.work_with_dog(dd)  # 并且传递不同对象,最终 work_with_dog 产生了不同的执行效果

 最终效果

    • Person 类中只需要调用 Dog 对象 work() 方法,而不关心具体是 什么狗

    • work() 方法是在 Dog 父类中定义的,子类重写并处理不同方式的实现

    • 在程序执行时,传入不同的 Dog 对象作为实参,就会产生不同的执行效果

总结:

  • 定义:多态是一种使用对象的方式,子类重写父类方法,调用不同子类对象的相同父类方法,可以产生不同的执行结果

  • 好处:调用灵活,有了多态,更容易编写出通用的代码,做出通用的编程,以适应需求的不断变化!

  • 实现步骤:

    • 定义父类,并提供公共方法

    • 定义子类,并重写父类方法

    • 传递子类对象给调用者,可以看到不同子类执行效果不同

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值