您当前的位置:首页 > 计算机 > 编程开发 > Python

python精选12集(面向对象概述、类和对象、封装)

时间:04-25来源:作者:点击数:

一、面向对象【概述】

1、面向对象与面向过程

  • 可模拟现实情景,更接近于人类思维。
  • 有利于梳理归纳、分析解决问题。
  • 找出解决问题的人,然后分配职责。

面向过程

根据业务逻辑从上到下写代码

面向对象

将数据与函数绑定到一起,分类进行封装,每个程序员只要负责分配给自己的分类,这样能够更快速的开发程序,减少了重复代码

2、 引入

你是王X井的老板,现在要新建一个万达商场,然后招了一百个工人,说明了你是要盖一栋楼,把人往工地上一扔,让工人开始干活。

项目肯定是不能完成的,因为没有分工。工地上可以做的事情很多,可能一件简单又安全的工作同时有多个人去做,而那些复杂又危险的工作,可能到最后都没有人做。

必须要进行分工,哪些人是搭架子,哪些人是负责吊车,哪些人是混水泥。

总结:大型的项目,必须要进行分工,将函数分为几个不同的类型,每个人负责一个或多个类型,比如一个人负责网站首页,一个人负责订单界面,一个人负责用户设置页面。

3、 深入

解决菜鸟买电脑的问题

第一种方式:

1)在网上查找资料

2)根据自己预算和需求定电脑的型号 MacBook 15 顶配 1W8

3)去市场找到苹果店各种店无法甄别真假 随便找了一家

4)找到业务员,业务员推荐了另外一款 配置更高价格便宜,也是苹果系统的,价格 1W

5)砍价30分钟 付款9999

6)成交

回去之后发现各种问题 

第二种方式 :

1)找一个靠谱的电脑高手

2)给钱交易
  • 面向对象和面向过程都是解决问题的一种思路而已

买电脑的第一种方式:

强调的是步骤、过程、每一步都是自己亲自去实现的

这种解决问题的思路我们就叫做面向过程

买电脑的第二种方式:

强调的是电脑高手, 电脑高手是处理这件事的主角,对我们而言,我们并不必亲自实现整个步骤只需要调用电脑高手就可以解决问题

这种解决问题的思路就 是面向对象

用面向对象的思维解决问题的重点

当遇到一个需求的时候不用自己去实现,如果自己一步步实现那就是面向过程

应该找一个专门做这个事的人来做

面向对象是基于面向过程的

4、浅出【客观定义】

面向对象(object-oriented ;简称: OO) 至今还没有统一的概念 我这里把它定义为: 按人们 认识客观世界的系统思维方式,采用基于对象(实体)的概念建立模型,模拟客观世界分析、设 计、实现软件的办法。

面向对象编程(Object Oriented Programming-OOP) 是一种解决软件复用的设计和编程方法。 这种方法把软件系统中相近相似的操作逻辑和操作 应用数据、状态,以类的型式描述出来,以对象实例的形式在软件系统中复用,以达到提高软件开发效率的作用。

二、类和对象

1、定义

<1> 类:一个抽象的概念,即生活中的”类别”。

理解:人以类聚 物以群分。

具有相似内部状态和运动规律的实体的集合(或统称为抽象)。 具有相同属性和行为事物的统称

<2> 对象:类的具体实例,即归属于某个类别的”个体”。

理解:某一个具体事物的存在 ,在现实世界中可以是看得见摸得着的。

可以是直接使用的

<3> .类是创建对象的”模板”。【类和对象的关系】

【理解如图】:

在这里插入图片描述

<4> 类与类行为不同,对象与对象数据不同。

Demo【类和对象】

奔驰汽车 类
奔驰smart 类 
张三的那辆奔驰smart 对象
狗 类
大黄狗 类 
李四家那只大黄狗 对象 
水果 类
苹果 类 
红苹果 类 红富士苹果 类 
我嘴里吃了一半的苹果 对象

<5> 类的构成

类(Class) 由3个部分构成

  • 类的名称:类名
  • 类的属性:一组数据
  • 类的方法:允许对进行操作的方法 (行为)

Demo【类的构成】

1)人类设计,只关心3样东西:

