Python高级编程1-python面向对象初识

面向对象初识

文章目录

  • 一、面向对象
    • (一)什么是面向对象?
    • (二)什么是类?
    • (三)使用面向对象写代码的好处
    • (四)面向对象的三大特征
      • 1. 封装
        • 小案例:使用面向对象思想实现游戏中攻击、血量等功能
      • 2.继承与多态

一、面向对象

(一)什么是面向对象?

​ 面向对象是一个编程范式(也就是我们写代码的套路)

​ 满足我们的需求,比如:我现在给你一个商品列表,要你按照价格排序

首先我们要现有一个商品表

commodity_infos = [
    {"cid":101,"name":"苹果""price":5},
    {"cid":102,"name":"葡萄""price":8},
    {"cid":103,"name":"橘子""price":3},
    {"cid":104,"name":"猕猴桃""price":6},
    {"cid":105,"name":"柚子""price":2}
]

输出商品信息:利用一个for循环便可以将商品的信息输出

for commodity_info in commodity_infos:
    print(commodity_info)

我们的需求是:通过价格排序

思路:

1.确定列表里的第一个元素的价格是列表里面最大的

拿列表里的第一个元素和它后边的元素比较一下

如果发现比第一个元素大的就要交换元素的位置

那么我们如何交换位置嘞?

list1 = [1, 2, 3, 4, 5]
list1[1], list1[0] = list1[0], list1[1]

#运行结果:[2, 1, 3, 4, 5]


#回顾一点点知识:给列表里的值重新赋值给变量
a, b, c, d, e = list1
print(a)
#运行结果:2

2.确定列表里的第二个元素的价格是列表里面第二大的

拿列表里的第二个元素和它后边的元素比较一下

如果发现比第二个元素大的就要交换元素的位置

3.确定列表里的第三个元素的价格是列表里面第三大的

拿列表里的第三个元素和它后边的元素比较一下

如果发现比第三个元素大的就要交换元素的位置

4.确定列表里的第四个元素的价格是列表里面第四大的

拿列表里的第四个元素和它后边的元素比较一下

如果发现比第四个元素大的就要交换元素的位置

(第五个就不用啦,因为我们在第四步的时候就已经将整体的排序都做好了)

实现的步骤:

1.取出前几个数据(不要最后一个)

2.拿到数据与后边的元素作比较

3.发现更大的交换位置

commodity_infos = [
    {"cid": 101, "name": "苹果", "price": 5},
    {"cid": 102, "name": "葡萄", "price": 8},
    {"cid": 103, "name": "橘子", "price": 3},
    {"cid": 104, "name": "猕猴桃", "price": 6},
    {"cid": 105, "name": "柚子", "price": 2}
]
#1.取出前几个数据(不要最后一个)
for r in range(len(commodity_infos) - 1):  # r表示第r个数据
    for c in range(r + 1, len(commodity_infos)):# c表示r后边的数据
        #2.拿到数据与后边的元素作比较
        if commodity_infos[r]["price"] < commodity_infos[c]["price"]:
            #3.发现更大的交换位置
            commodity_infos[r], commodity_infos[c] = commodity_infos[c], commodity_infos[r]

for commodity_info in commodity_infos:
    print(commodity_info)

面向过程

  • 总结之前写代码的套路,即分析出来写代码的步骤,然后使用代码逐步实现,如上诉的例子。这就是面向过程 (面向:即是以什么为核心)

  • 面向过程就是把 一个复杂的过程流程化,进而简单化,我们要实现一个功能就要使用这种思维方式。

面向对象:对象再我们程序里边叫object,有物体的意思。

  • 在使用面向对象写代码的时候,首先要想的就是这个程序有哪些部分组成,然后再去想每一步要怎么做。

  • 在面向对象里面,我们想要把现实的事物在我们程序里面表示,需要将现实的事物抽象成我们代码里边的类,然后通过类产生程序对象,通过对象和我们现实生活中的事物对应。

面向对象与面向过程的关系

​ 面向对象和面向过程都是我们写代码的方式,不能把他们对立起来,他们之间是相辅相成的。面向对象是从整体上分析构成,面向过程是注重怎样实现。

小tips❤️:

1.输出快捷方式

​ 用法:变量名称.print + 按下enter键 即可立即变成 print(变量名称) 的形式

2.快速打出for循环的模板

​ 用法:iter + 按下enter键 即可立即出现一个for循环的模板,如下

for  in  :

3.快速调整代码的的格式:Ctrl+Alt+L

4.快速注释:Ctrl+/

5.property的快捷模板:

​ 用法: props + Enter 即可出现模板

 @property
    def (self):
        return 
    
    @.setter

6.快速将参数传递的快捷键 Alt+Enter+Enter,效果如下:

class Commodity :
    def __init__(self,cid,name,price):
        self.price = price
        self.name = name
        self.cid = cid

(二)什么是类?

​ 就是我们生活当中类别的意思

语法:

class 类的名称 :

1.先定义类

  • 使用class关键字去定义一个类

  • 类名建议使用驼峰体

  • 类与类之间主要是行为不同:人类和动物类有不同的行为

  • 在类中写的函数,我们管它叫做方法,每个方法都会有一个self参数

#1.先定义类

class GirlFriend:
    def send_msg(self):  #女朋友会给男朋友发消息
        print('给男朋友发消息')
    
    def shopping(self):  #女朋友会购物
        print('买买买')

2.产生对象

  • 类名 + ()就是实列话一次,实例化一次就是得到一个对象。实例化两次就得到两个对象。
g1 = GirlFriend()
g2 = GirlFriend()
  • 但是每个女朋友都有她独特的地方,我们这时候就会用到一个叫做__init__的方法

    当我们添加了__init__方法的时候,首先会根据这个类创建一个对象,第二部接着去执行__init__这个方法,python会自动将创建的对象当成参数传值给self(self就是对象的一个内存空间)\

    举个:如下,创建对象时,因为有init,所以会将g1传递给self。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2PrrUPVP-1651233023580)(C:\Users\彭兴娇\AppData\Roaming\Typora\typora-user-images\1645447697005.png)]

class GirlFriend:
    def __init__(self,name,face_score,money,boy_fiend):
        #实列属性:属于对象的,只能通过对象调用
        self.name = name
        self.face_score = face_score
        self.money = money
        self.boy_fiend = boy_fiend
        
    #绑定到对象的方法:可以使用类或者对象调用
    #如果我们使用类来调用的话,这个方法就是一个普通的函数
    #如果是对象来调用的话,就会把对象当成第一个参数传递
    def send_msg(self):  #女朋友会给男朋友发消息
        print('给男朋友发消息')
    
    def shopping(self):  #女朋友会购物
        print('买买买')
        
        
g1 = GirlFriend("小红",95,88888,"小蓝")
g2 = GirlFriend()

#如果我们想要输出女朋友的名字或者颜值,我们可以像这样子输出:
print(g1.name)
print(g1.face_score)

#如果我们是通过类来调用
print(GirlFriend.send_msg)  #这样字就只是一个普通的函数

#如果我们想要调用的话,就必须传入参数
GirlFriend.send_msg



我们在给对象传值得时候会自己传到参数里边去。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1MKER7uw-1651233023582)(C:\Users\彭兴娇\AppData\Roaming\Typora\typora-user-images\1644586886286.png)]

(三)使用面向对象写代码的好处

好处:把数据对象封装到一个类里边去,然后在方法里边对已经封装的数据进行操作,这样可以将数据对数据的操作相关联,让代码的可读性更高,让我们分析问题的时候更方便。

#如果我们将每一个商品做成一个类
class Commodity :
    def __init__(self,cid,name,price):
        self.price = price
        self.name = name
        self.cid = cid
    #定义一个功能,用于输出商品的信息
	def print_commodity_info(self):
        print(f"编号:{self.cid}--商品名称:{self.name}--商品价格:{self.price}")

#如何去产生一个真实的商品呢?我们使用类名往里边传入参数,就产生了一个商品
commodity_info = [
    #商品对象
    Commodity(1001,"苹果",5)
]

(四)面向对象的三大特征

1. 封装

将多个数据打包、封装到一个自定义的类里面,对类外提供必要的功能隐藏实现的细节。

好处:

  • 将多个数据打包、封装到一个自定义的类里面

    • 符合人的思维方式

    • 可以将数据和对数据的操作封装在一起,有利于我们分析解决问题

    • 以后我们拿到一个需求,我们应该将这个需求分解成多个类,类和类之间是行为上的不同,对象和对象之间是数据上的不同。

      例如:五子棋可以分为:棋子,棋盘,规则三个类

      • 便于分工
      • 代码可读性更高
      • 可扩展性强
  • 对类外提供必要的功能隐藏实现的细节,无关紧要的不对外提供

    • 我写了一个类在我们使用的时候,不需要考虑每个功能是怎么实现的

      class Atm:
          #以下这五个功能,我们在使用的时候不用考虑细节,是怎么来的
          def card(self):
              print("插卡")
              
          def auth(self):
              print("用户认证")
              
          def input(self):
              print("输入取款的金额")
              
          def print_bill(self):
              print("打印账单")
          
          def take_money(self):
              print("取款")
          
          #我们只需要给出一个功能来触发上述五个功能即可
          def draw_money(self):
              self.card
              self.auth
              self.input
              self.print_bill
              self.take_money
              
      a = Atm
      a.draw_money()
      #运行结果:
      	#插卡
      	#用户认证
          #输入取款金额
          #打印账单
          #取款
      a.card()#在这一步我们发现card等功能还是暴露出来了,给用户看到了,我们需要将这些隐藏起来不给用户看到
      

      python中我们实现隐藏是通过私有化来做的,在命名的时候使用双下划线开头,就代表我们要把这个功能藏起来

        • #如何实现隐藏
          class A:
              def __init__(self,name):
                  self.__name = name  #在前边使用双下划线,代表把name隐藏了,私有化了
                  
              def __foo(self):#方法也是可以隐藏的
                  print('foo')
                  
          a = A("孜孜淑淑")
          print(a.name) #此时是访问不到name的,因为name已经被隐藏了,执行会报错
          
          print(A.__dict__)#通过这种方式,我们就可以知道类里边有哪些东西,隐藏的也能看到
          
          #如何访问隐藏的方法
          A._A__fool(1)#通过该方法就可以访问隐藏的方法或者变量
          
          #特点:
          '''
          1.在类外我们不是直接通过 对象.属性/方法 访问
          2.在类的内部是可以直接使用的
          '''
          
          

          隐藏的使用场景:

          ​ 实列属性:我们把放在____init____里边的叫做实列属性,也就是每个对象属性

          ​ 使用场景:

          class GirlFriend:
              def __init__(self,name,age,weight):
                  self.weight = weight
                  self.__age = age
                  self.__name = name
                  self.set_age(age)
              def get_age(self):
                  return self.__age
              def set_age(self,value):  #限定女朋友的年龄
                  if 21 <= value <=30:
                      set.__age = value
                  else:
                      raise ValueError("我不要")    #如果没有达到年龄的要求,就直接报错。这样可以保证数据的安全,比如空调的温度
                  
          #实例化就是通过调用一次类名,就进行实例化一次
          g1 = GirlFriend("小红",18,100)
          
        • 公开的实例属性,缺少逻辑验证。私有实例和两个公开的方法结合使用。在这里我们介绍一个类property:

          • '''
            使用了property(放在类里边的)之后,我们在通过 对象.age 就会触发到 get_age的执行
            当我们使用 对象.age = 赋值 的时候就会出发到 set.age
            property对象可以当作是拦截了我们对age的读写操作,优先级更高
            '''
            #property使用方法一:
            class GirlFriend:
                def __init__(self,name,age,weight):
                    self.weight = weight
                    self.__age = age
                    self.__name = name
                    self.set_age(age)
                def get_age(self):
                    return self.__age
                def set_age(self,value):  #限定女朋友的年龄
                    if 21 <= value <=30:
                        set.__age = value
                    else:
                        raise ValueError("我不要") 
            	age = property(get_age,set_age)  #会使优先级更高,当涉及到age时,会先找到get_age,set_age这两个方法
                
            #property使用方法二:
            class GirlFriend:
                def __init__(self,name,age,weight):
                    self.weight = weight
                    self.__age = age
                    self.__name = name
                    self.set_age(age)
                    
                @property  #相当于执行了 age = property(age) 创建了一个property对象 只负责拦截读取操作
                def age(self):
                    return self.__age
                
                @age.setter  #拦截我们写入的操作
                def age(self,value):  #限定女朋友的年龄
                    if 21 <= value <=30:
                        set.__age = value
                    else:
                        raise ValueError("我不要") 
            '''
            使用该方法的快捷方式:`props`+`Enter`  就会自动创建一个该模板
             @property
                def (self):
                    return 
                
              @.setter
            '''
            

          小案例:使用面向对象思想实现游戏中攻击、血量等功能

          使用面向对象思想实现以下两个要求:

          玩家可以攻击敌人,敌人受伤血量减少的同时播放敌人受伤的画面

          敌人也可以攻击玩家,玩家血量减少的同时出现碎屏效果

          #玩家类
          class Player:
              def __init__(self,hp,atk):  #每一个玩家都会有血量和攻击力
                  self.atk = atk
                  self.hp = hp
          
              def attack(self,enemy):
                  print('玩家攻击敌人')
                  enemy.enemy_wounded(self.atk)
          
              def player_injured(self,value):
                  print('碎屏 啊啊啊')
                  self.hp -= value  # 被攻击血量应该减少
                  print(f'现在玩家的血量是{self.hp}')
          
          
          #敌人类
          class Enemy:
              def __init__(self,hp,atk):
                  self.atk = atk
                  self.hp = hp
          
              def enemy_wounded(self,value): #value是减少的血量值
                  print('播放受伤的画面')
                  self.hp -= value  #被攻击血量应该减少
                  print(f'现在敌人的血量是{self.hp}')
          
              def attack(self,player):
                  print('敌人攻击玩家')
                  player.player_injured(self.atk)
          
          
          p1 = Player(500, 50)  #创建一个玩家
          e1 = Enemy(100, 10)  #创建一个敌人
          
          p1.attack(e1)  #玩家攻击敌人
          print('-'*20)
          e1.attack(p1)
          
          #运行结果:
          '''
          玩家攻击敌人
          播放受伤的画面
          现在敌人的血量是50
          --------------------
          敌人攻击玩家
          碎屏 啊啊啊
          现在玩家的血量是490
          '''
          

          在该案例当中添加“手雷”,手雷爆炸可以炸玩家也可以炸敌人

          #手雷
          class Grenade:
              def __init__(self,atk): # atk攻击力
                  self.atk = atk
                  
                      
              def explode(self, target): #爆炸,target攻击目标
                  print("拉环")
                  print("手雷爆炸")
                  '''
                  if type(target) == Enemy:#如果攻击对象是敌人
                      target.enem_wounded(self.atk)  #敌人受伤
                  elif type(target) == Player: #如果攻击的对象是玩家
                      target.player_injured(self.atk)  #玩家受伤
          		'''
                  #改良之后,我们就不用判断它是那种属性的人了,直接调用即可
                  target.damage(self.atk)
                 
                  
          #分析:不管是我们的玩家还是敌人,总之有个共同属性,便是可攻击对象,在这里我们就可以创建以个攻击对象的父类
          
          class AttackTarget:  #父类
              def damage(self,value): #定义一个方法,让他们被攻击
                  pass
          
          #玩家类
          class Player(AttackTarget):
              def __init__(self,hp,atk):  #每一个玩家都会有血量和攻击力
                  self.atk = atk
                  self.hp = hp
          
          
              def attack(self,enemy):
                  print('玩家攻击敌人')
                  enemy.enemy_wounded(self.atk)
          
              def player_injured(self,value):
                  print('碎屏 啊啊啊')
                  self.hp -= value  # 被攻击血量应该减少
                  print(f'现在玩家的血量是{self.hp}')
          
          
          #敌人类
          class Enemy(AttackTarget):
              def __init__(self,hp,atk):
                  self.atk = atk
                  self.hp = hp
          
              def enemy_wounded(self,value): #value是减少的血量值
                  print('播放受伤的画面')
                  self.hp -= value  #被攻击血量应该减少
                  print(f'现在敌人的血量是{self.hp}')
          
              def attack(self,player):
                  print('敌人攻击玩家')
                  player.player_injured(self.atk)
          

