本周内容整理

本周内容概览

  • 面向对象
    • 面向对象简介
    • 类与对象
      • 类与对象概念
      • 类与对象创建
      • 对象独有的数据与方法
      • 动静态方法
    • 面向对象三大特性
      • 三大特性之继承
        • 继承的本质
        • 名字的查找顺序
        • 经典类与新式类
        • 派生方法
      • 三大特性之封装
        • property伪装属性
      • 三大特性之多态
    • 面向对象之反射
    • 面向对象魔法方法
    • 元类
      • 产生类的两种方式
      • 元类基本使用
      • 双下new方法

面向对象

面向对象简介

  • 面向对象是一种解决问题的思想,与之相对的就是面向过程编程,之前的代码编写中,一直使用的都是面向过程编程,通过按照流程一步步得到结果,而面向对象则是将数据和功能绑定在一起,创造一个对象,使用一个个对象去实现功能
    两种编程思想没有优劣之分,只是使用场景不同,甚至更多时候是两者结合使用

类与对象

类与对象概念

对象:数据与功能的结合体
类:多个对象相同的数据和功能的结合体

类与对象创建
class Myclass:
	pass
1.class是创建类的关键字
2.Myclass是类名,类名的命名和变量名一致,并且推荐首字母大写(更有识别度)
3.pass是类体代码公共的数据和方法
类体代码在类定义时就会执行

obj = Myclass()
使用类名加括号即可产生一个对象

查看名称空间的方法:/对象名.__dict__
对象独有的数据和方法
1.对象的独有数据:
使用__init__方法在实例化一个对象时添加数据值
class Myclass:
	def __init__(self, name, age):
		self.name = name
		self.age = age
		
obj = Myclass('jason', 18)
定义一个方法会默认将对象当做第一个值传入,一般使用self接收,后边的参数需要在实例化对象时传入
print(obj.name)  # jason
使用对象点名字的方式获取对应的数据值

2.对象的独有方法:
对象真正的独有方法实际上没有办法实现
如果定义在全局中则不是独有的
如果在定义在类中则是公共的
python解释器针对上述问题添加了一个特性
定义在类中的函数默认绑定给对象,相当于就是对象独有的方法
class MyClass:
    def __init__(self, name):
        self.name = name

    def func1(self):
        print(self.name)


obj1 = MyClass('jason')
obj2 = MyClass('kevin')
obj1.func1()  # jason
obj2.func1()  # kevin
使用对象点名字加括号的方式调用方法
动静态方法
在类中定义的方法一共有三种
1.绑定给对象的方法(默认)
2.绑定给类的方法
3.静态方法

class MyClass:
	def func1(self):  # 实例方法(绑定给对象的方法)
		print(self)

	@classmethod  #  类方法(绑定给类的方法)
	def func2(cls):
		print(cls)

	@staticmethod  # 静态方法(就是普通函数)
	def func3(a, b):
		print(a, b)

obj = MyClass()

MyClass.func1(obj)  # 类使用实例方法需要传一个对象
obj.func1()  # 对象使用实例方法会自动将自身传入

MyClass.func2()  # 类使用类方法会自动将自身传入
obj.func2()  # 对象使用类方法会自动将实例化自身的类传入

MyClass.func3(1, 2)  # 需要多少参数就传多少
obj.func3(1, 2)  # 需要多少参数就传多少

面向对象三大特性之继承

继承就是将被继承类的属性和方法全部获取
继承的目的是为了节省代码的编写
在定义类的时候在类名后加括号填写想要继承的父类
可以继承一个或多个,使用逗号隔开

继承的本质

抽象:将多个类共同的数据或功能提取出来抽象成一个基类
继承:从上往下获取各个基类中的数据与功能

名字的查找顺序

不继承的情况下:先从对象自身开始查找,没有在去产生该对象的类查找,没有的话报错
单继承的情况下:继承一个父类,现充对象自身查找,再去对象的类查找,然后是一个个父类
多继承的情况下:继承多个父类,有两种情况

  1. 非菱形继承,多个父类最后不会汇总到一个父类,采用深度优先,第一个父类层层向上,最后都没有的话再去第二个父类里查找
  2. 菱形继承,多个父类最后都是继承的同一个父类,采用广度优先,第一个父类层层向上,但不会走到汇总的那个类,汇总的那个类的所有子类都没有才会在其中查询
    使用类点mro()方法查看查找顺序
经典类与新式类

经典类是不继承object或其子类的类
新式类是继承了object或其子类的类
在python3中,默认创建类都继承object,所以python3中没有经典类
在python2中,可以创建经典类和新式类
由于经典类没有核心的功能,所以在python3直接砍掉了
但是在定义类的时候,如果没有想要继承的父类,还是推荐以下写法
class MyClass(object):
pass
虽然和不写是相同的,但是这段代码放在python2中也同样能运行

派生方法

在子类中重写了父类的方法并且扩展了该方法

class MyJsonEncode(json.JSONEncoder):
	def default(self, o):
		if isinstance(o, datetime.datetime)
			return o.strftime(%Y-%m-%d %H:%M:%S)
		return super().default(o)
