面向对象编程

面向过程:根据业务逻辑从上到下写代码
面向对象:将数据与函数绑定到一起,进行封装,这样能够更快速的开发程序,减少了重复代码的重写过程

类和对象
面向对象编程的2个非常重要的概念:类和对象
对象是面向对象编程的核心在使用对象的过程中,为了将具有共同特征和行为的一组对象抽象定义,提出了另外一个新的概念—类
类就相当于制造飞机时的图纸,用它来进行创建的飞机就相当于对象

类的构成
类(Class) 由3个部分构成(三要素)
类的名称:类名
类的属性:一组数据
类的方法:允许对进行操作的方法 (行为)

<1> 举例:人类设计
事物名称(类名):人(Person) ;类似于函数名
属性:身高(height)、年龄(age) ;类似于变量
方法(行为/功能):跑(run)、打架(fight) ;类似于函数

定义类
定义一个类,格式如下:

class 类名:
      方法列表

demo:定义一个Car类

# 定义类
class Car:
    # 方法
    def getCarInfo(self):
        print('车轮子个数:%d, 颜色%s'%(self.wheelNum, self.color))
    def move(self):
        print("车正在移动...")

说明:
定义类时有2种:新式类和经典类,上面的Car为经典类,如果是Car(object)则为新式类
类名 的命名规则按照”大驼峰”

创建对象

通过上一节课程,定义了一个Car类;就好比有车一个张图纸,那么接下来就应该把图纸交给生成工人们去生成了。python中,可以根据已经定义的类去创建出一个个对象

创建对象的格式为:

对象名 = 类名()

创建对象demo:

# 定义类
class Car:
    # 移动
    def move(self):
        print('车在奔跑...')
    # 鸣笛
    def toot(self):
        print("车在鸣笛...嘟嘟..")

# 创建一个对象,并用变量BMW来保存它的引用
BMW = Car()
#定义属性
BMW.color = '黑色'
BMW.wheelNum = 4 #轮子数量
BMW.move()
BMW.toot()
print(BMW.color)
print(BMW.wheelNum)

总结:
(1)BMW = Car(),这样就产生了一个Car的实例对象,此时也可以通过实例对象BMW来访问属性或者方法
(2)第一次使用BMW.color =’黑色’表示给BMW这个对象添加属性,如果后面再次出现BMW.color = xxx表示对属性进行修改
(3)BMW是一个对象,它拥有属性(数据)和方法(函数)
(4)self 传递对象,类似于c/c++中的this指针
(5)当创建一个对象时,就是用一个模子,来制造一个实物

_init_()方法
<1>使用方式

def 类名:
    #初始化函数,用来完成一些默认的设定
    def __init__():
        pass

<2>init()方法的调用

# 定义汽车类
class Car:
    def __init__(self):
       self.wheelNum = 4
       self.color = '蓝色'
    def move(self):
       print('车在跑,目标:夏威夷')
# 创建对象
BMW = Car()
print('车的颜色为:%s'%BMW.color)
print('车轮胎数量为:%d'%BMW.wheelNum)

总结1
当创建Car对象后,在没有调用init()方法的前提下,BMW就默认拥有了2个属性wheelNum和color,原因是init()方法是在创建对象后,就立刻被默认调用了

想一想
既然在创建完对象后init()方法已经被默认的执行了,那么能否让对象在调用init()方法的时候传递一些参数呢?如果可以,那怎样传递呢?

# 定义汽车类
class Car:
    def __init__(self, newWheelNum, newColor):
        self.wheelNum = newWheelNum
        self.color = newColor
    def move(self):
        print('车在跑,目标:夏威夷')
# 创建对象
BMW = Car(4, 'green')
print('车的颜色为:%s'%BMW.color)
print('车轮子数量为:%d'%BMW.wheelNum)

总结2
(1)init()方法,在创建一个对象时默认被调用,不需要手动调用
(2)init(self)中,默认有1个参数名字为self,如果在创建对象时传递了2个实参,那么init(self)中出了self作为第一个形参外还需要2个形参,例如init(self,x,y)
(3)init(self)中的self参数,不需要开发者传递,python解释器会自动把当前的对象引用传递进去

“魔法”方法
1. 打印id()
如果把BMW使用print进行输出的话,会看到如下的信息即看到的是创建出来的BMW对象在内存中的地址
这里写图片描述

