0
点赞
收藏
分享

微信扫一扫

【Python中的面向对象】

萨科潘 2022-04-15 阅读 120

Python中的面向对象

文章目录

  • 实例化 : 根据类来创建对象

创建类

  • 关键字 : class 用于定义一个类
  • 类名第一个字母通常要大写
  • __init__(self) : 为构造函数, 第一个参数必须为self, 后面的参数是实例化类时传入的参数
  • 定义类的时候若无参数传入可以不用定义构造函数
class Car():
    def __init__(self,name,color,brand):
        # 定义对象属性(也叫变量)
        self.name = name # 获取存储在形参name中的值,并将其存储到变量name 中,然后该变量被关联到当前创建的实例
        self.color = color
        self.brand = brand

    def kind(self):
        #类方法中的定义的对象属性是可以在同一个类中的方法中使用, 但是必须得在类方法中已经初始化才能给另一个类方法中
        self.level = "很牛逼的车" 
        size = "large"  # 这个才是类方法的变量
        print(self.name+"的车类型为::"+self.type)

    def drive(self):
        print(self.name+"开着一辆"+self.color+self.type)

    def evaluate(self):
        print(self.level)
  • self一个指向实例本身的引用,让实例能够访问类中的属性和函数(方法)。
  • 每个与类相关联的函数(方法)调用都自动传递实参self
  • 定义类函数(方法)时,必须要用self作为形参, 这也是普通方法与类方法的主要区别
  • 类方法只需要传入一个self作为实参, 它就可以任意使用类中的属性和调用类中的方法

使用类

  • 用类来创建对象 : 对象名 = 类名()
  • 访问对象属性 : 对象名.属性
  • 使用对象方法 : 对象名.方法()
# 使用Car类创建一个实例
car1 = Car("张三","粉色","奔驰") # 创建一个对象
# 可以指定传入的参数, 若没有指定, 则必须要按顺序传参
car2 = Car(name = "李四",brand="宝马",color="黑色") # 这种传参无需按顺序
print(car1.color) # 使用对象的属性
car1.kind() # 调用对象的方法
car1.drive() # 调用对象的方法 
  • 修改属性
    • 可直接通过对象.属性进行赋值修改
    • 也可通过定义类方法来将属性值传入方法中
    • 通过调用方法来改变属性值
class Car():
    def __init__(self,name,color,brand):
        self.name = name
        self.color = color
        self.brand = brand
        self.capacity = 5 # 座位数量, 给默认初始值
        self.num = 0
        self.introduce = "车的简介"

    def update_capacity(self,capacity):
        self.capacity = capacity

    def update_num(self):
        self.num += 1
        
    def getNum(self):
        print("num:%d"%self.num)

    def getCapacity(self):
        print("capacity:%d"%self.capacity)

    def getIntroduce(self):
        print("introduce:%s"%self.introduce)

    def printGet(self):
        self.getNum()
        self.getCapacity()
        self.getIntroduce()

xiaoming_car = Car("小明","绿色","本田")
xiaoming_car.printGet()
print("修改后的属性值")

# 第一种: 直接修改属性值
xiaoming_car.introduce = "这是个牛逼的车"
# 第二种: 通过类方法进行传参
xiaoming_car.update_capacity(3)
# 第三种: 通过类方法进行修改
xiaoming_car.update_num()

xiaoming_car.printGet()

输出 :

num:0
capacity:5
introduce:车的简介
修改后的属性值
num:1
capacity:3
introduce:这是个牛逼的车

类的专有方法

专有方法说明
__init__构造函数,在生成对象时调用
__del__析构函数,释放对象时使用
__repr__打印,转换
__setitem__按照索引赋值
__getitem__按照索引获取值
__len__获得长度
__cmp__比较运算
__call__函数调用
__add__加运算
__sub__减运算
__mul__乘运算
__truediv__除运算
__mod__求余运算
__pow__乘方

