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 *- 不建议用这种方法导入 
    - 当类名很多时, 你将不知道你的程序用了哪些类
- 有可能导入了一个与程序文件中其他东西同名的类,引发难以察觉的错误
 
 
- 不建议用这种方法导入 
    
-  也可以导入整个模块, 直接用 import 模块名-  需要从一个模块中导入很多类时,最好导入整个模块 
-  使用 模块名.类名的方式来访问类
 
-  
在一个模块中导入另一个模块
- 当一个模块中的类有依赖的类在另一个模块中, 就需要从另一个模块中导入所依赖的类到这个模块中
- 最后再将该模块的类导入到主程序中
Tips :
-  类名应采用 驼峰命名法 ,即将类名中的每个单词的首字母都大写,而不使用下划线。实例名和模块名都采用小写格式,并在单词之间加上下划线。 
-  可使用空行来组织代码,但不要滥用。在类中,可使用一个空行来分隔方法;而在模块中,可使用两个空行来分隔类。 
-  需要同时导入标准库中的模块和你编写的模块时,先编写导入标准库模块的 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元
  










