面向对象编程是一种编程方式,使用 “类” 和 “对象” 来实现,因此,面向对象编程其实就是对 “类” 和 “对象” 的使用。类就是一个模板,模板里能够包含多个方法(函数),方法里实现各类各样的功能,对象则是根据模板建立的实例,经过实例,对象能够执行类中的方法,每一个对象都拥有相同的方法,但各自的数据可能不一样。java
在Python中,定义类是经过class
关键字,class
后面紧接着是类名,类名一般是大写开头的单词,紧接着是('要继承的类名')
,表示该类是从哪一个类继承下来的,能够有多个父类(基类),一般若是没有合适的继承类,就使用object
类,这是全部类最终都会继承的类,也能够不写。python
class F1(object): def __init__(self,name,age): self.name = name self.age = age f1 = F1('python',27) 上面的这个__init__()叫作初始化方法(或构造方法), 在类实例化时,这个方法(虽然它是函数形式,但在类中就不叫函数了,叫方法)会自动执行,
进行一些初始化的动做,因此咱们这里写的__init__(self,name,age)就是要在建立一个角色时给它设置这些属性。
参数self有什么用呢?
1.在内存中开辟一块空间指向f1这个变量名
2.实例化F1这个类首先执行其中的__init__()方法,至关于F1.__init__(f1,'python',27),是为了把'python',27这2个值跟刚开辟的f1关联起来,由于关联起来后,你就能够直接f1.name, f1.age 这样来调用啦。因此,为实现这种关联,在调用__init__方法时,就必须把f1这个变量也传进去,不然__init__不知道要把那2个参数跟谁关联,self其实就是实例化对象f1被看成参数传递了。
3.因此这个__init__(…)构造方法里的,self.name = name , self.age = age 等等就是要把这几个值存到f1的内存空间里。 程序员
面向对象有3大特性,首先咱们来讲第一个特性,封装,封装通常是经过在类中封装数据,而经过对象或者self获取。和其余面向对象的语言相似,也是经过构造函数来进行数据封装。下面来看一下代码。 数据库
class A: def __init__(self,name): # 构造函数,初始化数据, self.name=name # 封装数据 def f1(self): print(self.name) # 经过self间接获取封装的数据 a=A('json') # 至关于A.__init__(a,'json')将'json'封装到a中的name属性中 print(a.name) # 直接调用a对象的name属性 a.f1() # python会把a看成参数传递给a.f1(a),因此print(a.name)
还有一种封装的方式,使用私用的属性来封装数据,看一下具体的用法,编程
class A: name='Jason' __age=18 # 私有类属性 def __init__(self): self.__like='soccer' # 私有实例属性 self.hobby='kkkk' def f1(self): print(self.__age) # 私有类属性,私有实例属性只能被类中的方法调用 print(self.__like) # A.__age # 外部获取不到私有类属性,数据被封装起来 a=A() # soccer a.f1() # 18 print(a.hobby)
复杂的封装(必定要搞清楚): 将类封装进对象中 json
class c1: def __init__(self,name,obj): self.name = name self.obj = obj class c2: def __init__(self,name,age): self.name = name self.age = age def show(self): print(self.name) class c3: def __init__(self,a1): self.money = 123 self.aaa = a1 c2_obj = c2('aa',12) # 将字符串'aa',数字12封装到c2_obj.name和c2_obj.age中 c1_obj = c1('python',c2_obj) # 将字符串'python'封装到c1_obj.name中,将c2_obj中的属性c2_obj.name,c2_obj.age封装到c1_obj.obj中 c3_obj = c3(c1_obj) # 将c1_obj中的全部属性,包括(c2_obj的所全部方法和属性) print(c3_obj.aaa.obj.name) #c3类中找到c2类中的属性 ret = c3_obj.aaa.obj.show() #c3类中找到c2类中的方法执行并接收返回值 print(ret)
继承的本质是将父类中的方法所有复制一份到子类中。Python里面的继承能够多继承,经过继承,能够得到父类的功能,继承的时候,若是父类中有重复的方法,优先找本身c#
经过继承建立的新类称为“子类”或“派生类”。被继承的类称为“基类”、“父类”或“超类”。
函数式编程
(1)、Python的类能够继承多个类,Java和C#中则只能继承一个类函数
(2)、Python的类若是继承了多个类,那么其寻找方法的方式有两种,分别是:深度优先和广度优先spa
经典类和新式类,从字面上能够看出一个老一个新,新的必然包含了跟多的功能,也是以后推荐的写法,从写法上区分的话,若是 当前类或者父类继承了object类,那么该类即是新式类,不然即是经典类。
继承的执行过程例子:
class A: def f(self): print('a') class B: def f(self): print('b') def f1(self): print('bbbb') class C(A,B): def f1(self): print('c') cc=C() cc.f() # 结果为a,在C类中没有f()这个方法时,继承时A基类写在前面,因此优先找A类中的f()方法 cc.f1() # 结果为c,在C类中有f1()方法,则优先执行本身的方法
下面是重点和难点,在其余源码都是这么干的
class A: def bar(self): print('bar') self.f1() class B(A): def f1(self): print('b') class C(): def f1(self): print('c') class D(B): def f1(self): print('d') class E(C,D): pass d=D() d.bar()
上述继承的执行过程:
(3)、除了继承方法,还能够继承父类的构造函数
# 继承构造方法 class A: def __init__(self): self.name='jason' class B(A): def __init__(self): self.age='16' super(B,self).__init__() # A.__init__(self) #另外一种继承构造函数的方法 d=B()
(4)、强制使用父类中的方法(很是有用)使用:super(子类类名,self).父类中的方法
class C1: def f1(self): print('c1.f1') return 123 class C2(C1): def f1(self): # 主动执行父类的f1方法 ret = super(C2,self).f1() print('c2.f1') return ret # C1.f1(self) 第二种方法,主动执行父类的方法,不经常使用 obj = C2() obj.f1()
Pyhon不支持Java和C#这一类强类型语言中多态的写法,python自己就是支持多态的,因此在Python面向对象里面讨论多态并无什么意义,其Python崇尚“鸭子类型”。
class F1: pass class S1(F1): def show(self): print('S1.show') class S2(F1): def show(self): print('S2.show') def Func(obj): print(obj.show()) s1_obj = S1() Func(s1_obj) s2_obj = S2() Func(s2_obj)
在java,c#中定义参数是须要强制定义一个参数是什么类型的参数,相似下面的代码
class A: pass class B(A): pass class C(A): pass # arg参数:必须是A类型或A的子类 def func(A arg): print(arg) # obj = B() # obj = C() obj = A() func(obj)
以上就是本节对于面向对象初级知识的介绍,总结以下:
问答专区
问题一:什么样的代码才是面向对象?
答:从简单来讲,若是程序中的全部功能都是用 类 和 对象 来实现,那么就是面向对象编程了。
问题二:函数式编程 和 面向对象 如何选择?分别在什么状况下使用?
答:须知:对于 C# 和 Java 程序员来讲不存在这个问题,由于该两门语言只支持面向对象编程(不支持函数式编程)。而对于 Python 和 PHP 等语言却同时支持两种编程方式,且函数式编程能完成的操做,面向对象均可以实现;而面向对象的能完成的操做,函数式编程不行(函数式编程没法实现面向对象的封装功能)。
因此,通常在Python开发中,所有使用面向对象 或 面向对象和函数式混合使用
面向对象的应用场景:
class SqlHelper: def __init__(self, host, user, pwd): self.host = host self.user = user self.pwd = pwd def 增(self): # 使用主机名、用户名、密码(self.host 、self.user 、self.pwd)打开数据库链接 # do something # 关闭数据库链接 def 删(self): # 使用主机名、用户名、密码(self.host 、self.user 、self.pwd)打开数据库链接 # do something # 关闭数据库链接 def 改(self): # 使用主机名、用户名、密码(self.host 、self.user 、self.pwd)打开数据库链接 # do something # 关闭数据库链接 def 查(self): # 使用主机名、用户名、密码(self.host 、self.user 、self.pwd)打开数据库链接 # do something # 关闭数据库链接# do something
如:张3、李4、杨五,他们都有姓名、年龄、血型,但其都是不相同。即:属性个数相同,但值不相同
class Person: def __init__(self, name ,age ,blood_type): self.name = name self.age = age self.blood_type = blood_type def detail(self): temp = "i am %s, age %s , blood type %s " % (self.name, self.age, self.blood_type) print temp zhangsan = Person('张三', 18, 'A') lisi = Person('李四', 73, 'AB') yangwu = Person('杨五', 84, 'A')
问题三:类和对象在内存中是如何保存?
答:类以及类中的方法在内存中只有一份,而根据类建立的每个对象都在内存中须要存一份,大体以下图:
如上图所示,根据类建立对象时,对象中除了封装 name 和 age 的值以外,还会保存一个类对象指针,该值指向当前对象的类。
当经过 obj1 执行 【方法一】 时,过程以下: