面向对象

编程范式

面向对象指的是一种编程范式;

编程范式:可以理解为一种编程方式,编程规范,编程模式

  • 面向过程

面向过程编程:是一种以过程为核心的编程,主要是在解决一个问题的时候 , 将这个问题拆分成一个个小步骤完成并且拼接起来的就是面向过程。

  • 面向对象

面向对象编程(object oriented programming ,简称OOP):是一种以对象为核心的编程 , 面向对象在解决问题的时候是思考如何设计这个事情。

类和对象

  • 在代码里面实行一个对象是通过类进行产生的;

  • 类就相当于生活中的一个类别,一个比较抽象的概念。

  • 对象就是一个通过类产生的一个拥有属性以及行为的实体,是对应类里面的一个个体

  • <先有类 , 再有对象>

  1. 函数是一系列的指令,完成特定的功能。变量是描述事物特征的东西,姑且叫信息。
  2. 类就是将变量信息和函数指令结合到一起的东西。变量表达类的特征(属性),函数表示类的功能(方法)。
  3. 对象是类的特例。犹如动物和人的关系。

类的定义

python中如何定义一个函数

# 定义
def 函数名(形参):
函数体
# 调用
函数名(实参)
def func_1(name):
return f'{name}是个超人'
print(func_1('伤心超人'))

python中定义类的语法:

class 类名:
代码

类目的定义:使用驼峰式命名(大驼峰,每个单词的首字母大写)

定义类之后 , 执行代码 , 类里面的代码也会一起执行

定义再类中的变量称之为属性

class People:
'''
我是类文档
就相当于类的说明书
'''
# 类属性 (所有对象共有的)
height = 1.73
weight = 200
# 实例化类
xs = People()
print(xs.weight)
# print(People.__dict__)
mj = People()
# 创建对象独有的属性,如果属性存在,则是修改属性值的操作
# 对象名.属性名 = 属性值
mj.weight = 90
mj.weight = 85
print(mj.weight)
# 使用对象.__dict__得到的是对象的属性
print(mj.__dict__)
# 修改类属性
# 类名.属性名 = 属性值
People.weight = 170
print(xs.weight)
# 动态的增加类属性
People.age = 20
print(xs.age)

--init--

class Animal:
'''动物类'''
# 初始化方法
def __init__(self , name , age):
# 属性
self.age = age
self.name = name
cat = Animal('da' , 1)
print(cat.name)
print(cat.age)
dog = Animal('xi',1.5)
print(dog.name)

self

class Animal:
'''动物类'''
# 初始化方法
def __init__(self , name , age):
# 属性
self.age = age
self.name = name
def sleep(self):
print(f'{self.name}睡觉')
cat = Animal('da' , 1)
dog = Animal('xi',1.5)
dog.sleep()
# print(cat.name)
# print(cat.age)
# print(dog.name)

封装

面向对象的三大特性:封装、继承、多态

  • ​ 封装:把功能代码 , 数据封装到某一个地方,需要的时候进行调用 , 提过程序的安全性。即把属性以及方法放到类中 ,通过类对象的操作或者调用。

  • ​ 通过封装,可以将一些不想给用户看到的功能进行隐藏 , 用户只能访问公开的功能,可以提高数据的安全性 , 也对后期的维护降低成本。

  • ​ 封装的好处:便于分工 , 便于复用 , 可扩展性强。

class People:
'''人类'''
height = 1.73
weight = 200
# 初始化方法
def __init__(self , name , age , weight , job):
self.name = name
self.age = age
self.weight = weight
self.job = job
def eat(self):
print(f'{self.name}食べる')
self.weight += 2
def drink(self):
print(f'{self.name} 飲みましょう。')
self.weight += 0.5
def run(self):
print(f'{self.name} gogogo')
self.weight -= 0.5

属性查找

  • 在实例化属性中不同的对象 , 调用的属性不会产生影响互不干扰

  • 对象寻找对应的属性,先从自身的实例属性开始查找 , 如果没有再从类属性查找。

  • 不同的对象之间的实例属性是互不相通 , 都是独有的 , 两者无法相互访问

class Cat:
# 类属性
category = 'ねこ'
age = 2
# 初始化方法
def __init__(self , name , category):
# 实例属性
self.name = name
self.category = category
def sleep(self):
print(f'{self.name}睡觉')
mao1 = Cat('xiaopang' , '家猫')
mao1.age = 1
print(mao1.name)
print(mao1.category)
mao2 = Cat('dapang','流浪猫')
print(mao2.name)
print(mao2.age) # 2
print(mao2.category)

属性隐藏