"""重写了JSONEncoder模块,使其遇到datetime类型数据将其格式化为字符串返回"""

面向对象三大特性之封装

封装就是将数据或方法隐藏起来,然后开设一个特定的接口,让用户只能根据这个接口才能使用到封装过的数据或方法
在类的定义阶段,使用双下划线开头的名字,就是隐藏的名字,类的外边无法直接获取,子类也不会继承隐藏属性
但python不会真正的限制任何代码,可以使用__dict__可以看到隐藏的名字只是做了个变形,在名字前加上_类名,不过这样也没有了隐藏的意义

property伪装属性

将方法伪装成数据,让方法不加括号调用(方法不能有参数)

class MyClass(object):
    def __init__(self, name):
        self.__NAME = name

    @property
    def name(self):
        return self.__NAME
 	
 	@name.setter
 	def name(self, value):
 		if not isinstance(value, str):
 			raise TypeError('类型错误')
 		self.__NAME = value

	@name.deleter
	def name(self):
		raise PermissionError('无法删除')

obj = MyClass('jason')
print(obj.name)
obj.name = 'kevin'
del obj.name

"""
使用@property语法糖伪装方法
使用@伪装方法名.setter添加伪装函数的修改功能
使用@伪装方法名.deleter添加伪装函数的删除功能
"""

面向对象三大特性之多态

多态:一种事物的多种形态
一种事物有多种形态,但是多种形态的相同功能应该使用相同的名字
也可以使用abc模块设置一个抽象类,类中装饰方法使其继承当前类的子类都必须重写此方法

import abc

class MyClass(metaclass=abc.ABCMeta):  
	@abc.abstractmethod  # 使用装饰器限制子类必须要有一个func的方法
	def func(self):
		pass

鸭子类型:只要你长得像鸭子,走路像鸭子,说话像鸭子,那么你就是鸭子

面向对象之反射

反射:通过字符串来操作对象的属性或方法
反射主要使用四个方法:

  1. hasattr(): 根据字符串判断对象是否存在指定的属性或方法
  2. getattr(): 根据字符串获取对象内指定的属性或方法
  3. setattr(): 根据字符串设置对象的属性
  4. delattr(): 根据字符串删除对象的属性
class MyClass(object):
    def __init__(self, name):
        self.name = name

    def func(self):
        print('func')


obj = MyClass('xm')
print(hasattr(obj, 'name'))  # True
print(hasattr(obj, 'func'))  # True
print(hasattr(obj, 'xxxx'))  # False

print(getattr(obj, 'name'))  # xm
getattr(obj, 'func')()  # func

setattr(obj, 'name', 'jason')
setattr(obj, 'age', 18)
print(obj.__dict__)  # {'name': 'jason', 'age': 18}

delattr(obj, 'name')
print(obj.__dict__)  # {'age': 18}

面向对象魔法方法

魔法方法就是在类中定义的双下方法,魔法方法会在特定条件下自动触发

"""常用的魔法方法"""
class MyClass(object):
	def __init__(self):  # 实例化对象时自动触发
		pass

	def __str__(self):  # 在对象被打印是自动触发,需要返回一个字符串以供打印
		return ''

	def __call__(self,*args, **kwargs):  # 对象被加括号调用时自动触发
		pass

	def __getattr__(self, item):  # 获取一个对象中不存在的数据时自动触发,返回值就是外界获取的值
		return 'item'
	
	def __setattr__(self, key, value):  # 操作对象的属性时自动触发	super().__setattr__(key, value)

	def __del__(self):  # 对象被主动或被动删除时自动触发
		pass

	def __getattribute__(self, item):  # 对象获取属性时自动触发,无论属性是否存在,此方法相比__getattr__优先级更高
		return super().__getattribute__(item)

	def __enter__(self):  # 对象被with语法执行时自动触发,返回值会被as后的变量名接收
		pass
	
	def __exit__(self, exc_type, exc_val, exc_tb):  # 对象被with语法执行结束时自动触发
		pass
		

元类

使用type可以查看对象的所属类是谁,使用type查询类的所属类可以发现是被type创建的
这种创建类的类就被称为元类

产生类的两种方式
  1. 使用class关键字创建类
  2. 使用元类
    type(类名, 父类, 名称空间)
元类基本使用
继承了type的类才可以称为元类
想要切换产生类的元类不能使用继承必须使用关键字metaclass声明
可以在元类中使用__init__控制类的创建,在元类中使用__call__控制对象的创建
class MyMetaClass(type):
	def __init__(self,what, bases=None, dict=None):
		if not what.istitle():  # 控制创建类不许第一个字母大写其他字母小写
			raise Exception('首字母必须大写')
		super().__init__(what, bases, dict)
	
	def __call__(self, *args, **kwargs):
		if args:  # 控制创建对象只能用关键字传参
			raise Exception('必须使用关键字传参')
		super().__call__(*args, **kwargs)

class MyClass(metaclass=MyMetaClass):
	pass
双下new方法

创建对象的步骤

  1. 创建一个空对象
  2. 触发__init__方法实例化对象
  3. 返回对象
    __new__方法的作用就是创建一个空对象
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值