从0开始学python_面向对象进阶
私有属性和私有方法(实现封装)
Python 对于类的成员没有严格的访问控制限制,这与其他面向对象语言有区别。关于私有 属性和私有方法,有如下要点:
- 通常我们约定,两个下划线开头的属性是私有的(private)。其他为公共的(public)。 2. 类内部可以访问私有属性(方法)
- 类外部不能直接访问私有属性(方法)
- 类外部可以通过“_类名__私有属性(方法)名”访问私有属性(方法)
#测试私有属性
class Employee:
def __init__(self,name,age):
self.name=name
self.__age=age
e=Employee('高淇',18)
print(e.name)
#print(e.age)
print(e._Employee__age)
print(dir(e))
@property 装饰器:
@property 可以将一个方法的调用方式变成“属性调用”。下面是一个简单的示例,让大 家体会一下这种转变:
#@property装饰器的用法
class Employee:
def __init__(self,name,salary):
self.__name=name
self.__salary=salary
@property
def salary(self):
return self.__salary
@salary.setter
def salary(self,salary):
if 1000<salary<50000:
self.__salary=salary
else:
print('录入错误,薪水在1000-50000之间')
emp1=Employee('高淇',30000)
print(emp1.salary)
emp1.salary=2000
print(emp1.salary)
#不用装饰器时的用法
class Employee:
def __init__(self,name,salary):
self.__name=name
self.__salary=salary
def get_salary(self):
return self.__salary
def set_salary(self,salary):
if 1000 < salary < 50000:
self.__salary = salary
else:
print('录入错误,薪水在1000-50000之间')
emp1=Employee('高淇',10000)
print(emp1.get_salary())
emp1.set_salary(5000)
print(emp1.get_salary())
@property 主要用于帮助我们处理属性的读操作、写操作。对于某一个属性,我们可以直 接通过:
emp1.salary = 30000 如上的操作读操作、写操作。但是,这种做法不安全。比如,我需要限制薪水必须为 1-10000 的数字。这时候,我们就需要通过 getter、setter 方法来处理。
属性和方法命名总结
· _xxx:保护成员,不能用“from module import * ”导入,只有类对象和子类对象能访 问这些成员。
· xxx:系统定义的特殊成员
· __xxx: 类中的私有成员,只有类对象自己能访问,子类对象也不能访问。(但,在类外 部可以通过“对象名. _类名__xxx”(e._Employee__age)这种特殊方式访问。Python 不存在严格意义的私有成员)
注:再次强调,方法和属性都遵循上面的规则。
**
面向对象三大特征介绍
**
Python 是面向对象的语言,也支持面向对象编程的三大特性:继承、封装(隐藏)、多态。
·封装(隐藏)
隐藏对象的属性和实现细节,只对外提供必要的方法。相当于将“细节封装起来”,只 对外暴露“相关调用方法”。
通过前面学习的“私有属性、私有方法”的方式,实现“封装”。Python 追求简洁的 语法,没有严格的语法级别的“访问控制符”,更多的是依靠程序员自觉实现。
·继承
继承可以让子类具有父类的特性,提高了代码的重用性。
从设计上是一种增量进化,原有父类设计不变的情况下,可以增加新的功能,或者改进 已有的算法。
·多态
多态是指同一个方法调用由于对象不同会产生不同的行为。生活中这样的例子比比皆 是:同样是休息方法,人不同休息方法不同。张三休息是睡觉,李四休息是玩游戏,程序员休息是“敲几行代码”。
继承:
继承是面向对象程序设计的重要特征,也是实现“代码复用”的重要手段。
如果一个新类继承自一个设计好的类,就直接具备了已有类的特征,就大大降低了工作 难度。已有的类,我们称为“父类或者基类”,新的类,我们称为“子类或者派生类”。
#测试继承的基本属性
class Person:
def __init__(self,name,age):
self.name=name
self.__age=age #私有属性
def say_age(self):
print('年龄,年龄,我也不知道')
class Student(Person):
def __init__(self,name,age,score):
Person.__init__(self,name,age) #调用父类的属性
self.score=score
#Student-->Person-->object类
print(Student.mro())
s=Student('高淇',18,80)
s.say_age()
print(s.name)
#print(s.age) 子类不能直接调用父类的私有属性
print(dir(s))
print(s._Person__age) #这样调用私有属性就可以了
方法重写:
#方法的重写
class Person:
def __init__(self,name,age):
self.name=name
self.__age=age #私有属性
def say_age(self):
print('我的年龄:',self.__age)
def say_introduce(self):
print('我的名字是{0}'.format(self.name))
class Student(Person):
def __init__(self,name,age,score):
Person.__init__(self,name,age) #必须显式的调用父类的初始化方法,不然解释器不会调用
self.score=score
def say_introduce(self):
#重写了父类的方法
print('报告老师,我的名字是:{0}'.format(self.name))
s=Student('高淇',18,80)
s.say_age()
s.say_introduce()
重写__str__()方法
object 有一个__str__()方法,用于返回一个对于“对象的描述”,对应于内置函数 str() 经常用于 print()方法,帮助我们查看对象的信息。str()可以重写。
#测试重写object的__str__()
class Person: #默认继承object类
def __init__(self,name):
self.name=name
def __str__(self):
return '名字是:{0}'.format(self.name)
p=Person('高淇')
print(p)
多重继承
Python 支持多重继承,一个子类可以有多个“直接父类”。这样,就具备了“多个父 类”的特点。但是由于,这样会被“类的整体层次”搞的异常复杂,尽量避免使用。
MRO()
Python 支持多继承,如果父类中有相同名字的方法,在子类没有指定父类名时,解释器将 “从左向右”按顺序搜索。
super()获得父类定义
在子类中,如果想要获得父类的方法时,我们可以通过 super()来做。
super()代表父类的定义,不是父类对象。
#测试super(),代表父类的定义,而不是父类的对象
class A:
def say(self):
print('A:',self)
class B(A):
def say(self):
#A.say(self)
super().say()
print('B:',self)
B().say
多态
多态(polymorphism)是指同一个方法调用由于对象不同可能会产生不同的行为。在现实 生活中,我们有很多例子。比如:同样是调用人的休息方法,张三的休息是睡觉,李四的休 息是玩游戏,高淇老师是敲代码。同样是吃饭的方法,中国人用筷子吃饭,英国人用刀叉吃 饭,印度人用手吃饭。
关于多态要注意以下 2 点:
- 多态是方法的多态,属性没有多态。
- 多态的存在有 2 个必要条件:继承、方法重写。
#多态
class Man:
def eat(self):
print('饿了,吃饭啦!')
class Chinese(Man):
def eat(self):
print('中国人用筷子吃饭')
class English(Man):
def eat(self):
print('英国人用叉子吃饭')
class Indian(Man):
def eat(self):
print('印度人用右手吃饭')
def manEat(m):
if isinstance(m,Man):
m.eat()
else:
print('不能吃饭')
manEat(Chinese())
manEat(English())
运算符重载:
#运算符重载
class Person:
def __init__(self,name):
self.name=name
def __add__(self,other):
if isinstance(other,Person):
return'{0}--{1}'.format(self.name,other.name)
else:
return'不是同类对象,不能相加'
def __mul__(self,other):
if isinstance(other,int):
return self.name*other
else:
return'不是同类对象,不能相乘'
p1=Person('高淇')
p2=Person('高希希')
x=p1+p2
print(x)
print(p1*3)
运算结果:
高淇–高希希
高淇高淇高淇
特殊属性:
Python 对象中包含了很多双下划线开始和结束的属性,这些是特殊属性,有特殊用法。这 里我们列出常见的特殊属性:
继承和组合:
#测试has-a关系,使用组合
class MobilePhone:
def __init__(self,cpu,screen):
self.cpu=cpu
self.screen=screen
class CPU:
def calculate(self):
print('算你个12345')
print('cpu对象:',self)
class Screen:
def show(self):
print('显示一个好看的画面,亮瞎你的钛合金大眼')
print('screen对象:',self)
m=MobilePhone(CPU(),Screen())
m.cpu.calculate()
m.screen.show()
工厂模式:
#测试工厂模式
class CarFactory:
def creat_car(self,brand):
if brand=='奔驰':
return Benz()
elif brand=='宝马':
return BMW()
elif brand=='比亚迪':
return BYD()
else:
return '未知品牌,无法创建'
class Benz:
pass
class BMW:
pass
class BYD:
pass
factory=CarFactory()
c1=factory.creat_car('奔驰')
c2=factory.creat_car('比亚迪')
print(c1)
print(c2)