2 . 定义str()方法

    class Car:
           def __init__(self, newWheelNum, newColor):
                  self.wheelNum = newWheelNum
                  self.color = newColor
           def __str__(self):
                  msg = "嘿。。。我的颜色是" + self.color + "我有" + int(self.wheelNum) + "个轮胎..."
                  return msg
           def move(self):
                  print('车在跑,目标:夏威夷')
    BMW = Car(4, "白色")
    print(BMW)

总结
(1)在python中方法名如果是xxxx()的,那么就有特殊的功能,因此叫做“魔法”方法
(2)当使用print输出对象的时候只要自己定义了str(self)方法,那么就会打印从在这个方法中return的数据

应用:烤地瓜

1 . 分析“烤地瓜”的属性和方法

示例属性如下:
(1)cookedLevel : 这是数字;0~3表示还是生的,超过3表示半生不熟,超过5表示已经烤好了,超过8表示已经烤成木炭了!我们的地瓜开始时是生的
(2)cookedString : 这是字符串;描述地瓜的生熟程度
(3)condiments : 这是地瓜的配料列表,比如番茄酱、芥末酱等

示例方法如下:
(1)cook() : 把地瓜烤一段时间
(2)addCondiments() : 给地瓜添加配料
(3)init() : 设置默认的属性
(4)str() : 让print的结果看起来更好一些

2 . 定义类,并且定义init()方法

#定义`地瓜`类
class SweetPotato:
    #定义初始化方法
    def __init__(self):
        self.cookedLevel = 0
        self.cookedString = "生的"
        self.condiments = [] #定义属性为列表可以不断添加数据

3. 添加”烤地瓜”方法

#烤地瓜方法
def cook(self, time):
    self.cookedLevel += time  #时间是不断增加的
    if self.cookedLevel > 8:
        self.cookedString = "烤成灰了"
    elif self.cookedLevel > 5:
        self.cookedString = "烤好了"    
    elif self.cookedLevel > 3:
        self.cookedString = "半生不熟"
    else:
        self.cookedString = "生的"      

4. 基本的功能已经有了一部分,赶紧测试一下
把上面2块代码合并为一个程序后,在代码的下面添加以下代码进行测试

mySweetPotato = SweetPotato()
print(mySweetPotato.cookedLevel)
print(mySweetPotato.cookedString)
print(mySweetPotato.condiments)      

完整的代码为:

class SweetPotato:
   '这是烤地瓜的类'
   #定义初始化方法
   def __init__(self):
       self.cookedLevel = 0
       self.cookedString = "生的"
       self.condiments = []
       #烤地瓜方法
   def cook(self, time):
       self.cookedLevel += time
       if self.cookedLevel > 8:
          self.cookedString = "烤成灰了"
       elif self.cookedLevel > 5:
          self.cookedString = "烤好了"    
       elif self.cookedLevel > 3:
          self.cookedString = "半生不熟"
       else:
          self.cookedString = "生的"

# 用来进行测试
mySweetPotato = SweetPotato()
print(mySweetPotato.cookedLevel)
print(mySweetPotato.cookedString)
print(mySweetPotato.condiments)

5. 测试cook方法是否好用
在上面的代码最后面添加如下代码:

print("------接下来要进行烤地瓜了-----")
mySweetPotato.cook(4) #烤4分钟
print(mySweetPotato.cookedLevel)
print(mySweetPotato.cookedString)    

6. 定义addCondiments()方法和str()方法

def __str__(self):
    msg = self.cookedString + " 地瓜"
    if len(self.condiments) > 0:
        msg = msg + "("
        for temp in self.condiments:
            msg = msg + temp + ", "
        msg = msg.strip(", ")
        msg = msg + ")"
    return msg
def addCondiments(self, condiments):
    self.condiments.append(condiments)      

7. 再次测试
完整的代码如下:

class SweetPotato:
    "这是烤地瓜的类"
    #定义初始化方法
    def __init__(self):
       self.cookedLevel = 0
       self.cookedString = "生的"
       self.condiments = []
   #定制print时的显示内容
    def __str__(self):
        msg = self.cookedString + " 地瓜"
        if len(self.condiments) > 0:
           msg = msg + "("
           for temp in self.condiments:
               msg = msg + temp + ", "
           msg = msg.strip(", ")
           msg = msg + ")"
        return msg

    #烤地瓜方法
    def cook(self, time):
        self.cookedLevel += time
        if self.cookedLevel > 8:
           self.cookedString = "烤成灰了"
        elif self.cookedLevel > 5:
           self.cookedString = "烤好了"    
        elif self.cookedLevel > 3:
            self.cookedString = "半生不熟"
        else:
            self.cookedString = "生的"

    #添加配料
    def addCondiments(self, condiments):
        self.condiments.append(condiments)

