面向对象基础部分及模块
Posted Jason_wang_2016
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了面向对象基础部分及模块相关的知识,希望对你有一定的参考价值。
一、面向对象基础
面向对象名词解释:
-
类(Class): 用来描述具有相同的属性和方法的对象的集合。它定义了该集合中每个对象所共有的属性和方法。对象是类的实例。
-
类变量:类变量在整个实例化的对象中是公用的。类变量定义在类中且在函数体之外。类变量通常不作为实例变量使用。
-
数据成员:类变量或者实例变量用于处理类及其实例对象的相关的数据。
-
方法重写:如果从父类继承的方法不能满足子类的需求,可以对其进行改写,这个过程叫方法的覆盖(override),也称为方法的重写。
-
实例变量:定义在方法中的变量,只作用于当前实例的类。
-
继承:即一个派生类(derived class)继承基类(base class)的字段和方法。继承也允许把一个派生类的对象作为一个基类对象对待。例如,有这样一个设计:一个Dog类型的对象派生自Animal类,这是模拟"是一个(is-a)"关系(例图,Dog是一个Animal)。
-
实例化:创建一个类的实例,类的具体对象。
-
方法:类中定义的函数。(方法属于类,不属于实例)
-
对象:通过类定义的数据结构实例。对象包括两个数据成员(类变量和实例变量)和方法。
二、面向对象的特性:
封装
封装最好理解了。封装是面向对象的特征之一,是对象和类概念的主要特性。
封装,也就是把客观事物封装成抽象的类,并且类可以把自己的数据和方法只让可信的类或者对象操作,对不可信的进行信息隐藏。
第一步:将内容封装到某处
class1 SQLHELPer: def __init__(self,a1,a2,a3):#成为构造方法,根据类创建的对象自动执行 self.hhost = a1 self.uusername = a2 self.pwd = a3 def fetch(self): print(self.hhost) print(self.uusername) print(self.pwd) def create(self,sql): pass def remove(self,nid): pass def modify(self,name): pass #根据类SQLHELPer创建对象 #自动执行SQLHELPer 的__init__方法 obj = SQLHELPer() obj.hhost = "c1.salt.com" obj.uusername = "Jason" obj.pwd = "123"
obj1 = SQLHELPer(\'abc.com\',\'jack\',\'234\')
self 是一个形式参数,当执行obj = SQLHELPer()时,self 等于 obj
当执行obj1 = SQLHELPer(\'abc.com\',\'jack\',\'234\')时,self 等于 obj1
所以,内容其实被封装到了对象 obj 和 obj1 中,每个对象中都有 a1,a2和 a3 属性,在内存里类似于下图来保存。
第二步:从某处调用被封装的内容
调用被封装的内容时,有两种情况:
- 通过对象直接调用
- 通过self间接调用
1、通过对象直接调用被封装的内容
上图展示了对象 obj1 和 obj2 在内存中保存的方式,根据保存格式可以如此调用被封装的内容:对象.属性名
class Foo: def __init__(self, name, age): self.name = name self.age = age obj1 = Foo(\'wupeiqi\', 18) print obj1.name # 直接调用obj1对象的name属性 print obj1.age # 直接调用obj1对象的age属性 obj2 = Foo(\'alex\', 73) print obj2.name # 直接调用obj2对象的name属性 print obj2.age # 直接调用obj2对象的age属性
2、通过self间接调用被封装的内容
执行类中的方法时,需要通过self间接调用被封装的内容
class Foo: def __init__(self, name, age): self.name = name self.age = age def detail(self): print self.name print self.age obj1 = Foo(\'wupeiqi\', 18) obj1.detail() # Python默认会将obj1传给self参数,即:obj1.detail(obj1),所以,此时方法内部的 self = obj1,即:self.name 是 wupeiqi ;self.age 是 18 obj2 = Foo(\'alex\', 73) obj2.detail() # Python默认会将obj2传给self参数,即:obj1.detail(obj2),所以,此时方法内部的 self = obj2,即:self.name 是 alex ; self.age 是 78
综上所述,对于面向对象的封装来说,其实就是使用构造方法将内容封装到 对象 中,然后通过对象直接或者self间接获取被封装的内容。
继承
面向对象编程 (OOP) 语言的一个主要功能就是“继承”。继承是指这样一种能力:它可以使用现有类的所有功能,并在无需重新编写原来的类的情况下对这些功能进行扩展。
通过继承创建的新类称为“子类”或“派生类”。
被继承的类称为“基类”、“父类”或“超类”。
继承的过程,就是从一般到特殊的过程。
要实现继承,可以通过“继承”(Inheritance)和“组合”(Composition)来实现。
在某些 OOP 语言中,一个子类可以继承多个基类。但是一般情况下,一个子类只能有一个基类,要实现多重继承,可以通过多级继承来实现。
继承概念的实现方式有三类:实现继承、接口继承和可视继承。
在考虑使用继承时,有一点需要注意,那就是两个类之间的关系应该是“属于”关系。例如,Employee 是一个人,Manager 也是一个人,因此这两个类都可以继承 Person 类。但是 Leg 类却不能继承 Person 类,因为腿并不是一个人。
OO开发范式大致为:划分对象→抽象类→将类组织成为层次化结构(继承和合成) →用类与实例进行设计和实现几个阶段。
class Role(object): def __init__(self, name): self.name = name def get_name(self): return self.name class Teacher(Role): def __init__(self, name, course): \'\'\' 如果父类已经有一个方法,子类也有一个同名的方法,就会覆盖掉父类的方法,专业术语叫做重写 \'\'\' super(Teacher, self).__init__(name) # 通过super这种语法可以调用父类的方法和变量,这里调用父类的构造方法,初始化name self.course = course # 这个变量是父类所没有的 def say(self): # 定义父类的 print(\'My name is %s, i am a English teather\' %self.name) if __name__ == \'__main__\': lisi = Teacher(\'lisi\', \'English\') # 定义Teacher的实例 print(lisi.name) # name这个变量是子类通过继承的方式获取的 print(lisi.get_name()) # 继承自父类的方法 lisi.say() # 子类特有的方法
所以,对于面向对象的继承来说,其实就是将多个类共有的方法提取到父类中,子类仅需继承父类而不必一一实现每个方法。
注:除了子类和父类的称谓,你可能看到过 派生类 和 基类 ,他们与子类和父类只是叫法不同而已。
那么问题又来了,多继承呢?
- 是否可以继承多个类
- 如果继承的多个类每个类中都定了相同的函数,那么那一个会被使用呢?
1、Python的类可以继承多个类,Java和C#中则只能继承一个类
2、Python的类如果继承了多个类,那么其寻找方法的方式有两种,分别是:深度优先和广度优先
深度优先
class D:
def bar(self):
print(\'D.bar\')
class C():
def bar(self):
print(\'C.bar\')
class B(D):
def bar2(self):
print(\'B.bar\')
class A(B,C):
def bar1(self):
print(\'A.bar\')
a = A()
a.bar()##D.bar
# 执行bar方法时 # 首先去A类中查找,如果A类中没有,则继续去B类中找,如果B类中么有,则继续去D类中找,如果D类中么有,则继续去C类中找,如果还是未找到,则报错 # 所以,查找顺序:A --> B --> D --> C 如下图 # 在上述查找bar方法的过程中,一旦找到,则寻找过程立即中断,便不会再继续找了 a.bar()
广度优先
class D(object): def bar(self): print(\'D.bar\') class C(D): def bar(self): print(\'C.bar\') class B(D): def bar2(self): print(\'B.bar\') class A(B,C): def bar1(self): print(\'A.bar\') a = A()
# 执行bar方法时 # 首先去A类中查找,如果A类中没有,则继续去B类中找,如果B类中么有,则继续去C类中找,如果C类中么有,则继续去D类中找,如果还是未找到,则报错 # 所以,查找顺序:A --> B --> C --> D 如下图 # 在上述查找bar方法的过程中,一旦找到,则寻找过程立即中断,便不会再继续找了
a.bar()##C.bar
经典类和新式类,从字面上可以看出一个老一个新,新的必然包含了跟多的功能,也是之后推荐的写法,从写法上区分的话,如果 当前类或者父类继承了object类,那么该类便是新式类,否则便是经典类。
经典类:首先去A类中查找,如果A类中没有,则继续去B类中找,如果B类中么有,则继续去D类中找,如果D类中么有,则继续去C类中找,如果还是未找到,则报错
新式类:首先去A类中查找,如果A类中没有,则继续去B类中找,如果B类中么有,则继续去C类中找,如果C类中么有,则继续去D类中找,如果还是未找到,则报错
注意:在上述查找过程中,一旦找到,则寻找过程立即中断,便不会再继续找了
** Python3中默认均为广度优先
多态
三 类的定义(详细说明)
class Foo(object): # Foo为类名,括号内的表示是这个类继承自哪个类,这里的object是所有类的基类,一个类可以继承自多个类 \'\'\' 类的说明文档,Python会自动将这里面内容赋值给类的变量__doc__ \'\'\' class_var1 = \'var1\' # 类的变量,它属于类本身,而不是类的对象,可以通过类名.变量名的方式进行调用,也可以对象.变量名调用,前提是,没有同名的实例变量 def __init__(self, arg, arg2): \'\'\' 初始化方法,有点类似于java语言的构造方法,在创建类的对象的时候自动调用 :param var2: 参数,初始化方法也可以 :return: \'\'\' self.var2 = arg # 对象的变量,属于对象不属于类,只能通过对象.变量名的方式调用 self.__var3 = arg # 对象的变量,只能在内部调用,不能通过对象.变量名的方式调用,并且不能被继承 def func1(self, arg): \'\'\' 方法 1、方法属于类(也就是在实例化的时候不会像对象的变量一样单独开辟内存空间) 2、self表示类的对象本身,当我们通过对象名.方法()来调用的时候,解释器会自动将对象作为第一个参数传给方法,方法名.方法(对象名) :return: \'\'\' # 方法体,方法体可以通过self.关键字调用对象的变量和方法 self.__var3 = arg # 方法可以调用私有变量和方法 def __func2(self): \'\'\' 私有方法,和私有变量一样,不能被继承和外部调用 :return: \'\'\' pass class Foo2(Foo): def __init__(self, arg, arg2): \'\'\' 1、这里调用了父类的初始化方法,特别注意由于“__变量名”表示的私有方法, 2、这里尽管调用了父类的构造方法,__var3变量作为父类的私有方法,子类在没有重新定义之前依然没有这个变量,这点要特别注意 :param arg: :param arg2: :return: \'\'\' super(Foo2, self).__init__(arg, arg2) self.__var3 = arg2 # 由于__var3是父类的私有方法,尽管调用了父类的初始化方法,子类依然不会有,所以依然需要重新定义
##参考文档
1、金角大王博客:http://www.cnblogs.com/alex3714/articles/5188179.html
2、银角大王博客:http://www.cnblogs.com/wupeiqi/articles/5017742.html
3、 65年哥:http://www.cnblogs.com/zhangxiaxuan/p/5292691.html
4. Eva_l: http://www.cnblogs.com/Eva-J/p/5009377.html
以上是关于面向对象基础部分及模块的主要内容,如果未能解决你的问题,请参考以下文章
JS面向对象基础讲解(工厂模式构造函数模式原型模式混合模式动态原型模式)
JS面向对象基础讲解(工厂模式构造函数模式原型模式混合模式动态原型模式)