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的面向对象特性的主要内容,如果未能解决你的问题,请参考以下文章