# 用来进行测试
mySweetPotato = SweetPotato()
print("------有了一个地瓜,还没有烤-----")
print(mySweetPotato.cookedLevel)
print(mySweetPotato.cookedString)
print(mySweetPotato.condiments)
print("------接下来要进行烤地瓜了-----")
print("------地瓜经烤了4分钟-----")
mySweetPotato.cook(4) #烤4分钟
print(mySweetPotato)
print("------地瓜又经烤了3分钟-----")
mySweetPotato.cook(3) #又烤了3分钟
print(mySweetPotato)
print("------接下来要添加配料-番茄酱------")
mySweetPotato.addCondiments("番茄酱")
print(mySweetPotato)
print("------地瓜又经烤了5分钟-----")
mySweetPotato.cook(5) #又烤了5分钟
print(mySweetPotato)
print("------接下来要添加配料-芥末酱------")
mySweetPotato.addCondiments("芥末酱")
print(mySweetPotato)

隐藏数据
可能你已经意识到,查看过着修改对象的属性(数据),有2种方法
1. 直接通过对象名修改

SweetPotato.cookedLevel = 5

2. 通过方法间接修改

SweetPotato.cook(5)

分析:明明可以使用第1种方法直接修改,为什么还要定义方法来间接修改呢?至少有2个原因:
(1)如果直接修改属性,烤地瓜至少需要修改2部分,即修改cookedLevel和cookedString。而使用方法来修改时,只需要调用一次即可完成
(2)如果直接访问属性,可能会出现一些数据设置错误的情况产生例如cookedLevel = -3。这会使地瓜比以前还生,当然了这也没有任何意义,通过使用方法来进行修改,就可以在方法中进行数据合法性的检查

应用:存放家具

#定义一个home类
class Home:
    def __init__(self, area):
        self.area = area #房间剩余的可用面积
        #self.light = 'on' #灯默认是亮的
        self.containsItem = []
    def __str__(self):
        msg = "当前房间可用面积为:" + str(self.area)
        if len(self.containsItem) > 0:
           msg = msg + " 容纳的物品有: "
           for temp in self.containsItem:
              msg = msg + temp.getName() + ", "
           msg = msg.strip(", ")
        return msg

    #容纳物品
    def accommodateItem(self,item):
        #如果可用面积大于物品的占用面积
        needArea = item.getUsedArea()
        if self.area > needArea:
           self.containsItem.append(item)
           self.area -= needArea
           print("ok:已经存放到房间中")
        else:
           print("err:房间可用面积为:%d,但是当前要存放的物品需要的面积为%d"%(self.area, needArea))


#定义bed类
class Bed:
    def __init__(self,area,name = '床'):
        self.name = name
        self.area = area
    def __str__(self):
        msg = '床的面积为:' + str(self.area)
        return msg
    #获取床的占用面积
    def getUsedArea(self):
        return self.area
    def getName(self):
        return self.name

#创建一个新家对象
newHome = Home(100)#100平米
print(newHome)
#创建一个床对象
newBed = Bed(20)
print(newBed)
#把床安放到家里
newHome.accommodateItem(newBed)
print(newHome)
#创建一个床对象
newBed2 = Bed(30,'席梦思')
print(newBed2)
#把床安放到家里
newHome.accommodateItem(newBed2)
print(newHome)    

这里写图片描述

总结:如果一个对象与另外一个对象有一定的关系,那么一个对象可用是另外一个对象的属性

保护对象的属性
如果有一个对象,当需要对其进行修改属性时,有2种方法

对象名.属性名 = 数据 ---->直接修改
对象名.方法名() ---->间接修改

为了更好的保存属性安全,即不能随意修改,一般的处理方式为
(1)将属性定义为私有属性
(2)添加一个可以调用的方法,供调用

