在其他语言中可以定义多个重名的方法,只要保证方法签名唯一即可,方法签名包含三个部分:方法名、参数数量、参数类型
python中方法的参数没有类型(调用时确定参数的类型),参数的数量也可以由可变参数控制。因此,python中是没有方法的重载的,定义一个方法即可有多种调用方式,相当于实现了其他语言中的方法的重载。
如果在类体中定义了多个重名的方法,只有最后一个方法有效。
class Student
def say_hi
python是动态语言,可以动态的为类添加方法,或者动态的修改类的已有的方法。
#测试方法的动态性
class Person:
def work(self):
print('努力上班')
def play_game(a):
print('{0}在玩游戏'.format(a))
def study(b)
print('好好上学!')
p=Person()
p.work()
p.play_game() #报错,因为person class中没有play_game
#但是我们可以直接添加
Person.game=play_game
p.game() #-->翻译器翻译:Person.game(p)
# 也可以将原有方法修改
Person.work=study
p.work() #这里返回的结果不是原来的努力上班了,而是好好上学
class Person:
def work(self):
print('努力上班')
def play(self):
print('{0}在玩'.format(self))
p=Person()
p.play() #-->翻译器翻译:Person.play(p)
python对于类的成员没有严格的访问控制吸纳之,这与面向对象的其它语言有差别。
隐藏对象的属性和实现细节,只对外提供必要的方法。
通过前面学习的私有属性私有方法的方式实现封装,但是python最求简介没有严格的语法级别的‘访问控制符’,更多依靠程序员的自觉实现。
私有属性和私有方法,如下要点:
通常约定,两个下划线开头的属性是私有的,其他为公共的
类内部可以访问私有属性(方法)
类外部不能直接访问私有属性(方法)
类外部可以通过‘_类名__私有属性(方法)名’(下划线类名两下划线私有属性名)访问私有属性(方法)
测试私有属性&私有方法(本质相同方法就是属性)
class Employee
def __init__(self,name,age):
self.name = name #公开的
self.age = age
e = Employee('vivi',18) #外部
print(e.name)
print(e.age)
print('*****************************')
# 把属性和方法私有化
class Employee
def __init__(self,name,age):
self.name = name #公开的
self.__age = age #将属性私有化
def__work(self): #私有方法
print('好好学习,天天向上')
print('年龄:{0}'.format(self.__age)) #类内部可以自己调用自己的私有属性
e = Employee('vivi',18) #外部
print(e.name)
print(e.__age) #类外部调用私有属性会报错
print(_Employee.__age) #可以访问了
@property装饰器
可以将一个方法的调用方式变成“属性调用”。给属性增加对应的get和set方法。
class Employee:
def __init__(self,name,salary1):
self.__name=name
self.__salary=salary1
def get_salary(self):
return self.__salary
def set_salary(self,salary2):
if 1000<salary2<50000:
self.__salary=salary2
else:
print('输入错误')
e=Employee('vivi',10000) #传参给salary1
print(e.get_salary)#此时self.__salary=salary1,这时候get_salary相当于属性直接通过.get_salary来调用,得到的结果是10000,对比之前方法的调用print(e.get_salary())
e.set_salary=20000) #传参给salary2,通过逻辑后, self.__salary=salary2
print(e.get_salary()) #得到的结果是20000
class Employee:
def __init__(self,name,salary1):
self.__name=name
self.__salary=salary1
@property
def get_salary(self):
return self.__salary
@get_salary.setter #是上面这个方法的setter,如果没有这句话则print(e.get_salary)的值不会改变
def set_salary(self,salary2):
if 1000<salary2<50000:
self.__salary=salary2
else:
print('输入错误')
e=Employee('vivi',10000) #传参给salary1
print(e.get_salary)#此时self.__salary=salary1,这时候get_salary相当于属性直接通过.get_salary来调用,得到的结果是10000,对比之前方法的调用print(e.get_salary())
e.set_salary=20000 #传参给salary2,通过逻辑后, self.__salary=salary2
print(e.get_salary ) #得到的结果是20000
继承可以让子类拥有父类的特性,提高代码的重用性,是实现代码复用的重要手段。
设计上是一种增量进化,原有父类设计不变的情况下,可以增加新的功能,或者改进已有的算法。
如果一个新类继承自一个设计好的类,就直接具备了已有类的特征,大大降低了工作的难度。已有的类我们称为父类或基类,新的类称为子类或派生类。
python继承多重继承,一个子类可以继承多个父类,语法格式:
class 子类类名(父类1[,父类2…]):
类体
如果在类定义中没有指定父类,那么默认是object类,也就是说,object是所有类的父类,里面定义了一些所有类的共有实现,比如:__new __()
定义子类时,必须在其构造函数中调用父类的构造函数,语法如下:
父类名.__init __(self,参数列表)
class Person:
def __init__(self,name,age,gender):
self.name = name #实例属性
self.age = age
self.__gender = gender #私有属性
def say_age(self): #在Person中创建一个实例方法
print('你的年龄是')
class Student(Person): #继承Person
def __init__(self,name,age,score)
Person__init__(self,name,age) #显示的调用父类的初始化方法,不然解释器虽不会报错但是不会去调用
self.score = score
s=student(vivi,19,100) #创建子类方法
s.say_age #子类中没有的方法,调用父类里面的,返回结果‘你的年龄是’
print(s.name) #拥有了父类的属性,返回值为‘vivi’
print(s.gender) #私有属性可以拥有不能直接用
print(s._Person__gender)# 调用私有属性
class Person:
def __init__(self,name,age,gender):
self.name = name #实例属性
self.age = age
self.__gender = gender #私有属性
def say_gender(self): #在Person中创建一个实例方法
print('你的性别是:',self.__gender) #同一个类中可以调用私有属性
def say_name(self):
print('你的姓名是{0}'.format(self.name))
class Student(Person): #继承Person
def __init__(self,name,age,score)
Person__init__(self,name,age) #显示的调用父类的初始化方法,不然解释器虽不会报错但是不会去调用
self.score = score
def say_name(self):
print('报告,我的名字是{0}'.format(self.name))
s=Student('vivi',18,100)
s.say_gender()
s.say_name() #第一遍没有重写的时候返回的是你的名字是:vivi
s.say_name() #第二遍重写,返回的是报告,我的名字是:vivi
通过类的方法mro(),或者类的属性__mro__可以输出这个类的继承层次结构
class A:pass
class B(A):pass
class C(B):pass
print(C.mro())
返回结果:
[
由上图可以看出,object类是所有类的父类,因此所有类都有object类的属性和方法所以有必要研究一下object类的结构
# 定义一个类
class Person
def __init__(self,name,age):
self.name = name
self.age = age
def say_name(self):
print('你的名字是:',self.name)
obj = object() #调用所有父类的父类,注意小写o
s = Person('vivi',18)
print(dir(obj))
print(dir(s))
object中的__str__方法用于返回一个对于对象的描述,对应与内置函数str()经常用于print()方法,帮助我们查看对象的信息,并且__str__可以重写。
calss Person:
def __init__(self,name):
self.name = name
p = Person('vivi')
print(p) #这时默认返回的是__str__,也就是Person这个对象的说明<__main__Person object at 0x0042D410>
# 改写__str__
def __str__(self):
print('你好',self.name)
print(p) #这里返回的就是改过的‘你好’
一个子类可以有多个直接父类,虽然具备了多个父类的特点,但是把被类的整体层次搞得十分复杂,尽量避免使用
class A:
def say(self):
print('AAA')
class B:
def say(self):
print('BBB')
class C(A,B)
pass
c = C()
print(C.mro()) #[, , , ]
class C(A,B)
print(C.mro())#[, , , ]
class A:
def say(self):
print('A',self)
class B(A):
def say(self):
super().say() #获得父类对象的定义
print('B',self)
B().say()
同一方法调用可能会产生不同的行为。类似于张三休息是睡觉,李四休息是打游戏。。。
a.break\b.break\c.break
注意以下两点:
1、多态是方法的多态,属性没有多态
2、多态的存在有两个必要条件,继承和方法重写
class Person:
def thewayofeat(self):
print('吃饭')
class Chinese(Person):
def thewayofeat(self):
print('用筷子')
class English(Person):
def thewayofeat(self):
print('用刀叉')
class India(Person):
def thewayofeat(self):
print('用手')
def manEat(m):
if isinstance(m,Person):
m.thewayofeat() #多态
else:
print('输入错误')
manEat(chinese())
python的运算符实际上是通过调用对象的特殊方法实现的。比如:
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)
变量的赋值:只是形成两个变量,实质还是指向同一个对象
浅拷贝:源对象拷贝,子对象不拷贝
深拷贝:源对象子对象都拷贝
‘is----a’关系使用继承(狗是动物)
‘has----a’关系使用组合(手机有cpu)
都是实现了代码的复用
class MobilePhone:
def __init__(self,cpu,screen):
self.cpu = cpu
self.screen = screen
class CPU:
def calculate(self):
print("计算")
class Screen:
def show(self):
print("显示好看的图片")
c = CPU()
s = Screen()
m = MobilePhone(c,s)
m.cpu.calculate() #通过组合,我们也能调用cpu 对象的方法。相当于手机对象间接拥有了“cpu 的方法”
m.screen.show()
设计模式是面向对象语言特有内容,是面临某一类问题是的固定做法。
工厂模式实现了创建者和调用者的分离,使用专门的工厂类将选择实现类、创建对象惊醒统一的管理和控制
class CarFactory:
def create_car(self,brand)
if brand == '奔驰'
return Benz()
elif brand == '宝马'
return BMW()
elif brand == '比亚迪'
return BYD()
else:
print('没有这个品牌')
class Benz:
pass
class BYD:
pass
class BMW:
pass
factory = CarFactory()
c1 = factory.creat_car('奔驰')
单例模式的核心作用是确保一个类只有一个实例,比关切提供一个访问该实例的全局访问点。
单例模式只生成一个实例对象,减少了对系统资源的开销。当一个对象的产生需要比较多的资源,可以产生一个单例对象,永久驻留在内存中,从而极大地降低开销。
class Single:
__obj = None
__init_flag = Ture #防止初始化两次
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")
print(a)
b = MySingleton("bb")
print(b)
返回结果:
init…
<main.MySingleton object at 0x01E15610>
<main.MySingleton object at 0x01E15610>