zoukankan      html  css  js  c++  java
  • Python面向对象编程

    对象魔法

    1.多态

    多态指的是能够同样地对待不同类型和类的对象,既无需知道对象属于哪个类就可调用其方法。

    2.封装

    对象可能隐藏(封装)其内部状态。在有些语言中,这意味着对象的状态(属性)只能通过其方法来访问。在Python中,所有的属性都是公有的,但直接访问对象的状态时程序员应谨慎行事,因为这可能在不经意间导致状态不一致。

    3.继承

    一个类可以是一个或多个类的子类,在这种情况下,子类将继承超类的所有方法。你可以指定多个超类,通过这样做可组合正交(独立且不相关)的功能。为此,一种常见的做法是使用一个核心超类以及一个或多个混合超类。

    每个对象都属于特定的类,并被称为该类的实例。

    例如,你在窗外看到一只鸟,这只鸟就是“鸟类”的一个实例。鸟类是一个非常通用的(抽象)的类,它有多个子类:你看到的那只鸟可能属于子类“云雀”。你可以将“鸟类”视为由所有鸟组成的集合,而“云雀”是其一个资料集,一个类的对象为另一个类的对象的子集时,前者就是后者的子类,因此“云雀”为“鸟类”的子集,而“鸟类”为“云雀”的超类。

    1.创建自定义类

     1 class Student(object):
     2 
     3     # 构造方法(构造器、构造子 - constructor)
     4     # 调用该方法的时候不是直接使用方法的名字而是使用类的名字
     5     def __init__(self, name='无名氏', age=20):# 属性
     6         # 给对象绑定属性
     7         self._name = name
     8         self._age = age
     9 
    10     # 我们定义一个方法就代表对象可以接收这个消息
    11     # 对象的方法的第一个参数都是统一写成self
    12     # 它代表了接收消息的对象 - 对象.消息(参数)
    13     def study(self, course):# 方法,学生的行为
    14         print('%s正在学习%s' % (self._name, course))

    2.属性,函数和方法

    实际上,方法和函数的区别表现在参数self上。方法(更准确地说是关联的方法)将其第一个参数关联到它所属的实例,因此无需提供这个参数。无疑可以将属性关联到一个普通函数,但这样就没有特殊的self参数了。

    3.隐藏

    默认情况下,可以从外部访问对象的属性。

    有些程序员认为这没问题,但有些程序员认为这违反了封装原则。他们认为应该对外部完全隐藏对象的状态(即不能从外部访问它们)。为何他们的立场如此极端?由每个对象管理自己的属性还不够吗?为何要向外部隐藏属性?毕竟,如果能直接访问CloseObject(对象c所属的类)的属性name,就不需要创建方法setName了。

    关键是其他程序员可能不知道(也不应知道)对象内部发生的情况。为避免这类问题,可以将属性定义为私有。私有属性不能从对象外部访问,而只能通过存取器方法(如set_name和get_name)来访问。

    Python没有为私有属性提供直接的支持,而是要求程序员知道在什么情况下从外部修改属性是安全的。毕竟,你必须在知道如何使用对象之后才能使用它。然而,通过玩点小花招,可以获得类似于私有属性的效果。

    要让方法或属性成为私有的(不能从外部访问),只需要让其名称以两个下划线打头即可。

    虽然以两个下划线打头有点怪异,但这样的方法类似于其他语言中的标准私有方法,然而,幕后的处理手法并不标准:在类定义中,对所有以两个下划线打头的名称都进行转换,即在开头加上一个下划线和类名。

    只要知道这种幕后处理手法,就能从类外访问私有方法,然而不应这样做。

    总之,你无法禁止别人访问对象的私有方法和属性,但这种名称修改方式发出了强烈的信号,让他们不要这样做。

    如果你不希望名称被修改,有想发出不要从外部修改属性或方法的新号,可用一个下划线打头。这虽然只是一种约定,但也有些作用。例如,from module import *不会导入以一个下划线打头的名称。

    4.类的命名空间

    下面的两条语句大致等价:

     def foo(x): return x * x

     foo = lambda x: x * x 

    它们都创建一个返回参数平方的函数,并将这个函数关联到变量foo。可以在全局(模块)作用域内定义名称foo,也可以在函数或方法内定义。定义类时情况亦如此:在class语句中定义的代码都是在一个特殊的命名空间(类的命名空间)内执行的,而类的所有成员都可访问这个命名空间。类定义其实就是要执行的代码段,并非所有的Python程序员都知道这一点,但知道这一点很有帮助。例如,在类定义中,并非只能包含def语句。

    5.指定超类

    子类扩展了超类的定义。要指定超类,可在class语句中的类名后加上超类名,并将其用圆括号括起。

     1 class Filter(object):
     2     
     3     def __init__(self):
     4         self.blocked = []
     5     
     6     def filter(self,sequence):
     7         return [x for x in sequence if x not in self.blocked]
     8     
     9 
    10 class SPAMFilter(Filter): # SPAMFilter是Fliter的子类
    11     
    12     def __init__(self): # 重写超类Filter的方法init
    13         self.blocked = ['SPAM']

    Filter是一个过滤序列的通用类。实际上,它不会过滤掉任何东西。

    Filter类的用途在于可用作其他类(如将'SPAM'从序列中过滤掉的SPAMFilter类)的基类(超类)。

    请注意SPAMFilter类的定义中有两个要点。

      ·以提供新定义的方式重写了Fliter类中方法init的定义。

      ·直接从Filter类继承了方法filter的定义,因此无需重新编写其定义。

    第二点说明了继承很有用的原因:可以创建打量不同的过滤器类,它们都从Filter类派生而来,并且都使用已编写好的方法filter。这就是懒惰的好处。

    6.继承

    要确定一个类是否是另一个类的子类,可使用内置方法issubclass。

    如果有一个类,并想知道它的基类,可访问其特殊属性__bases__。

    同样,要确定对象是否是特定类的实例,可使用isinstance。

    7.接口和内省

    一般而言,你无需过于深入地研究对象,而只依赖于多态来调用所需的方法。然而,如果要确定对象包含哪些方法或属性,有一些函数可供你来完成这种工作。

    8.抽象基类

    使用模块 abc可创建抽象基类。抽象基类用于指定子类必须提供哪些功能,却不实现这些功能。

    关于面向对象设计的一些思考

    将相关的东西放在一起。如果一个函数操作一个全局变量,最好将它们作为一个类的属性和方法。

    不要让对象之间过于亲密。方法应只关系其所属实例的属性,对于其他实力的状态,让它们自己去管理就好了。

    慎用继承,尤其是多重继承。继承有时很有用,但在有些情况下可能带来不必要的复杂性。要正确地使用多重继承很难,要排除其中的bug更难。

    保持简单。让方法短小紧凑。一般而言,应确保大多数方法都能在30秒内读完并理解。对于其余的方法,尽可能将其篇幅控制在一页或一屏内。

  • 相关阅读:
    002. 在HTML页面嵌入循环代码
    001. 为input type=text 时设置默认值
    PHP包名解释
    003. vs2010发布、打包安装程序(转)
    SQL server 2008 Express Edition实现自动备份和自动删除备份
    解决phpMyAdmin中缺少mysqli扩展的错误
    IIS6下PHP环境的资源未找到(404)问题
    解决远程桌面连接过去后是蓝色屏幕问题
    解决tomcat一闪而过问题
    解决访问远程共享时发生 请检查名称的拼写. 否则, 网络可能有问题 故障
  • 原文地址:https://www.cnblogs.com/kurusuyuu/p/8588638.html
Copyright © 2011-2022 走看看