python入门知识(八):装饰器+面对对象的三个特征+组合+设计模式

一、方法的重载

python中没有方法的重载。在其他语言中,可以定义多个重名的方法,只要保证方法签名唯一即可。方法签名包含3个部分:方法名、参数数量、参数类型。而在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()   #不带参数,将会报错

二、方法的动态性

python是动态语言,我们可以动态的为类添加新的方法,或者动态的修改类已有的方法。具体例子如下:

class Person:
	def work(self):
		print("努力!")

def play_game(s):
	print("{0}在玩游戏".format(s))
	
Person.play=play_game  #为类添加新方法
p=Person()
p.work()
p.play()    

三、私有属性

 私有属性和私有方法,能够实现对象的封装,让外人不可随意查看。
 就像电脑一样,只需要会用,不需要知道内部的工作原理。
  • 注:方法本质上也是属性,只不过是通过()执行而已。
  • 要点:
    ①两个下划线开头的属性是私有属性:__私有属性名;其他的命名方法为公共属性;
    ②类内部可以直接访问私有属性(方法):类名.__私有属性名
    ③类外部不能直接访问私有属性(方法),但可以通过“对象名._类名__私有属性(方法)名”访问私有属性(方法)
class Employee:
	__company='百战'    #类的私有属性
	def __init__(self,name,age):
		self.name=name
		self.__age=age   #实例的私有属性

	def __work(self):    #私有方法
		print("{0} ,please work hard!".format(self.__age))  #在类内部,可以随意调用私有属性
		print(Employee.__company)    #类的私有属性的调用方法
	
e=Employee("何旯",18)
print(e._Employee__age)   #私有属性的调用方法
e._Employee__work()       #私有方法的调用方法
print(e._Employee__company)    #打印类的私有属性
print(dir(e))             #打印类可以调用的所有属性和方法

四、@property装饰器

(一)使用装饰器调用方法

  • 含义:@property可以将一个方法的调用方式变成“属性调用”
  • 使用方法:在方法的前一行,写上@property
  • 优点:调用方法时,不需要在后面加()了,像调用属性一样:对象名.方法名
class Empolyee:
	def salary(self):
		return 10000
#传统调用方式
emp1=Employee()  #创建对象
print(emp1.salary())   #将会打印10000

#@property调用
class Empolyee:
	@property
	def salary(self):
		return 10000
emp1=Employee()  #创建对象
print(emp1.salary)    #像调用属性一样,调用方法,但emp1.salary无法更改

(二)使用get和set修改属性

#使用get和set方法修改属性
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 10000<salary<50000:
			self.__salary=salary   #修改私有属性
		else:
			print("输入错误!")
			
emp1=Employee('高',30000)
print(emp1.get_salary())  #打印30000

emp1.set_salary(-20000)
print(emp1.get_salary())  #打印"录入错误!"

emp1.set_salary(40000)
print(emp1.get_salary())  #打印40000  

(三)使用@property和set修改属性

#使用@property和set方法修改属性
class Employee:
	def __init__(self,name,salary):
		self.__name=name
		self.__salary=salary
		
	@property
	def salary(self):        #对原来的get方法进行了简化
		return self.__salary
		
	def set_salary(self,salary):
		if 10000<salary<50000:
			self.__salary=salary
		else:
			print("输入错误!")
			
emp1=Employee('高',30000)
print(emp1.salary)  #使用装饰器后,调用方法时不需要加括号

emp1.set_salary(-20000)
print(emp1.salary)  #打印"录入错误!"

emp1.set_salary(40000)
print(emp1.salary)  #打印40000  
#可以看到使用@property装饰器,可以将get方法简化,可以直接将方法当作属性使用

五、面向对象的三大特征说明(封装、继承和多态)

python是面向对象语言。面向对象语言都有三大特性:封装(隐藏)、继承和多态。
  1. 封装(隐藏)
  • 含义:隐藏对象的属性和实现细节,只对外暴露“相关调用方法”。
  • 实现方式:私有属性、私有方法
  1. 继承
  • 继承可以让子类具有父类的特性,提高了代码的重用性
  • 原有父类设计不变的情况下,子类可以增加新的功能,或者改进已有算法
  1. 多态
  • 含义:由于对象不同,同一个方法的调用会产生不同的行为
  • 例子:中国人用筷子吃饭,美国人用刀叉吃饭等

(一)继承

已有的类:父类
新的类:子类(派生类)

1. 成员继承

  • 语法格式:class 子类类名(父类1[,父类2,…]):类体
  • 如果没有指定父类,则默认父类为object类。object类中定义了一些所有类共有的默认实现,比如__new__()
  • 定义子类时,必须在其构造函数中调用父类的构造函数。