继承

  • class 类名(继承类), 即继承的父类写在定义类的后面的括号里
  • python是可以多继承的, 若有多个父类则用,隔开,

子类的构造方法

  • 创建子类的实例时, Python 首先需要完成的任务是给父类的所有属性赋值。为此,子类的方法 __init__() 需要父类施以援手

  • super()是特殊函数(方法),将父类和子类关联起来。父类也叫超类(superclass), 因此用super()来将父类与子类的构造方法联系起来

    • super().__init__(), 该写法必须放在子类的构造函数里即__init__()函数里
  • 举个栗子

class Game():
    # 默认参数要跟在非默认参数后面, 不然会报错
    #比如: name 和 price = 0.00, name必须放前面, price带默认参数须放后面
    def __init__(self,name,type="手游",price=0.00):
        self.name = name
        self.type = type
        self.price = price

class Shop():
    def action(self):
        # print("欢迎来到{}游戏商店!".format(self.name)) # self.name使用子类的属性, 但是因为父类没有声明该属性, 若直接实例化父类, 再调用这个方法会报错
        print("欢迎来到游戏商店!")
        
        
class Shooter(Game,Shop):  # 继承多个父类
    def __init__(self,name,size,type="手游",price=0.00):
        # 使用super()即把父类下的构造方法内的属性都放到子类中, 使得子类得以继承父类的属性
        super().__init__(name,type,price)
        # 相当于下面的写法
        # self.name = name
        # self.type = type
        # self.price = price
        self.size = size  #添加的子类属性, 仅在子类中生效

重写父类的方法

  • 对于父类的方法,如果它的方法对子类不适用,都可在子类中对其进行重写
  • 重写就是用父类的方法名重新定义一遍, 当子类与父类的方法名相同时, 解释器会优先调用子类方法的内容,从而忽略父类方法的内容
class Game():
    # 默认参数要跟在非默认参数后面, 不然会报错
    #比如: name 和 price = 0.00, name必须放前面, price带默认参数须放后面
    def __init__(self,name,type="手游",price=0.00):
        self.name = name
        self.type = type
        self.price = price

class Shop():
    def action(self):
        print("欢迎来到游戏商店!")

class Shooter(Game,Shop):  # 继承多个父类
    def __init__(self,name,size,type="手游",price=0.00):
        # 使用super()即把父类下的构造方法内的属性都放到子类中, 使得子类得以继承父类的属性
        super().__init__(name,type,price)
        self.size = size

    def action(self):  # 重写父类Shop的方法
        print("欢迎来到{}游戏商店!".format(self.name))

将实例用作属性

  • 在类内实现另一个类的实例化, 即将别的类的实例作为该类的一个属性
  • 这样的好处是可以将大型类拆分成多个协同工作的小类, 可以将一个庞大的类变小(指在代码行数上), 方便后续的开发和整理
class Game():
    # 默认参数要跟在非默认参数后面, 不然会报错
    #比如: name 和 price = 0.00, name必须放前面, price带默认参数须放后面
    def __init__(self,name,type="手游",price=0.00):
        self.name = name
        self.type = type
        self.price = price

    def getName(self):
        print("这是一款%s游戏"%self.name)

    def getCost(self):
        print("游戏的花费%d"%self.price)

    def setPrice(self,set_price):
        self.price = set_price

    def promotePrice(self,cost):
        self.price += cost

    def getType(self):
        print("这款游戏的类型是%s"%self.type)


class Shop():
    def action(self):
        # print("欢迎来到{}游戏商店!".format(self.name)) # self.name使用子类的属性, 但是因为父类没有声明该属性, 若直接实例化父类, 再调用这个方法会报错
        print("欢迎来到游戏商店!")

class Skill():
    def __init__(self,arm,energy):
        self.arm = arm
        self.energy = energy
    def attack(self):
        print("武器为%s"%self.arm)