在类中定义一些数据或者功能不希望被外部访问到以及操作的时候 , 可以将数据以及功能进行隐藏。

在Python中没有绝对的隐藏 , 是可以通过一些方法对其进行访问的。

在类中的三种隐藏方法:

  • 属性或者方法名前加上双下划线
  • 使用property()函数
  • @property 装饰的方法是获取属性值的方法 , 被装饰的方法的名字会被作为属性名 , 方法名尽量跟隐藏的属性名一致
    @属性名.setter 装饰的方法是设置属性值的方法
    @属性名.deleter 装饰的方法是删除属性值的方法

属性或者方法名前加上双下划线

双下划线开头的属性 , 是对象的隐藏属性,隐藏属性可以在类内部进行访问

class People:
def __init__(self , name , age):
self.name = name
self.__age = age # 将age属性进行隐藏
def __speak(self):
print(f'我今年{self.__age}')
hh = People('haha', 24)
# print(hh.name)
# 获取对象属性
# print(hh.__dict__)
# 对象名称._类名__属性名
print(hh._People__age)
hh._People__speak()

使用property()函数

property可以设置、获取 , 删除对象的某一个属性值 , 也可以限制用户对属性的设置与获取

# property 属性
# property(fget = None , fset = None , fdel = None , doc = None)
# fget = 是获取属性值的方法
# fset = 是设置属性值的方法
# fdel = 是删除属性值的方式
class People:
def __init__(self , name , age):
self.name = name
self.__age = age # 将age属性进行隐藏
def speak(self):
print(f'我今年{self.__age}')
def get_age(self):
print('===get=====')
return self.__age
def set_age(self , value):
print('===set=====')
self.__age = value
def del_age(self):
print('===del=====')
del self.__age
# 赋予对象属性权限 加上这句话,可以限制权限,而且对象进行操作很符合习惯
age = property(fget=get_age , fset=set_age , fdel=del_age)
p2 = People('小小怪', 26)
print(p2.name)
# 获取对象属性
print(p2.__dict__)
# 对象名称._类名__属性名
print(p2._People__age)
# ac._People__speak() # 'People' object has no attribute '_People__speak'
# 因为本来就没有__speak,如果没有property,speak可以直接调用
print(p2.age)
p2.age = 22
print(p2.age)
del p2.age # 如果没有property,删除就得是p2.del_age,和习惯不同
print(p2.__dict__)

装饰器

class Student:
def __init__(self):
self.__name = '开心超人'
@property # grade = property(grade) 不清楚具体咋实现的,但是结果是 将函数的返回值 __name 赋给grade,也就是下变函数的名字,所以说为了让外边调用方便还是不要瞎起名
def grade(self):
return self.__name
@grade.setter
def grade(self , value):
self.__name = value
@grade.deleter
def grade(self):
del self.__name
p5 = Student()
print(p5.grade)
p5.grade = "花心超人"
print(p5.grade)
del p5.grade
# print(p5.grade)

继承

  1. 在python中是在多个类中的一种所属关系
  2. 被继承的类称为父类
  3. 接收的类称为子类
  4. 在继承中子类是默认继承父类中的属性以及方法
  5. 继承可以解决类与类之间的代码冗余。
  6. 在python3中都会默认继承object类 , 即object是python中所有类的父类(基类 , 超类)。

单继承

一个子类继承一个父类 , 子类默认继承父类中的所有方法 , 属性

class Father:
def __init__(self , name):
self.name = name
self.clothes = '👚'
self.job = '工作'
def eat(self):
print('吃')
return '吃东西'
class Son(Father):
pass
p3 = Son('校长')
print(p3.name)
print(p3.clothes)
print(p3.job)
print(p3.eat())

重写

在子类中重新定义父类的方法 , 子类在实例化之后会默认的访问自身的方法。

class Father:
def __init__(self , age , name='孙悟空'):
self.name = name
self.age = age
def eat(self):
print(f'{self.name}偷吃亚奇罗贝 的 <・)))><<')
def money(self):
print('1万')
class GrilOfSon(Father):
def eat(self):
print(f'{self.name}在优雅的吃饭')
# super()
def money(self):
print('5千')
# 方法一,指出父类名 需要self
Father.money(self)
# 方法二 , 通过super() 不用self
super().money()
p4 = GrilOfSon('小芳' , 8)
p4.eat()
p4.money()

属性查找:子类对象自身——>子类中——>父类中

多层继承

被继承类都有属于自己的父类