#定义父类
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)   #继承。这里不调用也不出错,但是如果不显式地调用父类初始化方法,解释器本身也不会去调用,就无法使用name,age
		Student.score =score
		
#Student->Person->object
stu1=Student("高",18,80)
print(stu1.name)  #将会打印出“高”
print(stu1.age)    #不会打印,因为age是私有属性
print(stu1.__Person__age)    #通过print(dir(stu1)),可以看到打印age的方法。此处将会打印出18
stu1.say_age()  #将会打印出不知道

2.方法的重写

#定义父类
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("我的名字为:",self.name)
		
#定义子类
class Student(Person):
	def __init__(self,name,age,score):
		Person.__init__(self,name,age)    
		Student.score =score
	
stu1=Student("高",18,80)
stu1.say_age()   #子类继承了父类的方法
stu1.say_introduce()

#重写父类的方法
class Student(Person):
	def __init__(self,name,age,score):
		Person.__init__(self,name,age)    
		Student.score =score

	def say_introduce(self):    #由于python有方法的重载特性,直接在子类中定义一个重名方法,python将会调用子类的方法
		print("报告老师,我的名字是:{0}".format(self.name))

stu1.say_introduce()   #这时程序将会调用子类的方法

3.object根类

  • object根类:object根类是所有类的父类。学习object类的结构,对深入学习python有好处。
  • 使用dir()可以查看类的属性

4.重写__str__()方法

  • object有一个__str__()方法,用于返回对于“对象的描述”
  • str()方法需要搭配print
  • str()方法可以重写
class Student:
	def __init__(self,name):
		self.name=name
		
p=Student("gao")
print(p)    #这里会打印出关于对象p的地址

#测试重写object的__str__()方法
class Student:
	def __init__(self,name):
		self.name=name
	def __str__(self):
		return "名字是{0}".format(self.name)
p=Student("gao")
print(p)  #使用str()方法改写后,这里会打印出“名字是gao”

5.多重继承

python支持多重继承,一个子类可以有多个父类,但是这样会被“类的整体层次”搞得异常复杂,应尽量避免使用。

class A:
	def aa(self):
		print("aa")

class B:
	def bb(self):
		print("bb")

class C(A,B):
	def cc(self):
		print("cc")
c=C()
c.cc()   #将会打印出cc
c.aa()   #将会打印出aa
c.bb()   #将会打印出bb

6.mro()

  • mro():通过类的方法mro()或者类的属性__mro__可以输出类的继承结构,或者说层次结构。

  • 例子如下:

class A:pass
class B(A):pass
class C(B):pass

print(C.miro())

输出结果为:
在这里插入图片描述

  • 由于python支持多重继承,所以父类中如果有相同名字的方法,在子类没有指定父类名时,会按照“从左到右”的顺序搜索。
class A:
	def aa(self):
		print("aa")
	def say(self):
		print("say AAA!")
		
class B:
	def bb(self):
		print("bb")
	def say(self):
		print("say BBB!")
		
class C(A,B):   
	def cc(self):
		print("cc")
		
c=C()
print(C.mro())  #打印类的层次结构
c.say()  #A在B前,先调用A,再调用B

7.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()  
#将会输出A:<__main__.B object at 0x021A6610>和B:<__main__.B object at 0x021A6610>

#-------------或者是使用以下方式获得父类的方法-----------
class B(A):
	def say(self):
		super().say()  #使用super()替代父类,以获取父类方法
		print("B:",self)
B().say()  #输出的效果如上

(二)同一方法调用多态

  • 多态是指同一方法调用,由于对象不同可能产生不同行为。
  • 注:
    1.多态是方法的多态,属性没有多态
    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):   #多态。如果传进来的是Man的子类,则根据对象的不同调用不同的方法!
		m.eat()
	else:
		print("不能吃饭")

manEat(Chinese())
manEat(English())

六、特殊方法和运算符重载

python的运算符实际上是通过调用对象的特殊方法实现的。比如:

a=20
b=30
c=a+b
d=a.__add_(b)  #加号+的实质是调用了__add__()方法
print('c=',c)  
print('d=',d)  #两者的运算结果相同

每个运算符实际上都对应了相应的方法,统计如下:
在这里插入图片描述
这解释了为什么字符串也可以进行±*等等操作

常见的特殊方法统计如下:
在这里插入图片描述
在这里插入图片描述

  • 运算符重载(实质是方法的重载)
class Person:
	def __init__(self,name):
		self.name=name
	def __add__(self,other):
		if isinstance(other,Person):  #判断other是不是Person类型
			return "{0}--{1}".format(self.name,other.name)
		else:
			return "不是同类对象,不能相加"
	def __mul__(self,other):
		if isintance(other,int):      #判断other是不是int类型
			return self.name*other
		else:
			return "传入的数据不是整数类型,不能相乘"