class People(object):
    def __init__(self, name):
        self.__name = name
    def getName(self):
        return self.__name
    def setName(self, newName):
        if len(newName) >= 5:
           self.__name = newName
        else:
           print("error:名字长度需要大于或者等于5")
xiaoming = People("dongGe")
print(xiaoming.__name)

这里写图片描述

class People(object):
    def __init__(self, name):
        self.__name = name
    def getName(self):
        return self.__name
    def setName(self, newName):
        if len(newName) >= 5:
           self.__name = newName
        else:
           print("error:名字长度需要大于或者等于5")

xiaoming = People("dongGe")
#通过对象调用方法设置私有属性
xiaoming.setName("wanger")
#通过对象调用方法获取私有属性
print(xiaoming.getName())
xiaoming.setName("lisi")
print(xiaoming.getName())

总结
(1)Python中没有像C++中public和private这些关键字来区别公有属性和私有属性
(2)它是以属性命名方式来区分,如果在属性名前面加了2个下划线’__’,则表明该属性是私有属性,否则为公有属性(方法也是一样,方法名前面加了2个下划线的话表示该方法是私有的,否则为公有的)。

_del_()方法
创建对象后,python解释器默认调用init()方法;
当删除一个对象时,python解释器也会默认调用一个方法,这个方法为del()方法

import time
class Animal(object):
    # 初始化方法
    # 创建完对象后会自动被调用
    def __init__(self, name):
        print('__init__方法被调用')
        self.__name = name
    # 析构方法
    # 当对象被删除时,会自动被调用
    def __del__(self):
        print("__del__方法被调用")
        print("%s对象马上被干掉了..."%self.__name)

# 创建对象
dog = Animal("哈皮狗")
# 删除对象
del dog
#创建多个对象
cat = Animal("波斯猫")
cat2 = cat
cat3 = cat

print("---马上 删除cat对象")
del cat
print("---马上 删除cat2对象")
del cat2
print("---马上 删除cat3对象")
del cat3
#暂停程序执行2秒
time.sleep(2) 

总结
(1)当有1个变量保存了对象的引用时,此对象的引用计数就会加1
(2)当使用del删除变量指向的对象时,如果对象的引用计数不会1,比如3,那么此时只会让这个引用计数减1,即变为2,当再次调用del时,变为1,如果再调用1次del,此时会真的把对象进行删除

继承介绍以及单继承
1. 继承示例

# 定义一个父类,如下:
class Cat(object):
      def __init__(self, name, color="白色"):
            self.name = name
            self.color = color
     def run(self):
            print("%s--在跑"%self.name)

# 定义一个子类,继承Cat类如下:
class Bosi(Cat):
        def setNewName(self, newName):
               self.name = newName
        def eat(self):
              print("%s--在吃"%self.name)

bs = Bosi("印度猫")
print('bs的名字为:%s'%bs.name)
print('bs的颜色为:%s'%bs.color)
bs.eat()

说明:
虽然子类没有定义init方法,但是父类有,所以在子类继承父类的时候这个方法就被继承了,所以只要创建Bosi的对象,就默认执行了那个继承过来的init方法
总结
(1)子类在继承的时候,在定义类时,小括号()中为父类的名字
(2)父类的属性、方法,会被继承给子类

2 . 注意点

class Animal(object):
    def __init__(self, name='动物', color='白色'):
        self.__name = name
        self.color = color
    def __test(self):
        print(self.__name)
        print(self.color)
    def test(self):
        print(self.__name)
        print(self.color)

class Dog(Animal):
    def dogTest1(self):
        #print(self.__name) #不能访问到父类的私有属性
        print(self.color)
    def dogTest2(self):
        #self.__test() #不能访问父类中的私有方法
        self.test()

A = Animal()
#print(A.__name) #程序出现异常,不能访问私有属性
print(A.color)
#A.__test() #程序出现异常,不能访问私有方法
D = Dog(name = "小花狗", color = "黄色")
D.dogTest1()
D.dogTest2()

(1)私有的属性、方法,不会被子类继承,也不能被访问
(2)一般情况下,私有的属性、方法都是不对外公布的,往往用来做内部的事情,起到安全的作用

多继承
从图中能够看出,所谓多继承,即子类有多个父类,并且具有它们的特征
Python中多继承的格式如下:

# 定义一个父类
class A:
    def printA(self):
        print('----A----')
# 定义一个父类
class B:
    def printB(self):
        print('----B----')

