一聚教程网:一个值得你收藏的教程网站

最新下载

热门教程

Python对象与类及方法的详解

时间:2016-08-22 编辑:简简单单 来源:一聚教程网


引言

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


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

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


python中一切皆为对象,所谓对象:我自己就是一个对象,我玩的电脑就是对象,坐着的椅子就是对象,家里养的小狗也是一个对象。。。。。。
 
我们通过描述属性(特征)和行为来描述一个对象的。比如家里的小狗,它的颜色,大小,年龄,体重等是它的属性或特征。它会汪汪叫,会摇尾巴等是它的行为。
我们在描述一个真实对象(物体)时包括两个方面:
它可以做什么(行为)
它是什么样的(属性或特征)。
 
在python中,一个对象的特征也称为属性(attribute)。它所具有的行为也称为方法(method)
结论:对象=属性+方法
 
在python中,把具有相同属性和方法的对象归为一个类(class)
比如人类,动物,植物等等,这些都是类的概念。
 
类是对象的模板或蓝图,类是对象的抽象化,对象是类的实例化。类不代表具体的事物,而对象表示具体的事物。
 
>>> class people:
...     def speak(self):
...             print ("hello!")
...

'''
定义一个people类,定义一个speak方法,但没有定义属性,
因为属性不属于类,而是属于各个类的实例。也就是说属于对象。
因此我们可以给每个实例设置不同的属性
'''   
>>> class people:                    #类   
...     def speak(self):            #方法               
...             print ("hello!")               
...
>>>

>>> jack = people()    #创建jack实例
>>> tom = people()    #创建tom实例
>>> import tab        #导入table键功能模块
>>> jack.            #输入jack.,可以看到以下方法
jack.__class__   jack.__doc__     jack.__module__  jack.speak(     
>>> jack.speak()    #引用speak方法
hello!

>>> jack.age=39            #添加age属性
>>> jack.        #添加height属性
>>> jack.
jack.__class__   jack.__module__  jack.height     
jack.__doc__     jack.age         jack.speak(     
>>> jack.height
120
>>> jack.age
39

'''
#初始化对象
创建类时,可以定义一个特定的方法,名为__init__(),只要创建这个类的一个实例
就会运行这个方法。可以向__init__()方法传递参数,
这样创建对象时就可以把属性设置为你希望的值
__init__()这个方法会在创建对象时完成初始化,

'''
>>> class peo:
...     def __init__(self,name,age,sex):
...             self.Name = name
...             self.Age = age
...             self.Sex = sex
...     def speak(self):
...             print "my name" + self.Name
...
>>>
实例化这个类的对象时:
>>> zhangsan=peo("zhangsan",24,'man')
>>> print zhangsan.Age
24
>>> print zhangsan.Name
zhangsan
>>> print zhangsan.Sex
man

# ----------
>>> print zhangsan
<__main__.peo instance at 0x7fe5041ec248>
'''
要让print能打印出来,就得使用__str__方法
__str__()这个方法告诉python在打印(print)一个对象时,具体显示什么内容
'''
#! /usr/bin/python
class peo:
    def __init__(self,name,age,sex):
        self.Name = name
        self.Age = age
        self.Sex = sex
    def speak(self):
        print "my name" + self.Name
    def __str__(self):
        msg='my name is: ' +self.Name+ ","+ "my age is: " + self.Age +','+ "my sex is:" +self.Sex
        # msg='my name is: ' +self.Name+ ","+ "my age is: " + str(self.Age) +','+ "my sex is:" +self.Sex
        return msg
shanghai=peo('shanghai','23','man')
# shanghai=peo('shanghai',23,'man')
'''
msg='my name is: ' +self.Name+ ","+ "my age is: " + self.Age +','+ "my sex is:" +self.Sex
此处23是年龄,但被转成了字符串,因为self.Age定义的是字符串
    如果不将23转义,则会报错
    如果希望在程序中就事先转义,需要使用str(self.Age)
'''
print shanghai

'''
之前多次用到self这个形参
类就好比是一张蓝图,使用一个类可以创建多个对象实例,
speak()方法在被调用时,必须知道是哪个对象调用了它.
    这里self参数就会告诉方法是哪个对象来调用的.这称为实例引用。
zhangsan。speak()就好比写成了peo.speak(zhangsan)
'''

在上面的文章中,我们定义的字符串,列表,字典等,都是对象,每个对象都有其内置的一些方法,例如对字符串对象使用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] 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

热门栏目