面向对象
- 本质:将特定的数据与特定的功能绑定到一起 将来只能彼此相互使用
- 对象其实就是一个容器 里面将数据和功能绑定到一起
使用场景一:
eg:游戏人物……
只负责创造出该人物具备的功能 至于后续战绩如何无人知晓 不是面向对象关心的内容
区别
- 面向过程编程相当于让你给出一个问题的具体解决方案
- 面向对象编程相当于让你创造出一些事物之后不用你管
对象与类的概念
对象:数据与功能的接合体
类:多个对象相同的数据和功能的接合体
'''
类比学习法: 一个人 可以看成对象
多个人 人类
'''
类:主要用于记录多个对象相同的数据和功能
对象:则用于记录多个对象不同的数据和功能
PS:在面向对象编程中 类主要是为了节省代码 对象才是核心
对象与类的创建
在编程世界里先有类才有对象
创建类的完整语法
#学生类
class person:
1.class是定义类的关键字
2.person是类的名字
类名的命名跟变量名一致 并且推荐首字母大写(为了更好的区分)
3.类体代码
公共的数据/公共的方法
4.通过类名加括号可以实例化一个对象
5.我们习惯将类或者对象聚点符后面的东西称为属性或者方法
对象独有的数据
class Student:
school = "清华大学"#属性
def choice_course(self):#对象具有的方法
print("正在上课")
obj1 = Student()#实例化出 一个对象
'''
类体最常见的是变量的定义和函数的定义,但其实类体可以包含任意Python代码,类体的代码在类定义阶段就会执行,因而会产生新的名称空间用来存放类中定义的名字,可以打印
Student.__dict__
来查看类这个容器内盛放的东西
'''
class Student:
school='清华大学'
#__init__该方法会在对象产生之后自动执行,专门为对象进行初始化操作,可以有任意代码,但一定不能返回非None的值
def __init__(self,name,sex,age):
self.name=name
self.sex=sex
self.age=age
def choose(self):
print('%s is choosing a course' %self.name)
#实例化出一个对象
stu1 = student('jason','male','eighteen')
print(stu1.__dict__)
对象独有的方法/功能
class person:
h_type = "人类" #多个对象公共的数据
def __init__(self,name):#让对像拥有独有的数据
self.name = name
def eat(self):#对象独有方法,只针对对象
print("正在干饭")
动静态方法
专门针对在类体代码中编写的代码
1.绑定给对象的方法
直接在类体代码中编写即可
对象调用直接将对象当做第一个参数传入
类调用则有几个形参就传几个形参
class Student:
school = "清华大学"
def run(self): #绑定给对象的方法self用于接收对象
print("互动课堂",self)
@classmethod
def eat(cls): #绑定给类的方法cls用于接收类
print("清华讲堂",cls)
@staticmethod #静态方法
def sleep(a,b):#无论谁来调都必须按照不同函数的方式调用
print("现代化设备")
stu1 = Student()
#调用绑定给类的方法
student.eat()#绑定给类的方法类调用自动将类当做第一个对象传入
stu1.eat() #对象调用类方法会将产生该对象的类当成第一个参数传入
#类和对象调用静态方法都必须传入相对应的参数没有默认参数
Student.sleep(1,3)
stu1.sleep(1,4)
面向对象三大特性
'''
面向对象的三大特性
封装、继承、多态
'''
1.继承的含义
表示类与类之间数据之间的关系
2.继承的目的
减少代码的编写
3.继承的操作
class Father:
money =999
def run(self):
print("继承财产")
#1.定义类名的时候在类名后加括号
#2.括号里面填写需要继承的类名
'''
我们将被继承的类称为:父类、基类、或超类;
进行继承的类称为:子类、派生类;
'''
class Son(Father1,Father2,Father3):
pass
print(son.money)
print(son.run())
4.继承的本质
抽象:将多个类共有的数据或功能抽取出来行程一个基类
继承:从上往下继承父类里面的数据和资源
'''
对象:数据和功能的接合体
类:多个对象,相同的数据和功能的接合体
父类:多个类,相同的数据和功能的结合体
'''
名字的查找顺序
1、不继承的情况下名字的查找顺序
先从对象自身查找 没有的话 再去产生该对象的类中查找
2、单继承的情况下名字的查找顺序
先从对象自身查找 然后是产生该对象的类 然后是一个个父类
3、多继承的情况下名字的查找顺序
- 1、不继承的情况下名字的查找顺序
class Student:
school = '清华大学'
def choice_course(self):
print("正在上课")
stu1 = student()
print(stu1.school)
stu1.school = '北京大学' #在自己命名空间中产生了新的school,不会更改类中的数据
print(stu1.school)#北京大学
print(Student.school)#清华大学
-
2、单继承的情况下名字的查找顺序
主要涉及对象的查找名字 那么几乎是
对象本身> 类 >父类
class A: name = 'from A' class B(A): name = 'feom B' class C(B): name ='from C' calss myclass(C): name = 'from myclass' obj = myclass() print(obj.name)
-
3、多继承的情况下名字的查找顺序
- 非菱形继承> 最后不会归总到一个类上> 深度优先
- 菱形继承> 最后都归总到一个类上> 广度优先
- 通过(类.mro)方法查看该类产生的对象名字的查找顺序
class A:
name = 'from A'
class B:
name = 'from B'
class C:
name = 'from C'
class MyClass(A,B,C):#查找顺序A>B>C
name = 'from MyClass'
obj = MyClass()
print(obj.name)
经典类与新式类(object)
金典类
不继承objict或其子类的类(什么都不继承)
新式类
继承了object或其子类的类
'''
在python3中所有的类都默认继承object类
在python2中不写object就是经典类
以后再定义类的时候如果没有要继承的类就继承object 可以更好的兼容python2
'''
派生方法
- 子类中定义了与父类一模一样的方法并且做了扩充就叫派生
class Person(object):
def __init__(self,name,age)
self.name = name
self.age = age
class Teacher(person):
def __init__(self,name,age,level):#子类需要的属性父类不满足时
'''
# person.__init__(self,name,age) 先调用父类的方法
# self.level = level #再自己补充一些
'''
super().__init__(name,age,gender) #super专门用于子类调用父类的方法
self.level = level #再自己补充一些
class Student(Person):
pass
派生实战演练
问题:json可以序列化的类型只有基本类型
#解决方式1:手动将不符合要求的数据转化成符合要求的
import datetimee
ipmort json
d = {"t1":str(datetime.datetime.today()),
"t2":str(datetime.date.today())
}# 获取当前时间
res = json.dump(d)#序列化字典
print(res)
#解决方式2:利用派生方法
d = {"t1":str(datetime.datetime.today()),
"t2":str(datetime.date.today())
}# 获取当前时间
res = json.dump(d)#序列化字典
print(res)
三大特性之封装
-
在类的定义阶段中使用‘__’开头的属性默认都是隐藏的属性 后续类和对象都无法访问
-
在python中不会真正限制代码的访问 隐藏的代码要访问需要做相应的变形
__变量名 会变成:_类名__变量名
封装其实是将数据或者功能隐藏起来(包起来 装起来)
隐藏的目的不是让用户无法使用 而是给这些隐藏的数据开设特定的窗口 让用户使用接口才可以去使用 我们在接口中添加一系列额外的操作
class Person:
d_type = '人类'
__school = '清华大学'
__name = 'jason'
__age = eight
def get_info(self):
return f"{self.__school},{self.__name}"
def eat(self):
print('立德立言')
obj1 = person()
print(obj1.get_info())#通过定义的类方法访问信息
property伪装属性
可以简单的理解为 将方法伪装成数据
obj.name #数据只需要.数据名就可以调用
obj.func() #方法需要加括号才能调用
伪装之后可以将func方法伪装成数据 obj.func
#计算人体的MBI指数
class person:
def __init__(self,name,weight,height)
self.name = name
self.weight = weight
self.height = height
@property
def MBI(self):
return self.weight/(self.height**2)
P1 = Person("jason",88,1.85)
res = P1.MBI()
print(P1.MBI)#不加括号也可以直接调用
面向对象之反射
- 反射:通过字符串来操作对象的数据或方法
- 反射就四个方法:hasattr、getattr、setattr、delattr
什么时候使用反射:只要在需求中看到了、‘关键字’、‘对象’、‘字符串’就用反射的知识
hasattr():判断对象是否含有某个字符串对应的属性
getattr():获取对象字符串对应的属性
setattr():根据字符串给对象设置属性
delattr():根据字符串给对象删除属性
class Student(object):
school = '清华大学'
def choice_course(self):
print("选课")
stu = Student()
#需求:判断用户提供的名字在不在对象可以使用的范围内
#方式1:利用异常捕获
try:
if stu.school:
print(f"True{stu.school}")
except Exception:
print("没有改属性")
#方式2:获取用户输入的名字 然后判断该名字有没有
target_name = input().strip()#用户输入的是字符串
'''上面的异常捕获不好实现 需要用反射'''
print(hasattr(stu,target_name))
getattr(stu,target_name)
setattr(stu,'gender','male')#用户自己输入设置属性
delattr(stu,'age')#用户自己输入需要删除的属性
面向对象魔法方法
- 魔法方法其实就是类中定义的双下方法 之所以叫魔法方法是因为这些方法达到条件后自动触发
- eg:“–init–“方法在给对象设置独有数据的时候自动触发(实例化)
class Myclass(object):
def __init__(self):#实例化对象的时候自动触发
print("__init__方法")
def __str__(self):#当对象被执行打印的时候自动触发 该方法必须返回一个字符串
print("__str__方法")
return "对象:%s"%self
def __call__(self,*args,**kwargs):#对象加括号自动调动该功能
print("__call__方法")
print(args)
print(kwargs)
def __getattr__(self,item):#当对象获取一个不存在的属性名自调用该方法返回什么 对象 获取不存在的属性名就会得到什么 型参item 就是 想要获取的不存在的属性名 当类中也有 __getattribute__时不走此代码
print("__getattr__方法")
return 123
def __setattr__(self,key,value):#对象添加属性值得时候自动触发 对象.属性名 = "属性值"
print("__setattr__方法")
print(key)
print(value)
def __del__(self):#对象在被删除的时候自动触发
print("__del__方法")
def __getattribute__(self,item):#对象获取属性的时候触发 无论属性存不存在 当 类中也有__getattr__时不走
print("__grtattribute__方法")
return super(MYclass,self).__getattribut__(item)
def __enter__(self):#对象被with语法执行时自动触发 该方法返回什么 as关键字后变量名就得到什么
print("__entrt__方法")
return 123
def __exit__(self,exc_type,exc_val,exc_tb):#对象被with语法执行并运行完with子代码后 自动触发
print("__exit__方法")
obj = Myclass()
obj(1,2,name='jason',age = '18')
print(obj.age)#获取对象不存在的属性名age
with obj as f:
print(f)
元类简介
class Mycalss(object):
psss
obj = Myclass()
print(type(obj))#查看产生对象obj的类:<class '__main__.Myclass'>
print(type(Myclass))#查看产生对象Myclass的类:<class 'type'>
'''
通过推导我们得出 自定义的类都是有 type类得出的 产生类的类称为 “元类”
'''
产生类的两种方式
1.class 关键字
class Myclass:
pass
2.利用元类type
type(类名,类的父类,类的名称空间)
原创文章,作者:ItWorker,如若转载,请注明出处:https://blog.ytso.com/283022.html