面向对象编程 -- 封装、继承

面向对象编程三要素:封装、继承和多态。本文主要看和封装、继承相关的概念;在python中多态的概念比较模糊,本文不做讨论。

1 封装

封装:将数据和操作组装到一起,对外只暴露一些接口供类外部或子类访问,隐藏数据和操作的实现细节。

在其他面向对象语言,比如java中,属性访问控制一般有三种状态:private、protectd、public。python中没有什么东西是完全不可见的,没有任何机制可以强制性的隐藏数据。所以在python中不存在真正的只能在对象内部访问的属性。
一个被大多数的python程序员遵守的约定:以下划线开头的变量应该被当作非公有属性对待,即它应该被当作是实现细节,其修改应该是不被察觉的。

1.1 名称管理

python中有一种机制对类成员的私有化提供有限的支持,称为名称管理
任何以至少两个下划线开头、至多一个下划线结尾的标识符,如__spam,都会被转换为_classname__spam的形式,其中classname是当前的类名。这种名称管理机制不考虑标识符实际归属哪个命名空间,只要它发生在类的定义中,就会自动生效。

class Chinese:
"""A sample example class"""
nationality = 'China' def __init__(self, name, age, gender):
self.name = name
self.__age = age
self.gender = gender def __str__(self):
return '{}(name={}, age={}, gender={})'.format(self.__class__, self.name, self.__age, self.gender) xm = Chinese('xiaoming', 18, 'male')
print(xm.__dict__) # {'gender': 'male', 'name': 'xiaoming', '_Chinese__age': 18}
print(xm) # <class '__main__.Chinese'>(name=xiaoming, age=18, gender=male)
print(xm.__age) # AttributeError: 'Chinese' object has no attribute '__age'
  • __age在类中被自动转化为_Chinese__age保存在实例的命名空间中;
  • 类内部出现的__age形式的标识符都会被自动转换,所以__str__方法可以访问本例中的__age属性;
  • 在类外部(包括在子类中),无法访问__age属性,因为实例命名空间中并不存在该属性。

继承

继承:对现有类的一种复用机制。如果相对现有的类做一些个性化的修改,可以通过继承实现,而不是直接修改原类。

python的继承语法如下:

class DerivedClassName(BaseClassName):
<statement-1>
.
.
.
<statement-N>

BaseClassName代表被继承的类,称为基类或者父类。
DerivedClassName称为子类。除了添加了父类,子类的定义和实例化和普通的类并没有什么区别。可以通过BaseClassName.__bases__查看其父类。

  1. 子类可以引用父类命名空间中的所有属性。属性的查找顺序:实例-->子类-->父类-->父类的父类...-->object。python3中所有的类都隐性继承自object类。
  2. 子类可以重写父类的属性。一旦属性重写,对于子类或子类之前开始的属性查找,父类对应的属性相当于被屏蔽掉了。
  3. 如果子类要重写初始化方法,最好通过扩展父类的初始化方法实现,即调用父类的初始化方法,并实现自己的个性化扩展。
class Animal:
def __init__(self, name, age):
self.name = name
self.age = age def reply(self):
return self.speak() def speak(self):
return 'Hello world' class Cat(Animal):
def __init__(self, name, age, breed):
super().__init__(name, age)
self.breed = breed def speak(self):
return 'Cat Miaow' print(Cat.__bases__) # (<class '__main__.Animal'>,)
garfield = Cat('Garfield', 10, 'Garfield')
print(garfield.reply()) # Cat Miaow

super().__init__引用Animal之前的祖先类的初始化方法。

多继承

python是支持多继承的,其语法如下:

class DerivedClassName(Base1, Base2, Base3):
<statement-1>
.
.
.
<statement-N>

多继承要解决的主要问题是属性搜索顺序:
1. 将类及其祖先类按照搜索优先级从高到低排列生成一个列表的过程称为类的线性化。
2. MRO: Method Resolution Order, 指用于类线性化的规则,python3用的是C3算法。C3算法可以保证线性化的单调性,单调性是指:如果在类C的线性化中,C1的优先级高于C2,那么C的所有子类的线性化中,C1的优先级高于C2。
3. 可以通过 DerivedClassName.__mro__ 查看类的线性化结果。

想了解C3算法的具体实现,可以参考文章:https://www.python.org/download/releases/2.3/mro/

其他

数据属性和方法属性可能会出现标识符冲突,这会导致非预期的属性重写(对于标识符而言,赋值即定义),这在大型项目中会引起难以定位的bugs。为了避免标识符冲突,使用一些约定最小化冲突概率是明智的。参考方案:

  • 大写方法属性的首字母,给数据属性标识符添加特定的前缀
  • 使用动词标识方法属性,使用名词标识数据属性

参考:

1 file:///Library/Frameworks/Python.framework/Versions/3.5/Resources/English.lproj/Documentation/tutorial/classes.html

 
 
 