class A:
name = '1A'
name1 = '11A'
class B(A):
name = '2B'
name2 = '22B'
class C(B):
name = '3C'
name3 = '33C'
def __init__(self):
self.name = '百事通'
q = C()
print(q.name)
# 如果没有初始化就会查到C类的name;
# 如果C类没有name,就会查到B类的name;以此类推
# 可以将前辈的东西都继承了,人要是天生就继承就好了
print(q.name1)
print(q.name2)
print(q.name3)
# 只能查到初始化方法里的属性
print(q.__dict__)

多继承

多继承:一个子类有多个父类

需要注意圆括号中父类的顺序,若是父类中有相同的方法名,而在子类使用时未指定,python从左至右搜索 即方法在子类中未找到时,从左到右查找父类中是否包含方法

class Horse:
def body(self):
return '健壮'
class Donkey:
def body(self):
return '娇小'
def labour(self):
return '勤快能干'
class Mule(Horse , Donkey):
pass
M = Mule()
print(M.body()) # 健壮
print(M.labour()) # 勤快能干
# 查看继承的顺序
print(Mule.__mro__)
# 查看第一个父类
# print(Mule.__base__)
# 在多继承中查看所有的父类,查不到爷爷类
print(Mule.__bases__)
# (<class '__main__.Mule'>, <class '__main__.Horse'>, <class '__main__.Donkey'>, <class 'object'>)
# <class '__main__.Horse'>
# (<class '__main__.Horse'>, <class '__main__.Donkey'>)

多态

不同的对象, 调用同一个方法 , 表现出不同的形态。

多态的实现:1、必须要有类的继承;2、子类对父类的方法进行重写

class A:
def func(self):
print('狗叫')
class B(A):
def func(self):
print('猫叫')
a = A()
b = B()
a.func()
b.func()

检查类型

# type() # 检查单个的数据类型
# issubclass(cls , class_tuple) # 检查类是否为后者的子类(检查前者是否继承后者)
# isinstance(obj , cls) # 检查 对象 是否为类中的
res = 'jjjj'
print(isinstance(res , int)) # False
print(issubclass(str, object)) # True
class Father:
pass
h = Father()
print(isinstance(h, Father)) # True
print(isinstance(res, Father)) # False
class Son(Father):
pass
print(issubclass(Father, Son)) # False
print(issubclass(Son, Father)) # True

_str_

str 是一个类的方法,在打印类对象,获取其属性信息时调用。

打印一个实例化对象时,默认打印的其实时一个对象的地址,

但是我们可以对其进行重载,打印我们想要的信息。

class people:
def __init__(self,name,age):
self.name=name
self.age=age
def __str__(self):
return '这个人的名字是%s,已经有%d岁了!'%(self.name,self.age)
a=people('孙悟空',999)
print(a)
# 这个人的名字是孙悟空,已经有999岁了!
# 如果没有重载函数的话输出的就是一串看不懂的字符串:
# <__main__.people object at 0x00000272A730D278

_del_

当检测到对象没有在继续引用时 , 就会自动的将对象所占用的内存空间清除

class Person:
def __init__(self, name):
self.name = name
def __str__(self):
return f'{self.name}来了 '
def __del__(self):
print(f'{self.name}被清除')
cx = Person('粗心超人')
tx = Person('甜心超人')
print(cx)
del cx
print('=' * 20)
print(tx)
print('kaijiu')

绑定与非绑定

类方法(绑定)

  • 通过@classmethod进行方法装饰
  • 类方法操作的是类属性 , 同cls进行对类的绑定
  • 类方法和对象方法(实例方法)都是绑定的
# 类方法(绑定)
class Student:
# 类属性
number = 0
# 实例属性
def __init__(self , name):
self.name = name
# 实例化的时候会执行下边的count函数,数量加一,
# 每次创建对象就会被监测到,而且给他编个号
self.id = self.count()
@classmethod
def count(cls):
cls.number += 1
return cls.number
ddg = Student('大大怪')
print(ddg.number)
xxg = Student('小小怪')
print(ddg.number)
print(Student.number)
print(ddg.id)
print(xxg.id)

静态方法(非绑定)

  • 通过@staticmethod进行方法装饰
  • 不需要绑定self以及call
  • 静态方法与定义在类外面的函数是一致的
  • 只是放在类中 ,方便管理(维护)。
import time
class FanPai:
def __init__(self, name):
self.name = name
@staticmethod
def str_time():
print(f'{time.strftime("%Y/%m/%d")}')
ddg = FanPai('大大怪')
xxg = FanPai('小小怪')
# 类和对象都可以 调用
# 类里边的的静态方法类似于模块里的函数
ddg.str_time()
xxg.str_time()
FanPai.str_time()