class Shooter(Game,Shop):  # 继承多个父类
    def __init__(self,name,size,type="手游",price=0.00):
        # 使用super()即把父类下的构造方法内的属性都放到子类中, 使得子类得以继承父类的属性

        super().__init__(name,type,price)
        # self.name = name
        # self.type = type
        # self.price = price
        self.size = size
        self.skill = Skill("m416",500) # 在类内实现另一个类的实例化, 即将别的类的实例作为该类的一个属性

    def action(self):
        print("欢迎来到{}游戏商店!".format(self.name))

# 类的实例化
# 注意 : 若指定传入参数可以不用按顺序进行写, 但必须全部都是写成按指定名字的形参进行传
# 像这样是错误的game1 = Shooter(size="100GB",绝地求生","端游")
# 不传参的就按默认值取
game1 = Shooter(size="100GB",name="绝地求生",type="端游")
game2 = Shooter("和平精英","5GB","手游")
game2.skill.attack()

导入类

  • 一个模块就是一个py文件
  • 可以将一个类写进一个模块里
  • 一个模块中可以有多个类, 因此模块的文件名不要求首字母大写

导入单个类

  • 使用import关键字导入

  • 若从某个模块中导入一个类, 则用from 模块名 import 类名

  • as 关键字可以给模块/类/函数指定别名

    • 如果要导入的模块/类/函数的名称可能与程序中现有的名称冲突,或者函数的名称太长,可指定简短而独一无二的 别名 —— 模块/类/函数的另一个名称,类似于外号。
    • 要指定这种特殊外号,只需要在导入它后面使用as关键字 : import 模块/类/函数名 as 别名 或者from 模块名 import 类/函数名 as 别名
  • 比如 : from supermarket import GetMessage as gm 即从supermarket模块中导入GetMessage类, 将该类类名改为gm

p.s. 从模块中导入特定的方法(函数)也是用import关键字, 即from 模块名 import 函数名

从一个模块中导入多个类

  • 可根据需要在程序文件中导入任意数量的类

  • 导入方法和导入单个类一样, 用import关键字, 用,隔开

  • 比如 : from supermarket import Commodity,GetMessage,Pay 导入三个类

  • 导入模块中的所有类 : from 模块名 import *

    • 不建议用这种方法导入
      1. 当类名很多时, 你将不知道你的程序用了哪些类
      2. 有可能导入了一个与程序文件中其他东西同名的类,引发难以察觉的错误
  • 也可以导入整个模块, 直接用import 模块名

    • 需要从一个模块中导入很多类时,最好导入整个模块

    • 使用模块名.类名的方式来访问类

在一个模块中导入另一个模块

  • 当一个模块中的类有依赖的类在另一个模块中, 就需要从另一个模块中导入所依赖的类到这个模块中
  • 最后再将该模块的类导入到主程序中

Tips :

  1. 类名应采用 驼峰命名法 ,即将类名中的每个单词的首字母都大写,而不使用下划线。实例名和模块名都采用小写格式,并在单词之间加上下划线。

  2. 可使用空行来组织代码,但不要滥用。在类中,可使用一个空行来分隔方法;而在模块中,可使用两个空行来分隔类。

  3. 需要同时导入标准库中的模块和你编写的模块时,先编写导入标准库模块的 import 语句,再添加一个空行,然后编写导入你自己编写的模块的 import 语句。在包含多条 import 语句的程序中,这种做法让人更容易明白程序使用的各个模块都来自何方。

举个大栗子:

模仿超市购物, 将商品添加到购物车然后进行结账。

supermarket.py文件

# 商品类
class Commodity():
    def __init__(self,name,price=0.00):
        #定义类的属性, 商品名称, 商品价格, 商品折扣
        self.goodsName = name
        self.price = price
        self.discount=1.00

    def setGoodsName(self,name):
        self.goodsName = name
        print("已将该商品命名为:{}",format(self.goodsName))

    def setPrice(self,price):
        self.price = price
        print("该商品的价格已设为:{:.2f}元".format(self.price))

    def setDiscount(self,discount):
        self.discount = discount
        print("该商品的折扣为{:.2f}".format(self.discount))

