1、方法没有重载
Python 中,方法的的参数没有声明类型(调用时确定参数的类型),参数的数量可由可变参数控制。因此,Python 中是没有方法的重载的。
定义一个方法即可有多种调用方式,相当于实现了其他语言中的方法的重载。
如果我们在类体中定义了多个重名的方法,只有最后一个方法有效。
建议:不要使用重名的方法!Python 中方法没有重载。
举例:
# Python中没有方法的重载,定义多个同名方法,只有最后一个有效
class Person:
def say_hi(self):
print("hello")
def say_hi(self,name):
print("{0},hello".format(name))
p1 = Person()
# p1.say_hi() #TypeError: say_hi() missing 1 required positional argument: 'name'
p1.say_hi("SSS")
2、方法的动态性
Python 是动态语言,我们可以动态的为类添加新的方法,或者动态的修改类的已有的方法。
举例:
# 测试方法的动态性
class Person:
def work(self):
print("努力上班!")
def play_game(self):
print("{0}玩游戏".format(self))
def work2(s):
print("好好工作,努力上班!")
Person.play = play_game
Person.work = work2
p = Person()
p.play()
p.work()
测试结果:
从测试结果可以看出,Person动态的新增了play_game方法,以及work2替换了work方法。
3、私有属性和私有方法(实现封装)
关于私有属性和私有方法,有如下要点:
1. 通常我们约定,两个下划线开头的属性是私有的(private)。其他为公共的(public)。
2. 类内部可以访问私有属性(方法)
3. 类外部不能直接访问私有属性(方法)
4. 类外部可以通过“_类名__私有属性(方法)名”访问私有属性(方法)
注:方法本质上也是属性,只不过是可以通过()执行而已。
举例:
# 测试私有属性、私有方法
class Employee:
__company = "程序猿" # 私有类属性 通过dir可以查到
def __init__(self, name, age):
self.name = name
self.__age = age # 私有实例属性
def say_company(self):
print("我的公司是:", Employee.__company) # 类内部可以直接访问私有属性
print(self.name, "的年龄是:", self.__age)
self.__work()
def __work(self): # 私有实例方法 通过dir可以查到_Employee__work
print("工作!好好工作,好好赚钱。")
p1 = Employee("kdx", 22)
print(p1.name)
print(dir(p1))
p1.say_company()
print(p1._Employee__age) # 通过这种方式直接访问到私有属性。通过dir可以查到属性:_Employee__age
# print(p1.__age) # 直接访问私有属性,报错
测试:
注:从打印的 Person 对象所有属性我们可以看出。私有属性“__age”在实际存储时是按照“_Person__age”这个属性来存储的。这也就是为什么我们不能直接使用“__age”而可以使用“_Person__age”的根本原因
4、@property装饰器
@property 可以将一个方法的调用方式变成“属性调用”
举例:
# 测试@property
class Employee:
@property
def salary(self):
return 10000
emp = Employee()
print(emp.salary) # 打印10000
print(type(emp.salary)) #打印<class 'int'>
# emp.salary() # TypeError: 'int' object is not callable
# mp.salary = 2000 # @property 修饰的属性,如果没有加 setter 方法,则为只读属性。
# 此处修改报错AttributeError: can't set attribute
测试结果:
注:@property 主要用于帮助我们处理属性的读操作、写操作。对于某一个属性,我们可以直接通过:
emp.salary = 30000
如上的操作读操作、写操作。但是,这种做法不安全。比如,我需要限制薪水必须为 1-10000的数字。这时候,我们就需要通过 getter、setter 方法
举例:
# 测试@property
class Employee:
def __init__(self, name, salary):
self.name = name
self.__salary = salary
@property # 相当于salary属性的getter方法
def salary(self):
print("月薪为{0},年薪为{1}".format(self.__salary, self.__salary*12))
return self.__salary
@salary.setter
def salary(self, salary): # 相当于salary属性的setter方法
if(0 < salary < 1000000):
self.__salary = salary
else:
print("薪水录入错误!只能在0-1000000之间!")
emp1=Employee("kdx", 100)
print(emp1.salary)
emp1.salary = 200
print(emp1.salary)
测试结果:
5、属性和方法命名总结
· _xxx:保护成员,不能用“from module import * ”导入,只有类对象和子类对象能访问这些成员。
· xxx:系统定义的特殊成员
· __xxx: 类中的私有成员,只有类对象自己能访问,子类对象也不能访问。(但,在类外部可以通过“对象名. _类名__xxx”这种特殊方式访问。Python 不存在严格意义的私有成员)
注:再次强调,方法和属性都遵循上面的规则。
6、继承
语法格式:
Python支持多重继承,一个子类可以继承多个父类。继承的语法格式如下:
class 子类类名(父类1[,父类2,…]):
类体
如果在类定义中没有指定父类,则默认父类是 object 类。也就是说,object 是所有类的父类,里面定义了一些所有类共有的默认实现,比如:new()。
举例:
class Person:
def __init__(self, name, age):
self.name = name
self.__age = age
def say_age(self):
print(self.name, "的年龄是:", self.__age)
class Student(Person):
def __init__(self, name, age, score):
self.score = score
Person.__init__(self, name, age) # 构造函数中包含调用父类构造函数。根据需要,不是必须。
# 子类并不会自动调用父类的的__init__(),我们必须显式的调用它
s1 = Student("SSS ", 20, 100)
s1.say_age()
print(dir(s1))
注:构造函数中包含调用父类构造函数。根据需要,不是必须。子类并不会自动调用父类的的__init__(),我们必须显式的调用它
7、类成员的继承与重写
1. 成员继承:子类继承了父类除构造方法之外的所有成员。
2. 方法重写:子类可以重新定义父类中的方法,这样就会覆盖父类的方法,也称为“重写”
如图所示:
8、查看类的继承层次结构
通过类的方法mro()可以输出这个类的继承层次机构。
举例:
结果:
[<class ‘main.C’>, <class ‘main.B’>, <class ‘main.A’>, <class ‘object’>]
9、object根类
object类是所有类的父类,所以所有的类都有object类的属性和方法。
10、重写__str__()方法
object 有一个__str__()方法,用于返回一个对于“对象的描述”,对应于内置函数 str()经常用于 print()方法,帮助我们查看对象的信息。str()可以重写。
举例:
class Person:
def __init__(self, name, age):
self.name = name
self.__age = age
def __str__(self): # 将对象转化成一个字符串,一般用于 print 方法
return "名字是:{0},年龄是{1}".format(self.name, self.__age)
p = Person("SSS", 19)
print(p)
11、多重继承
举例:
注:这样会使类的整体层次搞的异常复杂,尽量避免使用。
12、MRO()
Python支持多继承,如果父类中有相同名字的方法,在子类没有指定父类名时,解释器将“从左向右”按顺序搜索。
MRO(Method Resolution Order):方法解析顺序。 我们可以通过 mro()方法获得“类的层次结构”,方法解析顺序也是按照这个“类的层次结构”寻找的。
如下图所示:
13、super()获得父类定义
在子类中,如果想获得父类的方法,我们可以通过super()来做。
super()代表父类的定义,不是父类对象。
举例:
# super获得父类定义
class A:
def say(self):
print("A:", self)
print("say AAAA")
class B(A):
def say(self):
# A.say(self) # 调用父类的方法
super().say() # 通过super()调用父类的方法
print("say BBB")
b = B()
b.say()
测试结果:
14、多态
多态是指同一个方法调用由于对象不同可能产生不同的行为。
注:
1、多态是方法的多态,属性没有多态。
2、多态的存在有2个必要条件:继承、方法重写。
举例:
# 多态
class Animal:
def shout(self):
print("动物叫了一声")
class Dog(Animal):
def shout(self):
print("小狗,汪汪汪")
class Cat(Animal):
def shout(self):
print("小猫,喵喵喵")
def animalshout(a):
if isinstance(a, Animal): # 如果指定的对象拥有指定的类型,则 isinstance() 函数返回 True,否则返回 False。
a.shout() # 传入的对象不同,shout 方法对应的实际行为也不同。
animalshout(Dog())
animalshout(Cat())
测试结果:
15、Python isinstance() 函数
举例:
class MyObj:
name = "Bill"
y = MyObj()
x = isinstance(y, MyObj)
print(x)
结果:
16、特殊方法和运算符重载
常见的特殊方法统计如下:
每个运算符都有相应的方法,统计如下:
举例:
a = 12
b = 32
c = a + b
d = a.__add__(b)
print("c=", c)
print("d=", d)
运算结果:
举例:实现运算符的重载
# 测试运算符的重载
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("kdx")
p2 = Person("SSS")
x = p1 + p2
print(x)
print(p1 * 3)
17、特殊属性
Python对象中包含了很多双下划线开始和结束的属性,这些是特殊属性,有特殊用法。
举例:
# 测试特殊属性
class A:
pass
class B:
pass
class C(B, A):
def __init__(self, nn):
self.nn = nn
def cc(self):
print("cc")
c = C(3)
print(dir(c))
print(c.__dict__)
print(c.__class__) # c所属的类
print(C.__bases__) # c的基类(多继承)
print(C.mro()) # c类的层次结构
print(A.__subclasses__()) # A的子类列表
测试结果:
18、对象的浅拷贝和深拷贝(理解)
举例:
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)
# 测试浅复制
print("测试浅复制......")
s1 = Screen()
m1 = MobilePhone(c1, s1)
m2 = copy.copy(m1)
print(m1, m1.cpu, m1.screen)
print(m2, m2.cpu, m2.screen)
# 测试深复制
print("测试深复制......")
m3 = copy.deepcopy(m1)
print(m1, m1.cpu, m1.screen)
print(m3, m3.cpu, m3.screen)
测试结果:
19、组合
“is-a”关系,我们可以使用“继承”。从而实现子类拥有的父类的方法和属性。“is-a”关系指的是类似这样的关系:狗是动物,dog is animal。狗类就应该继承动物类。
“has-a”关系,我们可以使用“组合”,也能实现一个类拥有另一个类的方法和属性。”has-a”关系指的是这样的关系:手机拥有 CPU。 MobilePhone has a CPU。
举例:
# 组合测试
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)
c = CPU()
s = Screen()
m = MobilePhone(c, s)
m.cpu.calculate() # 通过组合,我们也能调用cpu对象的方法。相当于手机对象间接拥有了“cpu的方法”
m.screen.show()
测试结果:
20、设计模式_工厂模式
工厂模式实现了创建者和调用者的分离,使用专门的工厂类将选择实现类、创建对象进行统一的管理和控制。
举例:
# 工厂模式
class CarFactory:
def createCar(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.createCar("奔驰")
c2 = factory.createCar("宝马")
print(c1)
print(c2)
测试结果:
21、设计模式_单例模式
单例模式(Singleton Pattern)的核心作用是确保一个类只有一个实例,并且提供一个访问该实例的全局访问点。
单例模式只生成一个实例对象,减少了对系统资源的开销。当一个对象的产生需要比较多的资源,如读取配置文件、产生其他依赖对象时,可以产生一个“单例对象”,然后永久驻留内存中,从而极大的降低开销。
举例:
# 单例模式
class MySingleton:
__obj = None
__init_flag = True
def __new__(cls, *args, **kwargs):
if cls.__obj is 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")
print(a)
b = MySingleton("bb")
print(b)
测试结果;
22、测试工厂模式和单例模式的整合使用
举例理解:
# 测试工厂模式和单例模式的整合使用
class CarFactory:
__obj = None # 类属性
__init_flag = True
def create_car(self, brand):
if brand == "奔驰":
return Benz()
elif brand == "宝马":
return BMW()
elif brand == "比亚迪":
return BYD()
else:
return "未知品牌,无法创建"
def __new__(cls, *args, **kwargs):
if cls.__obj is None:
cls.__obj = object.__new__(cls)
return cls.__obj
def __init__(self):
if CarFactory.__init_flag:
print("init CarFactory....")
CarFactory.__init_flag = False
class Benz:
pass
class BMW:
pass
class BYD:
pass
factory = CarFactory()
c1 = factory.create_car("奔驰")
c2 = factory.create_car("比亚迪")
print(c1)
print(c2)
factory2 = CarFactory()
print(factory)
print(factory2)
测试结果: