转载

[Python]-9-对象与类

引言

这篇文章介绍Python如何将函数与数据整合成类,并通过一个对象名称来访问它们。

文章目录

  • 0×1.什么是python中的对象
  • 0×2.python中如何创建类

0×1.什么是python中的对象

Python中每条数据都是对象,每个对象都由三部分组成:标识,数据,类型;

标识是对象的名称,也储存了该对象的内存地址(对象引用),类型规定了这个对象所能储存的值的类型,内存中的某块区域保存了对象的数据值;

在之前的文章中,我们定义的字符串,列表,字典等,都是对象,每个对象都有其内置的一些方法,例如对字符串对象使用len()方法可以求出字符串的长度,我们可以在IDLE中使用dir()方法来查看某个对象可以使用的方法,如下:

>>> s="www.qingsword.com"
					>>> dir(s)
					['__add__', '__class__', '__contains__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getnewargs__', '__gt__', '__hash__', '__init__', '__iter__', '__le__', '__len__', '__lt__', '__mod__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__rmod__', '__rmul__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'capitalize', 'casefold', 'center', 'count', 'encode', 'endswith', 'expandtabs', 'find', 'format', 'format_map', 'index', 'isalnum', 'isalpha', 'isdecimal', 'isdigit', 'isidentifier', 'islower', 'isnumeric', 'isprintable', 'isspace', 'istitle', 'isupper', 'join', 'ljust', 'lower', 'lstrip', 'maketrans', 'partition', 'replace', 'rfind', 'rindex', 'rjust', 'rpartition', 'rsplit', 'rstrip', 'split', 'splitlines', 'startswith', 'strip', 'swapcase', 'title', 'translate', 'upper', 'zfill']

					#上面中括号中的所有输出,以逗号分隔,每一个都是字符串对象可以使用的方法,其中带双下划线的为"内部方法",不带下划线的为"外部方法"也叫"接口函数","内部方法"通常对用户是不可见的,但这并不意味着内部方法就是不可调用的,实际上我们对某个字符串对象使用len()函数的时候,就是调用了其内部的__len__方法,通过下面的实例可以看到,两者的输出是相同的
					>>> print(len(s))
					17
					>>> print(s.__len__())
					17

实际上,我们定义一个字符串对象的时候,python在其内部初始化了一个str类,这个类中包含了python提供的对字符串处理的内置方法,现在这么说可能有点生疏,等大家看完第二段自己手动创建了一个类之后,就会明白上面这些内部方法和接口函数的工作原理了。

0×2.python中如何创建类

python中的类,实际上是完成某个工作的对象和函数的集合,当一个类被调用时,它创建了绑定到一个名称的对象,请看下面的实例,这是一个经典的电冰箱实例,我们假设要创建一个类,用于将食物放入冰箱,查询冰箱中有哪些食物,然后提供取出食物的一系列方法:

#!/usr/bin/env python3
					#coding=utf-8

					########
					class Fridge:
					    """电冰箱类实例"""

					    #--------
					    def __init__(self,items={}):
					        """类初始化"""
					        if type(items)!=type({}):
					            raise TypeError("传入参数错误:%s"%items)
					        self.items=items
					########

					#python使用class关键字来定义一个类,本例定义了一个Fridge类,在这个类中有一个内部方法__init__,每个类都可以包含这个方法,也可以不包含,这个方法的作用是,当使用名称初始化一个Fridge对象时,自动执行__init__函数中的代码,相当于类的初始化操作

					#注意def __init__(self,items={})部分中的self参数,这是python独有的语法,self总是代表类对象本身,这段初始化代码初始化了一个空字典对象,如果不好理解self,可以尝试着将代码中的self省去,然后观察这段函数,实际上__init__就接收一个参数,这个参数必须是一个字典对象,如果省去这个参数,那么默认初始化一个空自字典,并且在Fridge内部使用items对象保存这个字典的数据,但实际情况下self参数不能省略

					#现在我们已经有了一个Fridge类,可以通过下面的方法创建这个类的对象实例,下面的语法没有给Fridge传递参数,所以将初始化一个空的字典,如果想要传递参数,可以这么写p=Fridge({"apple":1,"orange":3}),如果这样,那么Fridge中的items对象就将保存{"apple":1,"orange":3}这个字典
					p=Fridge()

					#现在有一个新的对象p,他是一个完整的Fridge类对象,在上面的创建过程中,Fridge类执行了__init__方法,这将创建一个空的字典对象,可以通过"类实例名称.类对象名称"来访问到这些数据
					print(p.items)

					#输出
					{}

现在,可以给Fridge类添加一系列方法来提供必要的功能了,在Fridge类中补充下面的内容,用于添加查询或删除食物:

#!/usr/bin/env python3
					#coding=utf-8

					########
					class Fridge:
					    """电冰箱类实例"""

					    #--------
					    def __init__(self,items={}):
					        """类初始化"""
					        if type(items)!=type({}):
					            raise TypeError("传入参数错误:%s"%items)
					        self.items=items
					    
					    #--------
					    def __add_multi(self,food_name,quantity):
					        """内部方法,向items字典添加键值,如果food_name不在items字典的键列表中,说明这是一个新添加的食物,将数量初始化为0,然后加上传递给这个函数的quantity的值(可能是一个或者多个)"""
					        if (not food_name in self.items.keys()):
					            self. items[food_name]=0
					        self.items[food_name]=self.items[food_name]+quantity
					    
					    #--------
					    def add_one(self,food_name):
					        """向items字典添加单个食物,这就是一个接口函数,通过调用内部方法__add_multi完成添加食物到冰箱的工作"""
					        if type(food_name)!=type(""):
					            raise TypeError("食物名称类型错误:%s,正确的数据类型:%s"/
					                            %(type(food_name),type("")))
					        else:
					            self.__add_multi(food_name,1)
					        return True
					    
					    #--------
					    def add_many(self,food_dict):
					        """像items字典添加多个食物,这个接口函数接收一个字典参数food_dict,使用for循环遍历这个传递过来的字典中的键名,然后将名称和数量传递给__add_multi函数"""
					        if type(food_dict)!=type({}):
					            raise TypeError("食物名称和数量必须使用字典,错误的数据输入:%s"%food_dict)
					        else:
					            for food_name in food_dict.keys():
					                self.__add_multi(food_name,food_dict[food_name])
					                
					    #--------
					    def has(self,food_name,quantity=1):
					        """查看items中是是否还有某个食物,如果只向这个接口函数传递一个食物名称,那么quantity默认为1,他将调用下面的has_various函数,将食物名称和食物数量传递过去,用于判断冰箱中还有没有这么多的食物"""
					        return self.has_various({food_name:quantity})
					    
					    #--------
					    def has_various(self,foods):
					        """查看食物是否低于输入值,这个接口函数接受一个字典类型的传入参数,通过遍历这个传入的字典中的键名,判断Fridge的items字典中对应键的值是否小于传递进来的这个列表中的每个食物的值,如果小于就返回False,代表冰箱中没有那么多食物了,如果传入的食物名称不存在,会产生一个KeyError异常,同样返回False"""
					        try:
					            for food in foods.keys():
					                if self.items[food]<foods[food]:
					                    return False
					                return True
					        except KeyError:
					            return False
					            
					    #--------
					    def __get_multi(self,food_name,quantity):
					        """取出食物的内部方法,这个方法接受两个值,一个为食物名称,一个为食物数量,第一个if判断冰箱中是否存在这个食物,第二个if调用has()函数将食物名称和数量传递给它,用于判断冰箱中是否还有这么多食物,如果有,则从中取出对应数量的食物,第三个if在刚才取出食物后,判断该食物是否还有库存,如果食物数量为0,则从字典中删除这个食物"""
					        if not food_name in self.items.keys():
					            print("冰箱中并没有这个食物:%s,取出失败"%food_name)
					            return False
					        if self.has(food_name,quantity):
					            self.items[food_name]-=quantity     
					            print("成功取出:%s,数量%s"%(food_name,quantity))
					        if self.items[food_name] == 0:
					            self.items.pop(food_name)
					        return True
					     
					    #--------
					    def get_one(self,food_name):
					        """取出某个食物,调用内部方法__get_multi取出单个食物"""
					        if type(food_name)!=type(""):
					            raise TypeError("食物名称类型错误:%s,正确的数据类型:%s"/
					                                        %(type(food_name),type("")))
					        else:
					            self.__get_multi(food_name, 1)
					        return True
					     
					    #--------
					    def get_many(self,food_dect):
					        """取出多个食物,这个函数接收一个字典参数,for循环遍历这个传入的字典中的键列表,然后判断Fridge类中items字典中这个名称对应的数量是否大于等于传入的这个字典中设置的数量,如果判断成立,表示冰箱中还有足够的食物,调用__get_multi取出这些食物和对应的数量,如果不满足条件,则提示用户,库存补足和现有数量"""
					        if type(food_dect)!=type({}):
					            raise TypeError("食物名称和数量必须使用字典,错误的数据输入:%s"%food_dict)
					        for food in food_dect.keys():
					            if self.items[food]>=food_dect[food]:
					                self.__get_multi(food,food_dect[food])
					            else:
					                print("食材:%s,库存不足,现有数量:%s"%(food,self.items[food])) 
					########       
					
					#初始化Fridge类
					p=Fridge()
					print(p.items)

					#分别调用add函数,像Fridge类添加单个和多个食物
					d={"orange":5,"apple":3}
					p.add_one("banana")
					p.add_many(d)
					print(p.items)

					#如果Fridge中至少有一个orange,取出它
					if p.has("orange"):
					    p.get_one("orange")
					    print(p.items)
					else:
					    print("冰箱里已经没有orange了")
					 
					#如果冰箱中还有5个apple告知用户,如果没有输出现有apple数量
					if p.has("apple",5):
					    print("冰箱里至少还有5个apple")
					else:    
					    print("冰箱里的apple数量:%s"%p.items["apple"])
					
					#判断冰箱中是否有字典中这些食物和数量,如果有取出它们
					if p.has_various({"apple":2,"orange":2,"banana":1}):
					    p.get_many({"apple":2,"orange":2,"banana":1})
					print(p.items)

					#因为冰箱中只有1个banana,刚才已经取出了,所以这里会提示并没有这个食物
					p.get_one("banana")

					#提示库存补足,因为现在只有一个apple在冰箱中
					p.get_many({"apple":3})
					    
					#程序输出
					{}
					{'banana': 1, 'apple': 3, 'orange': 5}
					成功取出:orange,数量1
					{'banana': 1, 'apple': 3, 'orange': 4}
					冰箱里的apple数量:3
					成功取出:banana,数量1
					成功取出:apple,数量2
					成功取出:orange,数量2
					{'apple': 1, 'orange': 2}
					冰箱中并没有这个食物:banana,取出失败
					食材:apple,库存不足,现有数量:1
原文  http://www.qingsword.com/qing/python-9.html
正文到此结束
Loading...