事物名称(类名):人(Person)
属性:身高(height)、年龄(age)
方法(行为/功能):跑(run)、打架(fight)
2)狗类的设计

类名:狗(Dog)
属性:品种 、毛色、性别、名字、 腿儿的数量
方法(行为/功能):叫 、跑、咬人、吃、摇尾巴
在这里插入图片描述

2、定义类

  • 定义
	class 类名:

 	 def __init__(self,参数列表):

    	self.实例变量 = 参数

      	方法成员
  • 说明
    • 类名所有单词首字母大写.
    • init也叫构造函数,创建对象时被调用,也可以省略。
    • self 变量绑定的是被创建的对象,名称可以随意。

Demo【定义一个类】

class Car:
    # 方法
    def getCarInfo(self):
        print('车轮子个数:%d, 颜色%s'%(self.wheelNum, self.color))

    def move(self):
        print("车正在移动...")

3、创建对象

就好比有车一个张图纸,那么接下来就应该把图纸交给生成工人们去生成了

python中,可以根据已经定义的类去创建出一个个对象

  • 创建对象的格式为:
	变量 = 构造函数 (参数列表)

Demo【创建对象】


# 定义类
class Car:
    # 移动
    def move(self):
        print('车在奔跑...')

    # 鸣笛
    def toot(self):
        print("车在鸣笛...嘟嘟..")


# 创建一个对象,并用变量BMW来保存它的引用
BMW = Car()
BMW.color = '黑色'
BMW.wheelNum = 4 #轮子数量
BMW.move()
BMW.toot()
print(BMW.color)
print(BMW.wheelNum)
在这里插入图片描述

理解

BMW = Car(),这样就产生了一个Car的实例对象,此时也可以通过实例对象BMW来访问属性或者方法

第一次使用BMW.color = '黑色’表示给BMW这个对象添加属性,如果后面再次出现BMW.color = xxx表示对属性进行修改

BMW是一个对象,它拥有属性(数据)和方法(函数)

当创建一个对象时,就是用一个模子,来制造一个实物

4、self

所谓的self,可以理解为自己

可以把self当做C++中类里面的this指针一样理解,就是对象自身的意思

某个对象调用其方法时,python解释器会把这个对象作为第一个参数传递给self,所以开发

者只需要传递后面的参数即可

Demo【理解self】

# 定义一个类
class Animal:

    # 方法
    def __init__(self, name):
        self.name = name

    def printName(self):
        print('名字为:%s'%self.name)

# 定义一个函数
def myPrint(animal):
    animal.printName()


dog1 = Animal('西西')
myPrint(dog1)

dog2 = Animal('北北')
myPrint(dog2)
  • 代码跑起来
名字为:西西
名字为:北北

5、init

在上一小节的demo中,我们已经给BMW这个对象添加了2个属性,wheelNum(车的轮胎数量)以及color(车的颜色),试想如果再次创建一个对象的话,肯定也需要进行添加属性,显然这样做很费事,那么有没有办法能够在创建对象的时候,就顺便把车这个对象的属性给设置呢?

那么__init__()方法就算最好的选择

  • 语法定义
	def 类名:
    	#初始化函数,用来完成一些默认的设定
    	def __init__():
        	pass

Demo【方法调用】


# 定义汽车类
class Car:

    def __init__(self):
        self.wheelNum = 4
        self.color = '蓝色'

    def move(self):
        print('车在跑,目标:夏威夷')

# 创建对象
BMW = Car()

print('车的颜色为:%s'%BMW.color)
print('车轮胎数量为:%d'%BMW.wheelNum)
  • 代码跑起来
车的颜色为:blue
车轮子数量为:4
  • 说明
    当创建Car对象后,在没有调用__init__()方法的前提下,BMW就默认拥有了2个属性wheelNum和color,原因是__init__()方法是在创建对象后,就立刻被默认调用了
  • 注意
    init()方法,在创建一个对象时默认被调用,不需要手动调用
    init(self)中,默认有1个参数名字为self,如果在创建对象时传递了2个实参,那么__init__(self)中出了self作为第一个形参外还需要2个形参,例如__init__(self,x,y)
    init(self)中的self参数,不需要开发者传递,python解释器会自动把当前的对象引用传递进去