类属性

对象中有多个相同的数据,这个时候我们可以选择吧这个给数据做成类变量

举个例子:

class Person:#定义一个人的类
   country = "中国"   #所有的人都是中国人,这个是相同的数据
   
   def __init__(self, name, age):
       self.name = name
       self.age = age
       
p1 = Person("小红",18)
p2 = Person("小蓝",22)
print(p1.name)
print(p2.name)

#country 是他们的共同属性,都可以用
print(p1.country)
print(p2.country)

2.继承与多态

(1)继承:重用类的功能和概念

​ ‘你要笑死我,然后继承我的花呗’ 父子的关系才会有继承

​ 比如皇位,江山不需要太子打,但太子可以登基

​ 在编程里,父类代码不用子类写,但是子类可以用父类的代码

# **********继承的写法***************
# 父类:动物
class Animal:
    def eat(self):
        print("吃")
# 子类:狗的父类是动物
class Dog:
    def eat(self):
        print("吃")

    def run(self):
        print("跑")
# 子类:鸟的父类是动物
class Bird:
    def eat(self):
        print("吃")

    def fly(self):
        print("飞")
# 狗和鸟有共性,我们可以将他们的共性写在父类,这样鸟和狗都可以使用

d1 = Dog()
# 对象本身找,没有的话然后到类里边找,最后到父类里边找
d1.eat = 123
print(d1.eat)

