Python进阶(二)Python中的类继承、封装、多态使用方法

  python中可以在类的外面给对象增加属性,比如tom.name="Tom"就可以给tom类增加一个name属性,但是这种方法并不推荐使用,最好都封装在类的内部。

  在类的内部封装可以通过self实现,self的地址会跟实例化对象的地址一样。

  在python3object是所有类的基类。

封装

  所谓封装,就是将属性方法抽象地封装到一个类中。

继承和重写

  面向对象(OOP)三要素(封装 继承 多态)之一,继承Inheritance。继承可以让子类从父类获取特征(属性和方法),在面向对象的世界中,从父类继承,就可以直接拥有父类的属性和方法。

  它可以使用现有类的所有功能,并在无需重新编写原来的类的情况下对这些功能进行扩展,这样可以减少代码,多复用,子类可以定义自己的属性和方法。

  在使用面向对象开发前,应该首先分析需求,确定一下,程序中需要包含哪些类。

继承基本思想

  在使用类创建一个对象的时候就会执行init方法,如果子类实现了init方法,会走子类中的init方法,如果子类没有实现init方法,会找继承父类init方法。

class Envrioment:
    def __init__(self,env):
        self.env = env
    def get_observation(self):
        print("Get Observation")
class Big_Env(Envrioment):
        pass
a = Big_Env(1)
a.get_observation()
print(a.env)
>>>Get Observation
	1

  继承是具有传递性的,也就是子类也会有爷爷类的方法。

super()扩展父类,重写

  如果父类原本封装的方法实现是子类方法的一部分,就可以使用扩展的方式。在需要的位置使用super().父类方法来调用父类方法的执行,代码其它的位置针对子类的需求编写子类特有的代码实现。

  在pythonsuper()是一个特殊的类,super()就是使用super类创建出来的对象,最常使用的场景就是在重写父类方法时,调用在父类中封装的方法实现。

  子类同样是不能访问父类的私有属性和私有方法的

  可依据魔法属性mro(method resolution order)顺序查看。

class little_animal():
    def __init__(self, sleep):
        self.sleep = sleep
class animal(little_animal):
    def __init__(self, sleep, eat, drink):
        super().__init__(sleep)
        self.eat = eat
        self.drink = drink
    def run(self):
        print("rrrrr")
class dog(animal):
    def __init__(self,bark,sleep,eat,drink):
        super().__init__(sleep,eat,drink)
        self.bark = bark
    def run(self):
        super().run()
        print("ttttt")
a = dog(1,2,3,4)
print(a.bark, a.sleep, a.eat, a.drink)
a.run()
print(dog.__mro__)

  输出:

1 2 3 4
rrrrr
ttttt
(<class '__main__.dog'>, <class '__main__.animal'>, <class '__main__.little_animal'>, <class 'object'>)

  在继承里面一定要注意的是继承不是复制,他只是指向父类,此时如果改变父类的值,子类相应的值也会发生改变。只有重写之后,也就是在子类中对其进行重新赋值之后,改变父类的值不会改变子类的值。

多继承

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

class A:
    def test(self):
        print("Test")
class B:
    def demo(self):
        print("demo")
class C(A,B):
    pass
C_test = C()
C_test.test()
C_test.demo()
>>>Test
   demo

  在多继承中要注意的问题就是,应该尽量避免产生不同父类存在同名的方法

  为了保证编写的代码能够同时在Python2Python3中同时运行,今后定义类时,如果没有父类,建议统一继承自object

多态

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

class Dog(object):
    def __init__(self, name):
        self.name = name
    def paly(self):
        print("Dog {} Play With Game".format(self.name))
class Fly_Dog(object):
    def __init__(self, name):
        self.name = name
    def play(self):
        print("Fly_Dog {} Play With Game".format(self.name))
class Person(object):
    def __init__(self, name):
        self.name = name
    def play(self, dog):
        print("Person {} Play With Dog {}".format(self.name, dog.name))
P = Person("Bob")
P.play(Dog("Wangcai"))
P.play(Fly_Dog("xiaotian"))
>>> Person Bob Play With Dog Wangcai
	Person Bob Play With Dog xiaotian

类属性

  使用面向对象开发,第一步是设计类。使用类名()创建对象,创建对象的动作有两步:

  1. 在内存中为对象分配空间。‘
  2. 调用初始化方法__init__为对象初始化

  对象创建后,内存中就有一个对象的实实在在的内存(实例)。上述是创建对象的完整过程。

  1. 若创建了多个对象,每个对象有自己独立的内存空间保存各自不同的属性
  2. 多个对象的方法,在内存中只有一份需要把对象的引用传递到方法内部。

  在Python中类是一个特殊的对象,且一切皆对象。在程序运行时,类对象同样会被加载到内存

  • class AAA:定义的类属于类对象
  • obj1 = AAA(): 属于实例对象

  在程序运行时,类对象在内存中只有一份,使用一个类可以创建很多个对象实例。除了封装实例的属性方法外,类对象还可以拥有自己的属性方法

class Tool(object):
    count = 0
    def __init__(self):
        Tool.count += 1
a = Tool()
b = Tool()
print(Tool.count)
print(b.count)
>>> 2
	2

  类属性用来记录与这个类相关的特征,不会记录具体对象的特征。如果通过实例化对象来访问,其会先在实例化对象的方法中找该属性,没有的话就会在类里面去找。因此访问类属性有两种方式:

  1. 类名.类属性
  2. 对象.类属性(不推荐)

  如果这里程序最后再设置b.count=10,那么此时python解释器会给实例化的对象b创建一个属性,而不是向上去查找类属性,因此不会改变Tool.count的值。也就是说使用对象.类属性=值赋值语句,只会给对象添加一个属性,而不会影响到类属性的值

类方法

  从上文类属性的文章中我们可以知道,使用赋值语句在class关键字下方可以定义类属性。

  • 类方法就是针对类对象定义的方法。在类方法内部可以直接访问类属性,或者调用其他的类方法。

  语法如下:

@classmethod
def 类方法名(cls):
	pass

  类方法需要用修饰器@classmethod来标识,告诉解释器这是一个类方法

  第一个参数cls。由哪一个类调用的方法,方法内的cls就是哪一个类的引用,这个参数和实例方法的第一个参数是self类似,使用其他名称也可以,不过习惯使用cls

  通过类名.调用类方法调用方法时,不需要传递cls参数,在方法内部可以通过cls.访问类的属性,也可以通过cls.调用其他类方法。

class Tool(object):
    count = 0
    @classmethod
    def num_of_count(cls):
        print("The num of tool is {}".format(cls.count))
    def __init__(self):
        Tool.count += 1
a = Tool()
a.num_of_count()
>>> The num of tool is 1

静态方法

  开始之前先总结一下类方法实例方法:1. 如果需要访问实例属性,那将这个方法封装成实例方法。2. 如果某一个方法不需要访问实例属性,但是需要访问类属性,那么这个时候可以考虑将这个方法封装成类方法。

  如果某一个方法既不需要访问其类属性,也不需要访问其实例属性(里面没有用到self.这种操作访问东西,比如单纯的一个print),那么可以将这个方法封装成静态方法

  语法如下:

@staticmethod
def 静态方法(): # 不需要指定第一个参数,因为它什么都不需要访问
	pass

  如:

class Dog(object):
    @staticmethod
    def run():
        print("Run ...")
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章