6、实例成员

实例变量

  • 语法:
    (1)定义:对象.变量名
    (2)调用:对象.变量名
  • 说明:
    (1)首次通过对象赋值为创建,再次赋值为修改.
e01 =Enemy()#不建议使用

e01.name = “灭霸”#创建实例变量

e01.name = “小灭霸”#修改实例变量
(2)通常在构造函数(_init_)中创建。
e01 = Enemy(“灭霸”,999)

print(e01.name)
(3)每个对象存储一份,通过对象地址访问。
  • 作用:描述所有对象的共有数据。

dict:对象的属性,用于存储自身实例变量的字典。

7、实例方法

  • 语法
    (1) 定义:
    def 方法名称(self, 参数列表):
    方法体
    (2) 调用:对象地址.实例方法名(参数列表)
    不建议通过类名访问实例方法
  • 说明
    (1) 至少有一个形参,第一个参数绑定调用这个方法的对象,一般命名为"self"。
    (2) 无论创建多少对象,方法只有一份,并且被所有对象共享。
  • 作用:表示对象行为。
class Enemy:

    def __init__(self, name, atk):
        # 创建实例变量:
        self.name = name
        self.atk = atk

    def fun01(self):
        # 创建实例变量(建议写在init方法中)
        self.hp = 10
#创建变量
e01 = Enemy("灭霸",9999)
#修改变量
e01.name = "灭灭"
print(e01.name, e01.atk) #  灭灭  9999
print(e01.__dict__)      #  {'name': '灭灭', 'atk': 9999

8、类成员

类变量

  • 语法
    (1)定义:在类中,方法外定义变量。
class 类名:

   变量名 = 表达式
(2)调用:类名.变量名

不建议通过对象访问类变量
  • 说明:
    存储在类中。
    只有一份,被所有对象共享。
  • 作用:描述所有对象的共有数据。

9、类方法

  • 语法
    (1)定义:
   @classmethod

   def 方法名称(cls,参数列表):

        方法体
(2)调用:类名.方法名(参数列表) 

 不建议通过对象访问类方法
  • 说明
    至少有一个形参,第一个形参用于绑定类,一般命名为’cls’
    使用@classmethod修饰的目的是调用类方法时可以隐式传递类。
    类方法中不能访问实例成员,实例方法中可以访问类成员。
  • 作用:操作类变量。

Demo【类方法】

class ICBC:
  """
    工商银行
  """
  # 类被加载时,类变量被创建.
  # 通过类变量,表示总行的钱
  total_money = 5000000

  @classmethod  # 调用当前方法时,自动传递类名(类地址).而不是对象地址
  def print_total_money(cls):
    # 表达类的行为,只能操作类变量,不能操作实例变量.
    print("总行的钱有:%d" % cls.total_money)

  def __init__(self, name, money):
    # 通过实例变量,表示支行的钱
    self.name = name
    self.money = money
    # 从总行中扣除当前支行使用的钱
    ICBC.total_money -= money


# 创建对象,创建实例变量
i01 = ICBC("天坛支行", 100000)
# 访问类变量
# print(ICBC.total_money)
# 访问类方法
ICBC.print_total_money()  # 自动传递类名,到类方法中.
i02 = ICBC("天安门支行", 200000)
print(ICBC.total_money)

  ##总行的钱有:4900000
  ##4700000

10、静态方法

  • 语法
    (1)定义:
   @staticmethod

   def 方法名称(参数列表):

     方法体
(2)调用:类名.方法名(参数列表) 

 不建议通过对象访问静态方法
  • 说明
    使用@ staticmethod修饰的目的是该方法不需要隐式传参数。
    静态方法不能访问实例成员和类成员
  • 作用:定义常用的工具函数。

Demo【静态方法】

class Vector2:
  """
    向量
  """

  def __init__(self, x, y):
    self.x = x
    self.y = y

  @staticmethod  # 调用当前方法时,不会自动传递任何信息.
  def get_right():
    return Vector2(0, 1)

  @staticmethod
  def get_up():
    return Vector2(-1, 0)

  @staticmethod
  def get_left():
    return Vector2(0, -1)

  @staticmethod
  def get_down():
    return Vector2(1, 0)
    