# 定义一个子类,继承自A、B
class C(A,B):
    def printC(self):
        print('----C----')
obj_C = C()
obj_C.printA()
obj_C.printB()

说明
(1)python中是可以多继承的
(2)父类中的方法、属性,子类会继承
想一想:如果在上面的多继承例子中,如果父类A和父类B中,有一个同名的方法,那么通过子类去调用的时候,调用哪个?

重写父类方法与调用父类方法
1. 重写父类方法
所谓重写,就是子类中,有一个和父类相同名字的方法,在子类中的方法会覆盖掉父类中同名的方法

#coding=utf-8
class Cat(object):
    def sayHello(self):
        print("halou-----1")
class Bosi(Cat):
    def sayHello(self):
        print("halou-----2")

bosi = Bosi()
bosi.sayHello()

2. 调用父类的方法

#coding=utf-8
class Cat(object):
    def __init__(self,name):
        self.name = name
        self.color = 'yellow'

class Bosi(Cat):
    def __init__(self,name):
        # 调用父类的__init__方法1,类名调用
        #Cat.__init__(self,name)
        # 调用父类的__init__方法2,super()调用(super指向父类的对象)
        super().__init__(name)
    def getName(self):
        return self.name

bosi = Bosi('xiaohua')
print(bosi.name)
print(bosi.color)    

多态
多态的概念是应用于Java和C#这一类强类型语言中,而Python崇尚“鸭子类型”。
所谓多态:定义时的类型和运行时的类型不一样,此时就成为多态

Python伪代码实现Java或C#的多态

class F1(object):
    def show(self):
        print 'F1.show'
class S1(F1):
    def show(self):
        print 'S1.show'
class S2(F1):
    def show(self):
        print 'S2.show'

# 由于在Java或C#中定义函数参数时,必须指定参数的类型
# 为了让Func函数既可以执行S1对象的show方法,又可以执行S2对象的show方法,所以,定义了一个S1和S2类的父类,而实际传入的参数是:S1对象和S2对象

def Func(F1 obj):
    """Func函数需要接收一个F1类型或者F1子类的类型"""
    print obj.show()

s1_obj = S1()
Func(s1_obj) # 在Func函数中传入S1类的对象 s1_obj,执行 S1 的show方法,结果:
S1.show

s2_obj = S2()
Func(s2_obj) # 在Func函数中传入Ss类的对象 ss_obj,执行 Ss 的show方法,结果:
S2.show

类属性、实例属性
在前面的例子中我们接触到的就是实例属性(对象属性),顾名思义,类属性就是类对象所拥有的属性,它被所有类对象的实例对象所共有,在内存中只存在一个副本,这个和C++中类的静态成员变量有点类似。对于公有的类属性,在类外可以通过类对象和实例对象访问
类属性为所有实例对象共有

class People(object):
    name = 'Tom'  #公有的类属性
    __age = 12     #私有的类属性

p = People()
print(p.name)           #正确,通过实例对象访问类属性
print(People.name)      #正确,通过类对象访问类属性
print(p.__age)          #错误,不能在类外通过实例对象访问私有的类属性
print(People.__age)      #错误,不能在类外通过类对象访问私有的类属性

不同实例对象具有各自的实例属性

class People(object):
    address = '山东' #类属性,定义在类里面方法外面
    def __init__(self):
        self.name = 'xiaowang' #实例属性,定义在方法里面
        self.age = 20 #实例属性
p = People()
p.age =12 #实例属性
print(p.address) #正确,实例对象访问实例属性
print(p.name)    #正确
print(p.age)     #正确
print(People.address) #正确,类对象访问类属性
print(People.name)    #错误,实例对象可以访问实例属性与类属性,但是类对象只能访问类属性

通过实例(对象)去修改类属性

class People(object):
    country = 'china' #类属性
print(People.country)
p = People()
print(p.country)
p.country = 'japan'   #通过实例对象修改类属性
print(p.country)      #实例属性会屏蔽掉同名的类属性
print(People.country)
del p.country         #删除实例属性
print(p.country)  

总结
(1)如果需要在类外修改类属性,必须通过类对象去引用然后进行修改。如果通过实例对象去引用,会产生一个同名的实例属性,这种方式修改的是实例属性,不会影响到类属性,并且之后如果通过实例对象去引用该名称的属性,实例属性会强制屏蔽掉类属性,即引用的是实例属性,除非删除了该实例属性。
(2)修改类属性又三种种方法:一是通过类对象修改类属性;二是通过global关键词声明为类属性在进行修改 ;三是通过类方法修改类属性

