Python基础(八)
面向对象编程
方法没有重载
在其他语言中,可以定义多个重名的方法,只要保证方法签名唯一即可。方法签名包含3个部分:方法名、参数数量和参数类型。而在Python中是没有方法重载的。
如果在类体中定义了多个重名的方法,只有最后一个方法有效。
方法的动态性
Python是动态语言,可以动态的为类添加新的方法,或者动态的修改类的已有的方法。
私有属性和私有方法(实现封装)
Python对于类的成员没有严格的访问控制限制,这与其他面向对象语言有区别。
关于私有属性和私有方法,有如下要点:
- 通常约定,两个下划线开头的属性(方法)是私有的,其他是公共的。
- 类内部可以访问私有属性(方法)。
- 类外部不能直接访问私有属性(方法)。
- 类外部可以通过"_类名 __私有属性(方法)名”访问私有属性。
class Employee:
def __init__(self,name,age)
self.name = name
self.__age = age # 私有属性
me = Employee("wyx",19)
print(e.name)
print(e._Employee__age)
@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("wyx",20000)
print(emp1.salary)
emp1.salary = 20000
print(emp1.salary)
class Employee:
def __init__(self,name,salary):
self.__name = name
self.__salary = salary
def get_salary(self):
return self.__salary = salary
def set_salary(self,salary):
if 1000<salary<500000:
self.__salary = salary
else:
print("录入错误!薪水在1000-50000这个范围")
emp1 = Employee("wyx",20000)
print(emp1,get_salary())
emp1.set_salary(30000)
print(emp1.get_salary())
上面两个代码的作用是一样的,但是使用@property装饰器的代码在调用的使用更为简单。
面向对象三大特征介绍
Python是面向对象的语言,也支持面向对象编程的三大特性:继承,封装(隐藏)、多态。
- 封装(隐藏):隐藏对象的属性和实现细节,只对外提供必要的方法。相当于将“细节封装起来”,只对外暴露“相关调用方法”。
- 继承:继承可以让子类具有父类的特性,提高了代码的重用性。从设计上是一种增量进化,原有父类设计不变的情况下,可以增加新的功能,或者改进已有的算法。
- 多态:多态是指同一个方法调用由于对象不同会产生不同的行为。生活中这样的例子比比皆是:同样是休息,人不同休息方法不同。张三休息是睡觉,李四休息是玩游戏,程序员休息是敲几行代码。
继承
继承是面向对象程序设计的重要特征,也是实现代码复用的重要手段。
如果一个新类继承自一个设计好的类,就直接具备了已有类的特征,就大大降低了工作难度。已有的类,我们称之为“父类或者基类”,新的类,我们称为“子类或者派生类”。
语法格式
Python支持多重继承,一个子类可以继承多个父类。继承的语法格式如下:
class 子类类名(父类1[,父类2,…]):
类体
如果在类定义中没有指定父类,则默认父类是object类。也就是说,objetc是所有类的父类,里面定义了一些所有类共有的默认实现。
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
s = Student()
s.say_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}".foramt(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("wyx",19,100)
s.say_age()
s.say_introduce # 子类重写了父类的方法,在调用时,会调用子类的方法
查看类的继承层次结构
通过类的方法mro()或者类的属性“mro”可以输出这个类的继承层次结构。
Object根类
object类是所有类的父类,因此所有的类都有object的属性。
注:
- 内置函数dir()可以方便的看到指定对象所有的属性。
- 方法也是一种特殊的属性。
重写__str__()方法
class Person:
def __init__(self,name)
self.name = name
def __str__(str):
return"名字是:{0}".format(self.name)
p = Person("wyx")
多重继承
Python支持多重继承,一个子类可以有多个“直接父类”。这样,就具备了“多个父类”的特点。但是会搞得异常复杂,尽量避免使用。
super()获得父类定义
在子类中,如果想要获得父类的方法时,我们可以通过super()来做。super()代表父类的定义,不是父类对象。
# 测试super()
class A:
def say(self):
print("A:",self)
class B(A):
def say(self):
A.say(self)
print("B:",self)
B().say()
class A:
def say(self):
print("A:",self)
class B:
def say(self):
super().say()
print("B:",self)
多态
多态是指同一个方法调用由于对象不同可能会产生不同的行为。
注意:
- 多态是方法的多态,属性没有多态
- 多态的存在有两个必要条件:继承、方法重写
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("不能吃饭")
特殊方法和运算重载符
Python的运算符实际上是通过调用对象的特殊方法实现的。
每个运算符实际上都对应了相应的方法,统计如下:
运算符 | 特殊方法 | 说明 |
---|---|---|
运算符+ | _add_ | 加法 |
运算符- | _sub_ | 减法 |
<,<=,== | _lt_, _le_, _eq_ | 比较运算符 |
>, >=,!= | _gt_, _ge_, _ne_ | 比较运算符 |
|, ^, & | _or_, _xor_, __and | 异、异或、与 |
<<, >> | _lshift_, _rshift_ | 左移、右移 |
*,/, %, // | _mul_, _truediv_, _mod_, _floorfiv_ | |
** | pow | 指数运算 |
在这里插入代码片
常用的特殊方法统计如下:
方法 | 说明 | 例子 |
---|---|---|
_init_ | 构造方法 | 对象创建:p = Person() |
_del_ | 析构方法 | 对象回收 |
_repr_, _str_ | 打印,转换 | print(a) |
_call_ | 函数调用 | a() |
_getattr_ | 点号运算 | a.xxx |
_setattr_ | 属性赋值 | a.xxx = value |
_getitem_ | 索引运算 | a[key] |
_setitem_ | 索引赋值 | a[key] = value |
_len_ | 长度 | len(a) |
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"不是同类对象,不能相加"
p1 = Person("wyx")
p2 = Person("xjj")
特殊属性
特殊方法 | 含义 |
---|---|
obj.__dict__ | 对象的属性字典 |
obj.__class__ | 对象所属的类 |
class.__bases__ | 类的基类元组(多继承) |
class.__base__ | 类的基类 |
class.__mro__ | 类层次结构 |
class.__subclasses__() | 子类列表 |
对象的浅拷贝和深拷贝
- 变量的赋值操作:只是形成两个变量,实际还是指向同一个对象。
- 浅拷贝:Python拷贝一般都是浅拷贝。拷贝时,对象包含的子对象内容不拷贝。
- 深拷贝:使用copy模块的deepcopy函数,递归拷贝对象中包含的子对象。源对象和拷贝对象所有的子对象也不同。
import copy
class MobilePhone:
def __init__(self,cpu,screen)
self.cpu = cpu
self.screen = screen
class CPU:
def calculate(self):
print("计算")
print("cpu对象:",self)
class Screen:
def show(self):
print("显示一个好看的画面")
print("screen对象:",self)
c1 = CPU()
c2 = c1
print(c1)
print(c2)
s1 = Screen()
m1 = MobilePhone(c1,s1)
m2 = copy.copy(m1) # 浅复制
print(m1,m1.cpu,m1.screen)
print(m2,m2.cpu,m2.screen) # 只有第一个地址不一样
m3 = copy.deepcopy(m1) # 深复制
print(m1,m1.cpu,m1.screen)
print(m3,m3.cpu,m3.screen)# 均不一样
组合
"is-a"关系,可以用“继承”。从而实现子类拥有的父类的方法和属性。
“has-a”关系,可以用“组合”,也能实现一个类拥有另一个类的方法和属性。
class A1:
def say_a1(self):
print("a1,a1,a1")
class B1(A1):
pass
b1 = B1()
b1.say_a1()
class A2:
def say_a2(self):
print("a2a2a2")
class B2:
def __init__(self,a):
self.a = a
a2 = A2()
b2 = B2(a2)
b2.a.say_a2()
设计模式
设计模式是面向对象语言特有的内容,是我们在面临某一类问题时候固定的做法。
工厂模式实现
工厂模式实现了创建者和调用者的分离,使用专门的工厂类将选择实现类、创建对象进行统一的管理和控制。
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("奔驰")
单例模式实现
单例模式的核心作用是确保一个类只有一个实例,并且提供一个访问该实例的全局访问点。
单例模式只生成一个实例对象,减少了对系统资源的开销。当一个对象的产生需要比较多的资源,如读取文件、产生其他依赖对象时,可以产生一个“单例对象”,然后永久驻留内存中,从而极大地降低开销。
class MySingleton:
__obj = None #类属性
__init_flag = True
def __new__(cls,*args,**kwargs):
if cls.__obj ==None:
cls.__obj = object.__new__(cls)
return cls.__obj
def __init__(self,name):
if MySingleton.__init_flag:
print("init……")
self.name = name
MySingleton.__init_flag = False
a = MySingleton("aa")
b = MySingleton("bb")