pos01 = Vector2(1, 2)
# 通过静态方法,获取向右的方向
right = Vector2.get_right()
# 表示 pos01 点向右: 点 + 方向
pos02 = Vector2(pos01.x + right.x, pos01.y + right.y)
print(pos02.x, pos02.y)  #1 3

三、封装

1、定义

<1> 数据角度讲,将一些基本数据类型复合成一个自定义类型。

<2> 行为角度讲,向类外提供必要的功能,隐藏实现的细节。

	封装数据:多个数据 --> 一个种数据(新类型)
	
	例如:学生类(姓名/年龄..) 汽车(品牌/价格..)
	
	适用性:多种信息描述同一种事物.

2、设计角度讲重点

(1)分而治之

  • 将一个大的需求分解为许多类,每个类处理一个独立的功能。 (类要小而精,拒绝大而全.)
  • 拆分好处:便于分工,便于复用,可扩展性强。

(2) 封装变化

  • 变化的地方独立封装,避免影响其他类。(分解的度,识别变化点,单独做成类.)

(3) 高 内 聚

  • 类中各个方法都在完成一项任务(单一职责的类)。(类内部,高度聚集.完成一个变化点。)

(4) 低 耦 合

  • 类与类的关联性与依赖度要低(每个类独立),让一个类的改变,尽少影响其他类。(类与类关系,尽量松散。)
      [例如:硬件高度集成化,又要可插拔]
    
    最高的内聚莫过于类中仅包含1个方法,将会导致高内聚高耦合。
    最低的耦合莫过于类中包含所有方法,将会导致低耦合低内聚。
  • 作用
    简化编程,使用者不必了解具体的实现细节,只需要调用对外提供的功能。
    松散耦合,降低了程序各部分之间的依赖性。

数据和操作相关联,方法操作的是自己的数据。

1.作用:无需向类外提供的成员,可以通过私有化进行屏蔽。

2.做法:命名使用双下划线开头。

3.本质:障眼法,实际也可以访问。

3、私有成员

私有成员的名称被修改为:_类名__成员名,可以通过_dict_属性或dir函数查看。

slots

  • 作用:限定一个类创建的实例只能有固定的实例变量,不能再额外添加。
  • 语法:
在类中定义

__slots__ = (“变量名1”,”变量名2”…..)

1.说明:含有__slots__属性的类所创建的对象没有__dict__属性, 即此实例不用字典来存储对象的实例属性。

2.优点:访止用户因错写属性的名称而发生程序错误。

3.缺点:丧失了动态语言可以在运行时为对象添加变量的灵活性。

class Wife:
  __slots__ = ("name","__age")
  def __init__(self, name, age):
    self.name = name
    self.age = age

  @property
  def age(self):
    return self.__age

  @age.setter
  def age(self,value):
    self.__age = value

w01 = Wife("丽丽",26)
# 因为类中定义了__slots__,所以不能在类外添加新数据.
# w01.sex = "女"
# w01.nmae = "莉莉"
print(w01.age)

4、属性@property

公开的实例变量,缺少逻辑验证。私有的实例变量与两个公开的方法相结合,又使调用者的操作略显复杂。而属性可以将两个方法的使用方式像操作变量一样方便。

1.定义:

class Wife:
  """
    老婆
  """
  def __init__(self, name, age):
    self.name = name
    self.age = age

  @property # 拦截读取操作
  def age(self):
    return self.__age

  @age.setter# 拦截写入操作
  def age(self, value):
    if 28 <= value <= 32:
      self.__age = value
    else:
      raise Exception("超出年龄,我不要")

  # 拦截 对数据的操作,转为调用读写方法.
  #age = property(get_age, set_age)


w01 = Wife("丽丽", 30)
print(w01.age)
print(w01.__dict__)

2.调用:

	对象.属性名 = 数据
	
	变量 = 对象.属性名

3.说明:

  • 通常两个公开的属性,保护一个私有的变量。
  • @property 负责读取,@属性名.setter 负责写入
  • 只写:属性名= property(None, 写入方法名)
方便获取更多学习、工作、生活信息请关注本站微信公众号城东书院 微信服务号城东书院 微信订阅号
推荐内容
相关内容
栏目更新
栏目热门