• Python语言和标准库(第三章:类和对象)


    python如何将函数和数据整合在一起,并且通过一个对象的名称访问它们。

    如何和为什么使用类与对象,以及他们如何使编程人员易于多种情形下编写和使用程序。

    3.1考虑编程

    现在要在python中创建一个对对象的描述,您已有足够的只是获得两个视图。第一个是数据视图,除了顶层或者全局作用域的数据外,可以根据需要使用和清除它们。另一个函数视图,他们没有固有的数据,而是操作提供给他们的数据。

    3.1.1对象的含义

    任何一个数据都有对象,每个对象都由3部分组成:标识,类型和值。对象的标识代表该对象在内存中存储的位置(不可改变的),对象的类型表明它可以拥有数据和值的类型,在对象中,可变类型的值可以更改,不可变类型的值不能更改。

    简单些的解释是参考本书中已经介绍的对象。例如,整型,字符串,列表等都是对象。可以在程序中很方便地使用这些对象,但是将关系紧密的对象整合在一起岂不是更有意义?这就是类的由来,类允许定义一组对象,并将他们封装到一个方便的空间去。

    3.1.2已经了解的对象

    3.1.3如何使用对象

    3.2定义类

    当思考包含几百行python代码的小程序如何运行时,经常可以发现程序将数据组织成组的形式——当访问某个数据时,将影响与该数据一起协作的数据。经常会碰到有依赖关系的完整数据列表,如列表1的第一个元素和列表2和列表3中的第一个元素匹配。有时,必须通过创造性地将这些列表组合起来才能解决这个问题。python运用了创建用作占位符的整个类的概念,类起了占位符的作用,当一个类被调用时,它创建了绑定到一个名称的对象。

    3.2.1如何创建对象

    定义一个类

    使用关键字class,在后面紧跟一个名称来完成。

    class Fridge:

    由类创建对象

    >>>f=Fridge()

    此时还没有定义任何复杂的类,Fridge类基本是空的,它作为一个起点。然而,即使他是空的,也应当注意到已经创建了一个可用的空类,它几乎不进行任何操作。

    花上几分钟看_init_和self部分,则是类的两个非常重要的特征,当python创建对象时,_init_方法传递给对象第一个参数。而self实际上是代表该实例本身的变量。

    编写内部方法

    这个内部方法,不能判断当前传入的类型是否有效,应当用接口函数去检测。在允许的每个地方做检查是一个好想法,但在当前这个例子中,不打算在此处检查,因为只会以非常简单的方式使用_add_multi方法。

    编写接口方法

    为了更快捷,现在可以不输入文档字符串,此处的方法使您在遇到问题时,可以更好地理解代码的实际操作。

    这些方法需要缩进在Fridge类的定义中,看上去每行的初始位置开始的任何代码实际上是前一行的延续,应当输入到同一行上:

            def  add_one(self, food_name):
            if type(food_name) != type(""):
                raise TypeError,"add_one requires a string,given a %s"% type
                    (food_name)
            else:
                self._add_multi(food_name,1)
    
            return True
    
    
            def add_many(self, food_dict):
                if type(food_dict) != type({}):
                    raise TypeError("add_many requires a dictionary,got a %s" food_dict)
    
            for item in food_dict.keys():
                self._add_multi(item, food_dict[item])
            return

    add_one和add_many的目的是类似,并且每个方法都有可以确保他们被正确使用的代码,他们都可以使用add-multi来完成主要工作。现在,如果add-multi的工作方式分发生改变,开发人员可以节省时间,因为它将自动改变使用它的两个方法的行为方式。

     现在已经编写了足够的代码,可以把食物放入Frige对象中,但是没有方法可以将放入冰箱的食物拿出来。可以直接访问object.items字典,但是除了测试的时候,这种不是一个好主意。但是现在就是测试,为何不这样做呢?

    >>>f = Fridge({"eggs":6,"milk":4,"cheese":3})
    >>>f.items
    {'cheese':3,'eggs':6,'milk':4}
    >>>f.add_one("grape")
    True
    >>>f.items
    {'cheese':3,'eggs':6,'grape':1,'milk':4}
    >>>f.add_many({"mushroom":5,"tomato":3})
    >>>f.items
    {"tomato":3,'cheese':3,'grape':1,'mushroom':5,'eggs':6,'milk':4}

    目前为止输入的代码都能正常工作了,接下来需要增加可以判断冰箱中是否存在某物的方法。

    编写代码真是某物是否在冰箱中存在很重要,因为它可以用于取出食物的方法中,如get_one,get_many,get_ingredients,从而使这些方法可以检查冰箱中是否有足够多所需的食物,这正是has和has_various方法的用途。

    def has(self,food_name,quantity=1):
        return self.has_various({food_name:quantity})
    
    def has_various({self,foods):
        try:
            for food in foods.keys():
                if self.items[food] < foods[food]:
                    return False
                return True
        except keyError:
                return False

    使用更多的方法:

    现在可以使用python-i或者Run with Interpreter命令调用ch6.py文件,这样可以使用调价到Fridge类的任何代码。如果出现错误而不是>>>提示符,注意抛出的异常,并试图修复缩进问题,拼写错误或者其他基本错误。

    Fridge类可按下述方法使用:

    >>>f = Fridge({"eggs":6,"mike":4,"cheese":3})
    >>>if f.has("cheese",2):
    ...        print("its time to make an omelet")
    ...
    its time to make an omelet

    实例说明:现在已经定义了新的方法,f对象可以使用它们,当用鸡蛋牛奶以及奶酪重新创建f对象时,就从新的fridge类创建对象,因此它拥有新添加的可用方法。

    最后,我们应当讨论从冰箱中取食物的方法了。与向冰箱中添加食物的方法类似,由一个核心方法完成主要工作,所有接口方法都是依赖于这个方法。

    def _get_multi(self,food_name,quantity):
         try:
                if(self.items[food_name] is None):
                    return False;
                if(quantity>self.items[food_name]):
                    return False;
                self.items[food_name] = self.items[food_name]-quantity
        except KeyError:
                return False
        return quantity

    定义后,可以创建文档字符串指定的方法,其中每个方法都是使用_get_multi,因此都可以最少的额外代码从冰箱中取出食物:

    3.2.2对象和它们的作用域

    函数为他们使用的名称创建了自己的空间,也就是作用域。当函数被调用时,声明了名称并赋予值之后,只要函数还在使用,任何对该名称做出的修改会持续下去。然而,在函数结束运行后,并在此被调用,之前电泳过程中所做的工作都丢失了,改函数必须重新开始执行。

    对象中的值可被存储的,并关联在self中,就是说self是指向对象的。

    创建另外一个类:

    我们创建了一个fridge类,现在创建omelet类:

    现在有一个类,它目的很明确。omelet类有接口方法,使得它可与fridge对象协作,它仍具备创建指定煎蛋卷的功能。

    下面代码都必须在omelet类定义下缩进一个级别:

    def _ingredients_(self):
        return self.needed_ingredients
    
    def get_kind(self):
        return self.kind
    
    def set_kind(self,kind):
        possible_ingredients = self._known_kinds(kind)
        if possible_ingredients == False:
            return False
        else:
            self.kind = kind
            self.needed_ingredients = possible_ingredients
    
    def set_new_kind(self,name,ingredients):
          self.kind = name
          self.needed_ingredients = ingredients
           return
    
    def _known_kind(self,kind):
        if kind == "cheese":
            return {"eggs":2,"mike":1,"cheese":1}
        elif kind == "mushroom":
            return {"eggs":2,"mike":1,"cheese":1,"mushroom":2}
         elif kind == "onion":
            return {"eggs":2,"mike":1,"cheese":1,"onion":1}
        else:
            self.kind = kind
            self.needed_ingredients = ingredients
            return
    
    def get_kown_kinds(self,fridge):
         self.from_fridge = fridge.get_ingredients(self)
    
    def mix(self):
         for ingredient in self.from_fridge.keys():
              print("Mixing %d %s for the %s omelet"% self.from_fridge[ingredient],ingredient,self.kind)
         self.mixed = true
    
    def make(self):
         if self.mixed ==true:
            print("cooking the %s omelet!"% self.kind)
            self.cooked = true        

    现在有一个omelet类可以创建omelet对象,omelet类与煎蛋卷的过程有相同的特性。并且Omelet的外在表现集中到几个简单的接口

    现在有两个类,用python -i或者run with Interpreter命令加载他们后,可制作一个煎蛋卷:

    我们还可以制作多个煎蛋卷:

    这样的编程方式,我们称之为面向对象,为什么会用于编制大型系统。

  • 相关阅读:
    策略模式
    装饰模式VS代理模式
    BufferedInputSream实现原理
    从字节码角度分析重载与重写
    函数sprintf真好用
    算法时间复杂度
    二项分布(Binomial Distribution)
    numpy中的tile函数
    图像缩放算法(最临近点插值算法、双线性内插值算法、双立方插值算法)
    C++ 类中成员函数的属性
  • 原文地址:https://www.cnblogs.com/romanhzzz/p/4028748.html
Copyright © 2020-2023  润新知