静态方法和类方法

1 . 类方法
是类对象所拥有的方法,需要用修饰器@classmethod来标识其为类方法,对于类方法,第一个参数必须是类对象,一般以cls作为第一个参数(当然可以用其他名称的变量作为其第一个参数,但是大部分人都习惯以’cls’作为第一个参数的名字,就最好用’cls’了),能够通过实例对象和类对象去访问。

class People(object):
    country = 'china'
    #类方法,用classmethod来进行修饰
    @classmethod
    def getCountry(cls):
        return cls.country
p = People()
print p.getCountry()       #可以用过实例对象引用
print People.getCountry()  #可以通过类对象引用

类方法还有一个用途就是可以对类属性进行修改:

class People(object):
    country = 'china'
    #类方法,用classmethod来进行修饰
    @classmethod
    def getCountry(cls):
        return cls.country
    @classmethod
    def setCountry(cls,country):
        cls.country = country

p = People()
print p.getCountry()         #可以用过实例对象引用
print People.getCountry()    #可以通过类对象引用
p.setCountry('japan')   
print p.getCountry()   
print People.getCountry()

2. 静态方法
需要通过修饰器@staticmethod来进行修饰,静态方法不需要多定义参数

class People(object):
    country = 'china'
    @staticmethod
    #静态方法
    def getCountry():
        return People.country

print People.getCountry()

总结
从类方法和实例方法以及静态方法的定义形式就可以看出来,类方法的第一个参数是类对象cls,那么通过cls引用的必定是类对象的属性和方法;而实例方法的第一个参数是实例对象self,那么通过self引用的可能是类属性、也有可能是实例属性(这个需要具体分析),不过在存在相同名称的类属性和实例属性的情况下,实例属性优先级更高。静态方法中不需要额外定义参数,因此在静态方法中引用类属性的话,必须通过类对象来引用

练习:设计类
1. 设计一个卖车的4S店,该怎样做呢?

# 定义车类
class Car(object):
     # 定义车的方法
    def move(self):
        print("---车在移动---")
    def stop(self):
        print("---停车---")

# 定义一个销售车的店类
class CarStore(object):
    def order(self):
        self.car = Car() #找一辆车
        self.car.move()
        self.car.stop()

说明
上面的4s店,只能销售那一种类型的车。如果这个是个销售北京现代品牌的车,比如伊兰特、索纳塔等,该怎样做呢?

2 . 设计一个卖北京现代车的4S店

# 定义伊兰特车类
class YilanteCar(object):
    # 定义车的方法
    def move(self):
        print("---车在移动---")
    def stop(self):
        print("---停车---")

# 定义索纳塔车类
class SuonataCar(object):
    # 定义车的方法
    def move(self):
        print("---车在移动---")
    def stop(self):
        print("---停车---")

# 定义一个销售北京现代车的店类
class CarStore(object):
    def order(self, typeName):
        #根据客户的不同要求,生成不同的类型的车
        if typeName == "伊兰特":
            car = YilanteCar()
        elif typeName == "索纳塔":
            car = SuonataCar()
        return car

这样做,不太好,因为当北京现代又生产一种新类型的车时,又得在CarStore类中修改,有没有好的解决办法呢?

工厂模式

1. 简单工厂模式
定义了一个创建对象的接口(可以理解为函数),但由子类决定要实例化的类是哪一个,工厂方法模式让类的实例化推迟到子类,抽象的CarStore提供了一个创建对象的方法createCar,也叫作工厂方法。
子类真正实现这个createCar方法创建出具体产品。 创建者类不需要直到实际创建的产品是哪一个,选择了使用了哪个子类,自然也就决定了实际创建的产品是什么。
在上一节中,最后留下的个问题,该怎样解决呢?

1.1.使用函数实现

# 定义伊兰特车类
class YilanteCar(object):
    # 定义车的方法
    def move(self):
        print("---车在移动---")
    def stop(self):
        print("---停车---")

# 定义索纳塔车类
class SuonataCar(object):
    # 定义车的方法
    def move(self):
        print("---车在移动---")
    def stop(self):
        print("---停车---")