小练习:

以下代码运行结果是什么?
class Foo:
    def f1(self):
        print("from Foo.f1")
    def f2(self):
        print("from Foo.f2")
        self.f1()

class Bar(Foo):
    def f1(self):
        print("from Bar.f1")

b = Bar()
b.f2()

#运行结果:
'''
from Foo.f2
from Bar.f1
'''

'''
原因:
	首先,b是一个没有实列属性的对象,b这个对象所在的类下边是没有f2这个属性,没有的话就去找父类Foo,那就打印出来from Foo.f2
	然后接下来是self.f1,在这里的这个self会在自己(b)的类里边找,就是Bar里边的f1
'''
  • 子类里边什么都没有的话,那这个子类里面的所有东西都是继承父类的

  • 在子类里面定义了自己的,就以自己的为准

  • 问题点是我们在子类里面派生出来的方法里面我想用父类的代码,不是说重新写一遍,我是想在父类的基础上做一点小改动,这个时候我们就需要在子类里边调用父类的方法。

#**********在子类里边调用父类的方法*************
class Animal:  #父类
    def __init__(self, name, sex, age):
        self.age = age
        self.sex = sex
        self.name = name
    def eat(self):
        print("吃")
        
class Dog(Animal): #子类
    def __init__(self, name, sex, age, title):
        self.title = title
        self.age = age
        self.sex = sex
        self.name = name


d1 = Dog("旺财", "公", 3, "拉布拉多") #在这里,我们最先促发到的还是Dog里边的__init__
print(d1.__dict__)
#方式一:指名道姓
class Dog(Animal): #子类
    def __init__(self, name, sex, age, title):
        Aniaml.__init__()  #执行到此处默认调用父类的__init__
        self.title = title

#方法二:super()方法
'''
使用super()会得到一个特殊的对象,这个对象专门用来调用父类的方法
'''
class Dog(Animal): #子类
    def __init__(self, name, sex, age, title):
        super().__init__(name, sex, age)  #执行到此处调用父类的__init__
        self.title = title

(2)多态:父类的同一中行为在不同的子类上有不同的实现,可以增强我们程序的可扩展性。

增加新的东西不会影响到我们的类

#子类
def init(self, name, sex, age, title):
self.title = title
self.age = age
self.sex = sex
self.name = name

d1 = Dog(“旺财”, “公”, 3, “拉布拉多”) #在这里,我们最先促发到的还是Dog里边的__init__
print(d1.dict)
#方式一:指名道姓
class Dog(Animal): #子类
def init(self, name, sex, age, title):
Aniaml.init() #执行到此处默认调用父类的__init__
self.title = title

#方法二:super()方法
‘’’
使用super()会得到一个特殊的对象,这个对象专门用来调用父类的方法
‘’’
class Dog(Animal): #子类
def init(self, name, sex, age, title):
super().init(name, sex, age) #执行到此处调用父类的__init__
self.title = title




(2)多态:父类的同一中行为在不同的子类上有不同的实现,可以增强我们程序的可扩展性。

增加新的东西不会影响到我们的类

​	

你可能感兴趣的:(Python高级编程学习笔记,python,pycharm)