python 继承与多重继承
当然,如果不支持python继承,语言特性就不值得称为“类”。派生类定义的语法如下所示:
<statement-1> . . . <statement-N>
名称 BaseClassName 必须定义于包含派生类定义的作用域中。 也允许用其他任意表达式代替基类名称所在的位置。 这有时也可能会用得上,例如,当基类定义在另一个模块中的时候:
class DerivedClassName(modname.BaseClassName):
派生类定义的执行过程与基类相同。 当构造类对象时,基类会被记住。 此信息将被用来解析属性引用:如果请求的属性在类中找不到,搜索将转往基类中进行查找。 如果基类本身也派生自其他某个类,则此规则将被递归地应用。
派生类的实例化没有任何特殊之处: DerivedClassName() 会创建该类的一个新实例。 方法引用将按以下方式解析:搜索相应的类属性,如有必要将按基类继承链逐步向下查找,如果产生了一个函数对象则方法引用就生效。
派生类可能会重载其基类的方法。 因为方法在调用同一对象的其他方法时没有特殊权限,调用同一基类中定义的另一方法的基类方法最终可能会调用覆盖它的派生类的方法。 (对 C++ 程序员的提示:Python 中所有的方法实际上都是 virtual 方法。)
在派生类中的重载方法实际上可能想要扩展而非简单地替换同名的基类方法。 有一种方式可以简单地直接调用基类方法:即调用 BaseClassName.methodname(self, arguments)。 有时这对客户端来说也是有用的。 (请注意仅当此基类可在全局作用域中以 BaseClassName 的名称被访问时方可使用此方式。)
Python有两个内置函数可被用于继承机制:
使用 isinstance() 来检查一个实例的类型: isinstance(obj, int) 仅会在 obj.__class__ 为 int 或某个派生自 int 的类时为 True。
使用 issubclass() 来检查类的继承关系: issubclass(bool, int) 为 True,因为 bool 是 int 的子类。 但是,issubclass(float, int) 为 False,因为 float 不是 int 的子类。
多重继承
class DerivedClassName(Base1, Base2, Base3): <statement-1> . . . <statement-N>
对于多数应用来说,在最简单的情况下,你可以认为搜索从父类所继承属性的操作是深度优先、从左至右的,当层次结构中存在重叠时不会在同一个类中搜索两次。 因此,如果某一属性在 DerivedClassName 中未找到,则会到 Base1 中搜索它,然后(递归地)到 Base1 的基类中搜索,如果在那里未找到,再到 Base2 中搜索,依此类推。
真实情况比这个更复杂一些;方法解析顺序会动态改变以支持对 super() 的协同调用。 这种方式在某些其他多重继承型语言中被称为后续方法调用,它比单继承型语言中的 super 调用更强大。
动态改变顺序是有必要的,因为所有多重继承的情况都会显示出一个或更多的菱形关联(即至少有一个父类可通过多条路径被最底层类所访问)。 例如,所有类都是继承自 object,因此任何多重继承的情况都提供了一条以上的路径可以通向 object。 为了确保基类不会被访问一次以上,动态算法会用一种特殊方式将搜索顺序线性化, 保留每个类所指定的从左至右的顺序,只调用每个父类一次,并且保持单调(即一个类可以被子类化而不影响其父类的优先顺序)。 总而言之,这些特性使得设计具有多重继承的可靠且可扩展的类成为可能。
私有变量
那种仅限从一个对象内部访问的“私有”实例变量在 Python 中并不存在。 但是,大多数 Python 代码都遵循这样一个约定:带有一个下划线的名称 (例如 _spam) 应该被当作是 API 的非仅供部分 (无论它是函数、方法或是数据成员)。 这应当被视为一个实现细节,可能不经通知即加以改变。
由于存在对于类私有成员的有效使用场景(例如避免名称与子类所定义的名称相冲突),因此存在对此种机制的有限支持,称为 名称改写。 任何形式为 __spam 的标识符(至少带有两个前缀下划线,至多一个后缀下划线)的文本将被替换为 _classname__spam,其中 classname 为去除了前缀下划线的当前类名称。 这种改写不考虑标识符的句法位置,只要它出现在类定义内部就会进行。
名称改写有助于让子类重载方法而不破坏类内方法调用。例如:
def __init__(self, iterable): self.items_list = [] self.__update(iterable) def update(self, iterable): for item in iterable: self.items_list.append(item) __update = update # private copy of original update() method class MappingSubclass(Mapping): def update(self, keys, values): # provides new signature for update() # but does not break __init__() for item in zip(keys, values): self.items_list.append(item)
上面的示例即使在 MappingSubclass 引入了一个 __update 标识符的情况下也不会出错,因为它会在 Mapping 类中被替换为 _Mapping__update 而在 MappingSubclass 类中被替换为 _MappingSubclass__update。
请注意,改写规则的设计主要是为了避免意外冲突;访问或修改被视为私有的变量仍然是可能的。这在特殊情况下甚至会很有用,例如在调试器中。
请注意传递给 exec() 或 eval() 的代码不会将发起调用类的类名视作当前类;这类似于 global 语句的效果,因此这种效果仅限于同时经过字节码编译的代码。 同样的限制也适用于 getattr(), setattr() 和 delattr(),以及对于 dict 的直接引用。
杂项说明
有时会需要使用类似于 Pascal 的“record”或 C 的“struct”这样的数据类型,将一些命名数据项捆绑在一起。 这种情况适合定义一个空类:
pass john = Employee() # Create an empty employee record # Fill the fields of the record john.name = 'John Doe' john.dept = 'computer lab' john.salary = 1000
一段需要特定抽象数据类型的 Python 代码往往可以被传入一个模拟了该数据类型的方法的类作为替代。 例如,如果你有一个基于文件对象来格式化某些数据的函数,你可以定义一个带有 read() 和 readline() 方法从字符串缓存获取数据的类,并将其作为参数传入。
实例方法对象也具有属性: m.__self__ 就是带有 m() 方法的实例对象,而 m.__func__ 则是该方法所对应的函数对象。

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
python方法对象 类和实例变量
通常,方法在绑定后立即被调用: 在 MyClass 示例中,这将返回字符串 'hello world'。 但是,立即调用一个方法并不是必须的: x.f 是一个方法对象,它可以被保存起来以后再调用。 例如: while True: print(xf()) 将继续打印 hello world,直到结束。 当一个方法被调用时到底发生了什么? 你可能已经注意到上面调用 x.f() 时并没有带参数,虽然 f() 的函数定义指定了一个参数。 这个参数发生了什么事? 当不带参数地调用一个需要参数的函数时 Python肯定会引发异常 --- 即使参数实际未被使用... 实际上,你可能已经猜到了答案:方法的特殊之处就在于实例对象会作为函数的第一个参数被传入。 在我们的示例中,调用 x.f() 其实就相当于 MyClass.f(x)。 总之,调用一个具有 n 个参数的方法就相当于调用再多一个参数的对应函数,这个参数值为方法所属实例对象,位置在其他参数之前。 如果你仍然无法理解方法的运作原理,那么查看实现细节可能会澄清问题。 当一个实例的非数据属性被引用时,将搜索实例所属的类。 如果名称表示一个属于函数对象...
- 下一篇
审核中Java岗位三年经验,最常见JVM十六道面试题!(附答案)
一.jvm内存布局 程序计数器:当前线程正在执行的字节码的行号指示器,线程私有,唯一一个没有规定任何内存溢出错误的情况的区域。 Java虚拟机栈:线程私有,描述Java方法执行的内存模型,每个方法运行时都会创建一个栈帧,存放局部变量表、操作数栈、动态链接、方法出口等信息,每个方法的运行到结束对应一个栈帧的入栈和出栈。会有StackOverFlowError异常(申请的栈深度大于虚拟机所允许深度)和OutOfMemoryError异常(线程无法申请到足够内存)。 本地方法栈:功能与Java虚拟机栈相同,不过是为Native方法服务。 java堆:线程共享,存放实例对象和数组对象,申请空间不足抛出OutOfMemoryError异常。 方法区:线程共享,存储已被虚拟机加载的类的类信息、常量、静态变量、编译后的代码;运行时常量池存放class文件中描述的符号引用和直接引用,具有动态性。方法空间不足时抛出OutOfMemoryError异常。 直接内存:JVM规范之外的,NIO类引入了一种基于通道和缓冲区的I/O方式,可使用Native函数库直接分配内存,通过一个存储在Java堆中的Direc...
相关文章
文章评论
共有0条评论来说两句吧...