# 结账
class Pay():
    def __init__(self):
        self.count = 0.00
        self.dic = {}  # 存放商品的名的列表, key为商品名, num为数量

    def add(self,name,count, num=1): # 添加商品
        # self.dic.__setitem__(name,num) #设置字典的key和value
        if num < 1:
            return False
        count = float(count)
        self.dic.setdefault(name, num) #设置字典的key和value
        now_count = count*num
        self.count += now_count
        print("添加到购物车的商品名为:{} 添加的金额为:{:.2f}".format(name,now_count))

    def sub(self,name,count,num=1):  # 删除商品
        if num < 1:
            return False
        now_count = count*num
        self.count -= now_count
        self.dic.pop(name)
        print("删除购物车的商品名为:{} 应减的金额为:{:.2f}".format(name, now_count))

    def balance(self):  # 结账
        print("账单 : ")
        print("商品名\t数量\t")
        for items in self.dic.items():
            print("{}\t{}\t".format(items[0],items[1]))

        print("需要支付的总金额为:{:.2f}元".format(self.count))

message.py 文件

from supermarket import Commodity
# 当前模块中的类有依赖于supermarket模块中的Commodity类

# 获取商品信息类
class GetMessage(Commodity):
    def __init__(self,name,price=0.00):
        super().__init__(name,price) # 将父类的构造函数中的属性相互关联

    def getName(self):
        try:
            # print("该商品的名称为:{}".format(self.goodsName))
            return self.goodsName
        except:
            print("该商品并没有设置命名")

    def getPrice(self):
        try:
            # print("该商品的价格为{:.2f}元".format(self.price))
            return self.price
        except:
            print("该商品还没有设置价格")

    def getDiscount(self):
        # if self.discount == 1.00:
        #     print("该商品没有打折扣")
        # else:
        #     print("该商品的折扣为{:.2f}".format(self.discount))
        return self.discount

shopping.py

from message import GetMessage as gm
from supermarket import Commodity, Pay

# 添加商品信息
def goods():
    apple = gm("苹果", 2)
    orange = gm("橙子", 3)
    banana = gm("香蕉", 1.5)
    return [apple,orange,banana]



def goodsMessage(ls):
    print("输出商品信息:")
    print("商品名称\t商品价格\t商品折扣\t")
    for item in ls:
        print("{}\t{}\t\t{}\t".format(item.getName(),item.getPrice(),item.getDiscount()))

    print("对应列表索引:")
    num = 0
    for item in ls:
        print("{}\t{}".format(num,item.getName()))
        num+=1

def buy(ls):
    sum = Pay()
    # sum.add(banana.goodsName, banana.price, 3)
    while True:
        a = input("请输入你要添加到购物车的索引:(输入q退出结账)")
        if a == 'q':
            break
        try:
            num = int(a)
            b = int(input("请输入要购买的数量:"))
            sum.add(ls[num].getName(), ls[num].getPrice(), b)
        except:
            print("输入有误,请重新输入")
            continue
    # 最后结账
    sum.balance()

if __name__ == '__main__':
    ls =goods()
    goodsMessage(ls)
    buy(ls)

运行效果 :

输出商品信息:
商品名称	商品价格	商品折扣	
苹果    	2		1.0	
橙子 	3		1.0	
香蕉 	1.5		1.0	
对应列表索引:
0	苹果
1	橙子
2	香蕉
请输入你要添加到购物车的索引:(输入q退出结账)0
请输入要购买的数量:2
添加到购物车的商品名为:苹果 添加的金额为:4.00
请输入你要添加到购物车的索引:(输入q退出结账)1
请输入要购买的数量:3
添加到购物车的商品名为:橙子 添加的金额为:9.00
请输入你要添加到购物车的索引:(输入q退出结账)q
账单 : 
商品名	数量	
苹果	    2	
橙子 	3	
需要支付的总金额为:13.00元

举报

相关推荐

0 条评论