面向对象是一种编程方式,此编程方式的实现基于对 类 和 对象 的使用。
Python从设计之初就已经是一门面向对象的语言,正因为如此,在Python中创建一个类和对象是很容易的。
特性:
封装
封装最好理解了。封装是面向对象的特征之一,是对象和类概念的主要特性。
封装,也就是把客观事物封装成抽象的类,并且类可以把自己的数据和方法只让可信的类或者对象操作,对不可信的进行信息隐藏。
__init__ 是封装必不可少的,看列子:
class Init(): def __init__(self,name,age,gender): self.Name = name self.Age = age self.Gender = gender obj1 = Init('xiao',15,'男') obj2 = Init('yao',16,'女') print(obj1.Name) print(obj2.Name)
这样实现了数据封装
xiao yao
继承
继承是指这样一种能力:它可以使用现有类的所有功能,并在无需重新编写原来的类的情况下对这些功能进行扩展。(此处我们只讨论python3的继承)
通过继承创建的新类称为“子类”或“派生类”。
被继承的类称为“基类”、“父类”或“超类”。
继承的过程,就是从一般到特殊的过程。
要实现继承,可以通过“继承”(Inheritance)和“组合”(Composition)来实现。
在某些 OOP 语言中,一个子类可以继承多个基类。但是一般情况下,一个子类只能有一个基类,要实现多重继承,可以通过多级继承来实现。
class C1(): def c1(self): print('C1') class C2(C1): def c2(self): print('C2') class C3(): def c3(self): print('C3') def c1(self): print('C3') class C4(C2,C3): def c4(self): print('C4') obj = C4() obj.c1() obj1 = C3() obj1.c1()
输出结果:
C1 C3
可见,C4继承C2,C3,C2又继承C1,所以obj会有c1方法。
类的继承可以总结为:
1.左侧优先
class C4(C2,C3) 这里C2比C3优先
2.深度优先
上面例子C1和C3都有c1方法,但是最后C4继承的是C1的c1
3.有共同的父类,最后找父类
看图红色箭头表示继承关系,黑色箭头表示查找关系
图一: 图二:
3.多态
方法:
类方法:由类调用; 至少一个cls参数;执行类方法时,自动将调用该方法的类复制给cls;
静态方法:由类调用;无默认参数;
class Foo: def __init__(self, name): """ 定义内置方法,至少有一个self参数 """ self.name = name def ord_func(self): """ 定义普通方法,至少有一个self参数 """ print('普通方法') @classmethod def class_func(cls): """ 定义类方法,至少有一个cls参数 """ print('类方法') @staticmethod def static_func(): """ 定义静态方法 ,无默认参数""" print('静态方法') @property def property_fuc(self): """ 定义属性方法,至少有一个self参数 """ print('属性方法') # 调用普通方法 f = Foo('那么') f.ord_func() # 调用类方法 Foo.class_func() f.class_func() # 调用静态方法 Foo.static_func() f.static_func() # 调用属性方法 f.property_fuc
实例是可以访问类方法和静态方法的,但不建议这样做,容易混淆。
变量
class Province: # 类变量 country = '中国' def __init__(self, param1): # 实例变量 self.name = param1 # 直接访问普通字段 obj = Province('北京') print(obj.name) # 直接访问静态字段 print(Province.country) print(obj.country)
我们可看到同方法相似,实例也是可访问类变量的。
对于每一个类的变量而言都有两种形式:
- 公有变量,在任何地方都能访问
- 私有变量,只有在类的内部才能方法
class A: name = "公有类变量" def func(self): print(A.name) class B(A): def show(self): print(A.name) A.name # 类访问 obj = A() obj.func() # 类内部可以访问 obj_son = B() obj_son.show() # 派生类中可以访问
class C: __name = "私有类字段" def func(self): print(C.__name) class D(C): def show(self): print(C.__name) C.__name # 类访问 ==> 错误 obj = C() obj.func() # 类内部可以访问 ==> 正确 obj_son = D() obj_son.show() # 派生类中可以访问 ==> 错误
class C: def __init__(self): self.foo = "公有实例变量" def func(self): print(self.foo) # 类内部访问 class D(C): def show(self): print(self.foo) # 派生类中访问 obj = C() obj.foo # 通过对象访问 obj.func() # 类内部访问 obj_son = D() obj_son.show() # 派生类中访问
class C: def __init__(self): self.__foo = "私有实例字段" def func(self): print(self.__foo) # 类内部访问 class D(C): def show(self): print(self.__foo) # 派生类中访问 obj = C() obj.__foo # 通过对象访问 ==> 错误 obj.func() # 类内部访问 ==> 正确 obj_son = D() obj_son.show() # 派生类中访问 ==> 错误
注:
非要访问私有属性的话,可以通过 对象._类__属性名 ( print(obj._C__foo) )
新式类&经典类
新式类很早在2.2就出现了,所以经典类(旧式类)完全是兼容的问题,Python3里的类全部都是新式类.
python2.X中
#新式类 class C(object): pass #经典类 class B: pass
python3.X中 由于没有经典类,所以上述两种写法都表示新式类。