Python的面向对象特性

Posted lynnblog

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Python的面向对象特性相关的知识,希望对你有一定的参考价值。

面向对象的特性

一、封装

  Python不依赖语言的特性去封装数据,而是通过遵循一定的数据属性或函数属性的命名来达到封装的效果。任何以单下划线开头的名字都应该是内部的、私有的。封装的意义在内部业务逻辑的数据隐藏。Python真正意义上的封装是用类的内外访问来区分的。并且它Java的private属性有很大的区别,Python并没有强制性的拒绝外部类对私有属性的访问。换句话说,以单下划线或双下划线开头的私有属性仅仅只是一种约定。需要注意的是,当我们使用另一个模块的私有属性在导入时,不能使用“*”号,只能使用私有属性的名称。Python有意义上的封装层次。

1. 第一层封装

  使用以单下划线开头的私有属性。对象在调用时可直接使用“对象名 . 私有属性名”。

2. 第二层封装

  使用以双下划线开头的私有属性。对象在调用时不能直接使用“对象名 . 私有属性名”。需要在双下划线开头的私有属性前加上“_类名”,如:“对象名 .  _类名 . 私有属性名”

3. 四三层封装

  使用自定义的函数来提供接口。明确区分内外,实现内部业务逻辑的封装,并像java的setter和getter方法一样给出外部程序的使用自定义的接口函数,让该接口函数返回一个值私有的性。但是在程序的设计中一定要清醒的认识到,程序在设计之初不应该被私有属性所捆版,否则在今后的修改或维护中就会非常的痛苦。只有真正需要封装的数据才需要封装。比如员工的工资等重要的数据。

        class Person:

            _privateproperty = "以单下划线开头的私有属性"

            __property = "以双下划线开头的私有属性"

            def __init__(self, name, gender, age):
                self.name = name
                self.gender = gender
                self.age = age

            def return_property(self):
                return self.__property

            def showinfo(self):
                print(self.name, self.gender, self.age)
        
 
        person = Person("Handy","",18)

        #单下划线开头的私有属性
        print(person._privateproperty)

        #双下划线开头的私有属性,注意调用方式
        print(person._Person__property)

 

 

二、继承

  Python的继承与C++的多继承非常相似,它的继承关系会被解释器解释为一个MRO列表,该MRO列表就是一个简单的所有基类的线性顺序列表。MRO列表的构造是通过一个C3线性化算法来实现的。Python和java一样,所有类的最终基类是Object。继承从某种角度上来讲是有害的,继承将类与类之间耦合到一块了。这大大的破坏了系统的封闭原则。继承真正有意义的是接口式的继承。Python提供的接口式的继承。

Python 的继承顺序可由类使用__mro__查看。解释器查看顺序遵循以下三条规则:

1. 子类会先于父类被检查

2. 多个父类会根据他们在列表中的顺序进行检查

3. 如果对下一个类存在两个合法的选择,选择第一个父类

    class Person:
        """
        描述人的类
        """

        def __init__(self, name, gender, age):
            self.name = name
            self.gender = gender
            self.age = age

        def printinfo(self):
            print("人类")


    class Student(Person):
        """
        学生的类
        """
        def __init__(self, name, gender, age, school):
            """
            使用super调用父类的构造函数时,参数中不能出现self,因为
            super已经默认给出了self,如果此时加上self会报错。而报错
            的原因是多了一个参数。使用super()调用父类的函数使程序更
            加灵活。当然也可以使用以下耦合的调用模式。
            Person.__init__(self, name, gender, age)

            """
            super().__init__(name, gender, age)
            self.school = school

        def ptintinfo(self):
            print(self.name, self.gender, self.age, self.school)


    s = Student("Macky", "", 18, "麻省理工")
    s.ptintinfo()

 

 