# 用来生成具体的对象--创建对象的接口函数
def createCar(typeName):
    if typeName == "伊兰特":
        car = YilanteCar()
    elif typeName == "索纳塔":
        car = SuonataCar()
    return car

# 定义一个销售北京现代车的店类--工厂类
class CarStore(object):
    def order(self, typeName):
        # 让工厂根据类型,生产一辆汽车
        car = createCar(typeName)
        return car

1.2.使用类来实现

# 定义伊兰特车类
class YilanteCar(object):
    # 定义车的方法
    def move(self):
        print("---车在移动---")
    def stop(self):
        print("---停车---")

# 定义索纳塔车类
class SuonataCar(object):
    # 定义车的方法
    def move(self):
        print("---车在移动---")
    def stop(self):
        print("---停车---")

# 定义一个生产汽车的工厂,让其根据具体的订单生产车--创建对象的接口类
class CarFactory(object):
    def createCar(self,typeName):
        if typeName == "伊兰特":
           car = YilanteCar()
        elif typeName == "索纳塔":
           car = SuonataCar()
        return car

# 定义一个销售北京现代车的店类--工厂类
class CarStore(object):
    def __init__(self):
        #设置4s店的指定生产汽车的工厂
        self.carFactory = CarFactory()

    def order(self, typeName):
        # 让工厂根据类型,生产一辆汽车
        car = self.carFactory.createCar(typeName)
        return car

咋一看来,好像只是把生产环节重新创建了一个类,这确实比较像是一种编程习惯,此种解决方式被称作简单工厂模式
工厂函数、工厂类对具体的生成环节进行了封装,这样有利于代码的后需扩展,即把功能划分的更具体,4s店只负责销售,汽车厂只负责制造

2. 工厂方法模式
多种品牌的汽车4S店
当买车时,有很多种品牌可以选择,比如北京现代、别克、凯迪拉克、特斯拉等,那么此时该怎样进行设计呢?

# 定义一个基本的4S店类
class CarStore(object):
    #仅仅是定义了有这个方法,并没有实现,具体功能,这个需要在子类中实现
    def createCar(self, typeName):
        pass
    def order(self, typeName):
        # 让工厂根据类型,生产一辆汽车
        self.car = self.createCar(typeName)
        self.car.move()
        self.car.stop()

# 定义一个北京现代4S店类
class XiandaiCarStore(CarStore):
    def createCar(self, typeName):
        self.carFactory = CarFactory()
        return self.carFactory.createCar(typeName)

# 定义伊兰特车类
class YilanteCar(object):
    # 定义车的方法
    def move(self):
        print("---车在移动---")
    def stop(self):
        print("---停车---")

# 定义索纳塔车类
class SuonataCar(object):
    # 定义车的方法
    def move(self):
       print("---车在移动---")
    def stop(self):
       print("---停车---")

# 定义一个生产汽车的工厂,让其根据具体得订单生产车
class CarFactory(object):
    def createCar(self,typeName):
       self.typeName = typeName
       if self.typeName == "伊兰特":
          self.car = YilanteCar()
       elif self.typeName == "索纳塔":
          self.car = SuonataCar()
    return self.car
suonata = XiandaiCarStore()
suonata.order("索纳塔")

_new__init_的作用

class A(object):
    def __init__(self):
        print("这是 init 方法")
    def __new__(cls):
        print("这是 new 方法")
        return object.__new__(cls)
A()     

总结
(1)new至少要有一个参数cls,代表要实例化的类,此参数在实例化时由Python解释器自动提供
(2)new必须要有返回值,返回实例化出来的实例,这点在自己实现new时要特别注意,可以return父类new出来的实例,或者直接是object的new出来的实例
(3)init有一个参数self,就是这个new返回的实例,initnew的基础上可以完成一些其它初始化的动作,init不需要返回值
(4)我们可以将类比作制造商,new方法就是前期的原材料购买环节,init方法就是在有原材料的基础上,加工,初始化商品环节

异常
<1>捕获异常 try…except…
<2> try…finally…
在程序中,如果一个段代码必须要执行,即无论异常是否产生都要执行,那么此时就需要使用finally。 比如文件关闭,释放锁,把数据库连接返还给连接池等