p1=Person("GA")
p2=Person("ca")
f=p1+p2
print(f)
print(f*3)

七、特殊属性

  • obj.dict:获得类的属性字典
class c:
	def __init__(self,age):
		self.age=age
		
g=c(20)  
print(g.__dict__)  #将会输出{'age':20}
  • obj.class:获得对象属于的类
class a:
	def say(self):
		print("不错")
		
class c(a):
	def __init__(self,age):
		self.age=age
		
g=c(20)  
print(g.__class__)  #将会输出类为c的地址
  • obj.bases:当有多个父类时,将对象的父类的地址放在元组中
class a:
	def say(self):
		print("不错")
		
class b:
	def say(self):
		print("很好")
		
class c(a,b):
	def __init__(self,age):
		self.age=age
g=c(20)  
print(g.__bases__)  #将会输出a,b的地址组成的元组
  • obj.base:当只有单个父类时,输出对象的父类的地址
  • obj.mro:类层次结构
  • obj.subclass():子类列表
class a:
	def say(self):
		print("不错")
		
class c(a):
	def __init__(self,age):
		self.age=age
g=c(20)  
print(a.__subclass__())  #已知父类,输出子类。此处将会输出c的地址

八、对象的浅拷贝和深拷贝

  • 变量赋值:形成两个变量(可以理解为标签),实质指向同一个对象(那么两个变量的地址仍然不变)
  • 浅拷贝:只拷贝了源对象,没有拷贝儿子和孙子,拷贝对象和源对象仍然指向同一个儿子和孙子。因此源对象和拷贝对象的地址不同,但是子对象的地址相同
  • 深拷贝:不仅拷贝了源对象,还拷贝了儿子和孙子。因此,源对象和拷贝对象的地址不同,其子对象的地址也不同

九、组合

  • 继承:是“is a”的关系,如狗是动物
  • 组合:是“has a”的关系,如手机拥有cpu
#继承
class A:
	def say_a1(self):
		print("a1")
class B(a):
	pass

b=B()
b.say_a1   #类B继承了类A的方法

#组合
class C:
	def __init__(self,a):
		self.a=a

class D:
	def say_d1(self,a):
		print("我是{0}".format(a)) 

c=C(D())   #将类D对类C进行组合
c.D.say_d1()  #可以通过对象c调用对象D的方法

十、设计模式

(一)工厂模式的实现

  • 含义:设计模式是面向对象语言特有的内容,是我们在面临某一类问题时候的固定做法。比较流行的是GOF(Goup Of Four)模式。
  • 工厂模式:能够实现创建者和调用者的分离,使用专门的工厂类将选择实现类、创建对象进行统一的管理和控制
    例子如下:
#测试工厂模式
class CarFactory:
	def create_car(self,brand):
		if brand =="奔驰":
			return Benz()
		elif brand=="宝马":
			return BNW()
		elif brand=="比亚迪":
			return BYD()
		else:
			return "未知品牌,无法创建"
class Benz:
	pass

class BNW:
	pass

class BYD:
	pass

factory=CarFactory()
c1=factory.create_car("奔驰")
c2=factory.create_car("比亚迪")

(二)单例模式的实现

  • 核心作用:确保一个类只有一个实例,并且提供一个访问该实例的全局访问点。
  • 优点:当一个对象的对象的产生需要比较多的资源,如读取配置文件、产生其他依赖对象时,可以产生一个“单例对象”,然后永久驻留于内存中,从而极大地降低开销。
class MySingleton:   #单例对象需要重写new和init方法
	__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==True:
			print("init...")
			self.name=name
			MySingleton.__init__flag==False
		
a=MySingleton("aa")  
b=MySingleton("bb")   #只会输出一次init...
print(a)
print(b)    #a和b的地址都是一样的
#测试工厂模式的单例模式
class CarFactory:
	__new__=None
	__init__flag=True

	def __new__(cls,*args,**kwargs):
		if cls.__obj==NONE:        #当类属性还没有建立时,创建一个类对象        
			cls.__obj=object.__new__(cls)
		return cls.__obj
		
	def __init__(self):
		if CarFactory.__init__flag==True:
			print("init CarFactory...")
			CarFactory.__init__flag==False

		def create_car(self,brand):
		if brand =="奔驰":
			return Benz()
		elif brand=="宝马":
			return BNW()
		elif brand=="比亚迪":
			return BYD()
		else:
			return "未知品牌,无法创建"
	
class Benz:
	pass

class BNW:
	pass

class BYD:
	pass

factory1=CarFactory()
c1=factory1.create_car("奔驰")
c2=factory1.create_car("比亚迪")
factory2=CarFactory()
print(factory1)
print(factory2)  #factory1和factory2的地址是一样的。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值