三、多态

  Python的多态和java的多态一样。多态的概念指出了对象如何通过他们共有的属性及函数来访问,不需要考虑他们之间的具体的类。

    class Person:

        def __init__(self, name, age):
            self.name = name
            self.age = age

        def behavior(self):
            if self.age >= 0 and self.age <= 18:
                print("%s是未成年人"%self.name)
            else:
                print("%s是成年人"%self.name)

    class Adult(Person):
        pass

    class Pupil(Person):
       pass

    #实现多态的简单例子
    def func(obj):
        obj.behavior()

    #初始化Adult和Pupil
    adult = Adult("小明",3)
    pupil = Pupil("小华",20)

    #调用func函数
    func(adult)
    func(pupil)

 

 

四、反射

  反射的概念是由Smith在1982年首次提出的,主要是指程序可以访问、检测和修改它本身状态或行为的一种能力(自省)。这一概念的提出很快引发了计算机科学领域关于应用反射性的研究。它首先被程序语言的设计领域所采用,并在Lisp和面向对象方面取得了成绩。反射展示了某对象在运行期间是如何取得自己的状态的。如果传一个对象给你,你可以查出他的所有能力,这是一项强大的特性。如果Python不支持某种形式的反射功能,dir和type内置函数,将很难工作。还有那些特殊的属性,像__dict__、__name__及__doc__。那反射究竟有什么好处呢?它可以事先定义好接口,接口只有在被完成后才会真正执行,这实现了即插即用,这其实是一种“后期绑定”,你可以事先把主要的逻辑写好(只定义接口),然后后期再去实现接口的功能。这与Java的反射机制是一样的,只不过在变现形式上不同。在开发中这项技术是必不可少的。

反射技术的实现基于以下四个函数:

   hasattr(object, name)                                  

  判断object中有没有一个name字符串对应的方法或属性。

   getattr(object, name, default=None)         

  获取对象的属性值或这函数的地址。当获取对象的属性值不存在时返回False,而函数不存在时报错。如果要想函数不存在时不报错能并且能通知我们函数不存在,恶可以使用default参数。该函数的功能与对象调用属性相同。如:getattr(x, ‘y‘)   <==>   x.y

   setattr(x, y, v)                                               

  为对象x的属性y设置或修改一个值,当属性不存在时,会将setattr设置的不存在的属性向对象的字典中追加。如:setattr(x, y, v)   <==>   x.y =v

   delattr(x, y)                                                   

  删除对象的属性。如:delattr(x, y)   <==>   del x.y

    class Person:

        def __init__(self, name, gender, age):
            self.name = name
            self.gender = gender
            self.age = age

        def eating(self):
            print("在吃饭")

        def sleep(self):
            print("在睡觉")


    person = Person("Handy","",18)

    #使用hasattr判断对象中是否存在属性name
    print(hasattr(person, "name"))  #输出:True

    #使用getattr获取对象的属性值
    print(getattr(person, "name"))  #输出:Handy

    #使用getattr获取对象的函数地址
    print(getattr(person, "eating"))#输出:eatting()的地址

    #运行函数
    getattr(person, "eating")()     #输出:在吃饭

    #使用getattr的default参数
    print(getattr(person, "eatingfood", "函数不存在"))    #输出:函数不存在

    #使用setattr修改一个值
    setattr(person, "name", "Lily")
    print(person.__dict__)

    #向对象的字典追加一个不存在的值
    setattr(person, "ID", "001")
    print(person.__dict__)

    #增加函数1
    setattr(person, "func", lambda x : x+1)
    print(person.func)
    print(person.func(10))

    #增加函数2
    setattr(person, "func", lambda self : self.name+"是可以这样做的")
    print(person.func)
    print(person.func(person))

    #使用delattr删除对象的属性
    delattr(person, "ID")
    print(person.__dict__)

 

以上是关于Python的面向对象特性的主要内容,如果未能解决你的问题,请参考以下文章

Python面向对象之:三大特性:继承,封装,多态。

19.Python面向对象之:三大特性:继承,封装,多态。

面向对象三大特性

继承 多态 封装 Python面向对象的三大特性

Python基础-第六天-面向对象编程

Python之面向对象继承详解以及面向对象三大特性