import time
try:
    f = open('test.txt')
    try:
        while True:
            content = f.readline()
            if len(content) == 0:
                break
            time.sleep(2)
            print(content)
    except:
        #如果在读取文件的过程中,产生了异常,那么就会捕获到
        #比如 按下了 ctrl+c
        pass
    finally:
        f.close()
        print('关闭文件')
except:
print("没有这个文件")

模块
模块就好比是工具包,要想使用这个工具包中的工具(就好比函数),就需要导入这个模块
在Python中用关键字import来引入某个模块,比如要引用模块math,就可以在文件最开始的地方用import math来引入。形如:

import module1,mudule2...

在调用math模块中的函数时,必须这样引用:

模块名.函数名           

想一想:为什么必须加上模块名调用呢?
因为可能存在这样一种情况:在多个模块中含有相同名称的函数,此时如果只是通过函数名来调用,解释器无法知道到底要调用哪个函数。所以如果像上述这样引入模块的时候,调用函数必须加上模块名

import math
#这样会报错
print sqrt(2)
#这样才能正确输出结果
print math.sqrt(2)

有时候我们只需要用到模块中的某个函数,只需要引入该函数即可,此时可以用下面方法实现:

from 模块名 import 函数名1,函数名2....

如果想一次性引入math中所有的东西,还可以通过from math import *来实现

模块制作
<1>定义自己的模块
在Python中,每个Python文件都可以作为一个模块,模块的名字就是文件的名字。
比如有这样一个文件test.py,在test.py中定义了函数add
test.py

def add(a,b):
    return a+b

<2>调用自己定义的模块
那么在其他文件中就可以先import test,然后通过test.add(a,b)来调用了,当然也可以通过from test import add来引入
main.py

import test
result = test.add(11,22)
print(result)

<3>测试模块
在实际开中,当一个开发人员编写完一个模块后,为了让模块能够在项目中达到想要的效果,这个开发人员会自行在py文件中添加一些测试信息,例如:
test.py

def add(a,b):
    return a+b
# 用来进行测试
ret = add(12,22)
print('int test.py file,,,,12+22=%d'%ret)

如果此时,在其他py文件中引入了此文件的话,想想看,测试的那段代码是否也会执行呢!
main.py

import test
result = test.add(11,22)
print(result)    

这里写图片描述
至此,可发现test.py中的测试代码,应该是单独执行test.py文件时才应该执行的,不应该是其他的文件中引用而执行为了解决这个问题,python在执行一个文件时有个变量name。可以根据name变量的结果能够判断出,是直接执行的python脚本还是被引入执行的,从而能够有选择性的执行测试代码。
这里写图片描述

模块中的_all_
1 . 没有all
这里写图片描述
这里写图片描述
这里写图片描述
2 . 模块中有all
这里写图片描述
这里写图片描述
总结
如果一个文件中有all变量,可以选择哪些模块能被from xxx import *时导入

python中的包

  1. 引入包
    1.1 有2个模块功能有些联系
    这里写图片描述
    1.2 所以将其放到同一个文件夹下
    这里写图片描述
    1.3 使用import 文件.模块 的方式导入
    这里写图片描述
    1.4 使用from 文件夹 import 模块 的方式导入
    这里写图片描述
    1.5 在msg文件夹下创建init.py文件
    这里写图片描述
    1.6 在init.py文件中写入
    这里写图片描述
    1.7 重新使用from 文件夹 import 模块 的方式导入
    这里写图片描述

总结:
(1)包将有联系的模块组织在一起,即放到同一个文件夹下,并且在这个文件夹创建一个名字为init.py 文件,那么这个文件夹就称之为包
(2)有效避免模块名称冲突问题,让应用组织结构更加清晰

2 . _init_.py文件有什么用
init.py 控制着包的导入行为

2.1 init.py为空
仅仅是把这个包导入,不会导入包中的模块

2.2 all
init.py文件中,定义一个all变量,它控制着 from 包名 import *时导入的模块

给程序传参数

import sys
name = sys.argv[1] #sys.argv[0]是程序名
print name

列表推导式
所谓的列表推导式,就是指的轻量级循环创建列表
1 . 基本的方式 (range())
这里写图片描述
2. 在循环的过程中使用if
这里写图片描述
3. 2个for循环
这里写图片描述
set、list、tuple
set是集合类型,集合中的元素不会重复
这里写图片描述
set、list、tuple之间可以相互转换
这里写图片描述
使用set,可以快速的完成对list中的元素去重复的功能

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值