python面向对象编程 -- 封装、继承的更多相关文章

  1. python 面向对象及封装继承和多态

    ######装饰器######装饰器的概念 - 装饰器的实现是函数里面嵌套函数;- 装饰器的本质是一个函数, 它可以让其他函数在不需要做任何代码改动的前提下增加额外的功能;- 装饰器需要传递一个函数, ...

  2. Python - 面向对象编程 - 多继承

    继承的详解 https://www.cnblogs.com/poloyy/p/15216652.html 这篇文章讲的都是单继承,Python 中还有多继承 Python 多继承的背景 大部分面向对象 ...

  3. Python 面向对象编程 继承 和多态

    Python 面向对象编程 继承 和多态 一:多继承性 对于java我们熟悉的是一个类只能继承一个父类:但是对于C++ 一个子类可以有多个父亲,同样对于 Python一个类也可以有多个父亲 格式: c ...

  4. Python面向对象编程——继承与派生

    Python面向对象编程--继承与派生 一.初始继承 1.什么是继承 继承指的是类与类之间的关系,是一种什么"是"什么的关系,继承的功能之一就是用来解决代码重用问题. 继承是一种创 ...

  5. Python面向对象中的继承、多态和封装

    Python面向对象中的继承.多态和封装 一.面向对象的三大特性 封装:把很多数据封装到⼀个对象中,把固定功能的代码封装到⼀个代码块, 函数,对象, 打包成模块. 这都属于封装思想. 继承:⼦类可以⾃ ...

  6. python面向对象编程进阶

    python面向对象编程进阶 一.isinstance(obj,cls)和issubclass(sub,super) isinstance(obj,cls)检查是否obj是否是类 cls 的对象 1 ...

  7. Python面向对象编程(下)

    本文主要通过几个实例介绍Python面向对象编程中的封装.继承.多态三大特性. 封装性 我们还是继续来看下上文中的例子,使用Student类创建一个对象,并修改对象的属性.代码如下: #-*- cod ...

  8. python面向对象编程学习

    python面向对象编程 基本概念理解 面向对象编程--Object Oriented Programming,简称OOP,是一种程序设计思想.OOP把对象作为程序的基本单元,一个对象包含了数据和操作 ...

  9. Python面向对象04 /封装、多态、鸭子类型、类的约束、super

    Python面向对象04 /封装.多态.鸭子类型.类的约束.super 目录 Python面向对象04 /封装.多态.鸭子类型.类的约束.super 1. 封装 2. 多态 3. 鸭子类型 4. 类的 ...

随机推荐

  1. C# Note25: .Net Core

    .NET Core全面扫盲贴 .NET Core与.NET Framework.Mono之间的关系 https://www.postgresql.org/

  2. centos7之vm11添加网卡

    需求 根据实际需求原来有一块网卡,现在需要新加一块网卡做集群. 1.在虚拟机添加一块网卡,开机后ip a查看是不是新加了一块网卡,下图是为了讲解,其实已经是做完的状态. 2.上满我们看到新加了一块网卡 ...

  3. js 首次进入弹窗

    今天有个需求,首次进入需要弹窗,然后就在网上找了下,虽然看了很多但是说的都不是我想要的,最后终于到了一个合适的. function get_cookie(Name) { var search = Na ...

  4. Hibernate 连接不同数据库的方言

    RDBMS 方言 DB2 org.hibernate.dialect.DB2Dialect DB2 AS/400 org.hibernate.dialect.DB2400Dialect DB2 OS3 ...

  5. Simple Use IEnumerable<T>

    Private static IEnumerable<T> FunDemo(T para) { while(...) { .... yield return Obj; } } static ...

  6. 页面传递的都是string ; 每个标签要有name的原因是为了取值 因为传递给后台是键值对的形式

    页面传递的都是string ; 每个标签要有name的原因是为了取值  因为传递给后台是键值对的形式

  7. [51Nod 1584] 加权约数和

    Description 在整理以前的试题时,他发现了这样一道题目:"求 \(\sum\sigma(i)\),其中 \(1≤i≤N\),\(σ(i)\) 表示 \(i\) 的约数之和.&quo ...

  8. Git——入门操作加创建账号【三】

    创建账号 GitHub https://github.com/ 码云 https://gitee.com/ 无论是github还是码云,创建账号都是非常简单快捷的,大家可以自行选择创建下,不过建议最好 ...

  9. Codeforces Round #514 (Div. 2) C. Sequence Transformation 思维构造

    题意 给出一个1-n的集合   gcd 集合里面的所有数  得到的 一个 数   然后自己选择删去一个数   要使得到的数 构成的数列 的字典序最大 思路: gcd所有数 那gcd得到的数肯定要小于数 ...

  10. 【BZOJ3999】【TJOI2015】旅游 树剖

    题目大意 给你一棵树,有\(n\)个点.有\(q\)个操作,每次要你从\(x\)到\(y\)的路径上选两个点,使得距离\(x\)比较远的点的点权\(-\)距离\(x\)比较近的点的点权最大,然后把这条 ...