面向对象三大特征:
封装
继承
多态
1. 封装
封装可以被认为是一个保护屏障,防止该类的代码和数据被外部类定义的代码随机访问。要访问该类的代码和数据,必须通过严格的接口控制。
封装最主要的功能在于我们能修改自己的实现代码,而不用修改那些调用我们代码的程序片段。
封装的优点
- 良好的封装能够减少耦合。
- 类内部的结构可以自由修改。
- 可以对成员变量进行更精确的控制。
- 隐藏信息,实现细节。
为了保护类里面的属性,可以采用如下方式解决:
5. 把类中变量定义为私有变量,即在属性名的前面加上两个下划线;
6. 由于私有变量只能被类中的成员函数修改和访问,所以需要添加用于设置和获取属性值的两个方法供外界调用。
例:
class Person:
def __init__(self, name, age):
self.__name = name
self.__age = age
def setAge(self, new_age):
if new_age<0 or new_age>160:
return
else:
self.__age = new_age
def getAge(self):
return self.__age
laowang = Person('老王', 30)
laowang.setAge(300)
print(laowang.getAge())
laowang.setAge(80)
print(laowang.getAge())
laowang = Person('老王', 30)
laowang.__age=800
print(laowang.__age)
2. 继承
在程序中,继承描述的是事物之间的所属关系。
类的继承是指在一个现有类的基础上构建一个新的类,构建出来的新类被称作子类。
2.1 单继承
Python程序中,继承使用如下语法格式标注:
class 子类名(父类名):
假设有一个类为A,A派生出来了子类B,示例如下:
class B(A):
class A(object):
#默认是继承自object的
例:
class Animal(object):
def __init__(self,food):
self.eatFood = food
def eat(self):
print('It likes eating ' + self.eatFood)
class Cat(Animal):
pass
class Monkey(Animal):
pass
c = Cat('fish')
c.eat()
m = Monkey('banana')
m.eat()
注意:子类不重写__init__,实例化子类时,会自动调用父类定义的__init__,但重写了__init__时,实例化子类,就不会调用父类已经定义的__init__
2,2 多继承
现实生活中,一个派生类往往会有多个基类。比如沙发床是沙发和床的功能的组合,这都是多重继承的体现。
Python支持多继承,多继承就是子类拥有多个父类,并且具有它们共同的特征,即子类继承了父类的方法和属性。
多继承可以看做是单继承的扩展,语法格式如下:
class 子类名(父类1,父类2…):
如果子类继承的多个父类间是平行的关系,子类先继承的哪个类就会调用哪个类的方法。
例:
class Sofa():
def __init__(self):
self.sit = True
print("继承Sofa")
class Bed():
def __init__(self):
self.sleep = True
print("继承Bed")
class SofaBed(Sofa,Bed):
def __init__(self):
Sofa.__init__(self)
Bed.__init__(self)
print(f'I can sit on the sofa:{
self.sit}')
print(f'I can sleep in the bed:{
self.sleep}')
s = SofaBed()
注意:如果想继承父类的对象属性,则需要在子类的构造方法中,显示地调用父类的构造方法。
2.3 重写父类方法和调用父类方法
在继承关系中,子类会自动拥有父类定义的方法,但是有时子类想要按照自己的方式实现方法,即对父类中继承来的方法进行重写,使得子类中的方法覆盖掉跟父类同名的方法。
- 需要注意的是,在子类中重写的方法要和父类被重写的方法具有相同的方法名和参数列表。
方法重写:
3. 多态
多态的目的:一个接口,多种实现
例:
class People(object):
def say(self):
pass
class American(People):
def say(self):
print("Hello")
class Chinese(People):
def say(self):
print("你好")
def greet(obj):
obj.say()
a = American()
c = Chinese()
greet(a)
greet(c)
4. 类属性和实例属性
4.1 类属性
类属性是类所拥有的属性,它需要在类中进行显示地定义(位于类内部,方法的外面),当使用类.属性名方式使用时它被所有类的实例对象所共有,在内存中只存在一个副本。
class Cat(object):
#类属性
num = 0
4.2 实例属性
通过“实例.属性”添加属性的属性都是实例属性。
class Cat(object):
num = 0
c = Cat()
#实例属性
c.newNum = 1
class Cat(object):
num = 0
def __init__(self):
# 实例属性
self.name = 'mimi'
类属性和实例属性实例:
class AAA():
aaa = 10
# 情形1
obj1 = AAA()
obj2 = AAA()
print(obj1.aaa, obj2.aaa, AAA.aaa)
# 情形2
obj1.aaa += 2
print(obj1.aaa, obj2.aaa, AAA.aaa)
# 情形3
AAA.aaa += 3
print(obj1.aaa, obj2.aaa, AAA.aaa)
情形1的结果是:10 10 10;
情形2的结果是:12 10 10;
情形3的结果是:12 13 13;
这个实例涉及到Python中属性的获取存在一个向上查找机制,如果不理解上面代码的原理,可以参考关于Python类属性和实例属性的讨论
5. 类方法和静态方法
5.1 类方法
使用修饰器@classmethod来标识类方法。
class 类名:
@classmethod
def 类方法名(self):
方法体
要想调用类方法,既可以通过对象名.函数名方式调用类方法,又可以通过类名.函数名调用类方法,这两种方法没有任何区别。
例:
class Cat:
name = 'mimi'
@classmethod
def fun(self):
print(self.name)
c = Cat()
#对象名.函数名
c.fun()
#类名.函数名
Cat.fun()
注意:类方法只能使用类变量,因为不用实例化就可以使用。所以调用对象变量会报错。
5.2 静态方法
使用修饰器@staticmethod来标识静态方法。
class 类名:
@staticmethod
def 静态方法名():
方法体
- 静态方法是没有self参数,在静态方法中无法访问实例变量。
- 静态方法中不可以直接访问类属性,但是可以通过类名引用类属性。
- 静态方法跟定义它的类没有直接关系,只是起到了类似函数的作用。
例:
class Cat:
eyes = 2
@staticmethod
def look():
#通过类名引用类属性
print(Cat.eyes)
c = Cat()
c.look()
#类名.函数名
Cat.look()
面向对象部分就到这里了-----------