当前位置: 澳门新濠3559 > 操作系统 > 正文

修改代码,面向对象是一种设计思想

时间:2019-11-20 22:05来源:操作系统
保护对象的属性 如果有一个对象,当需要对其进行修改属性时,有2钟方法: 对象名.属性名 = 数据 ----直接修改 对象名.方法名() ----间接修改 为了更好的保存属性的安全,即不能随意修

保护对象的属性

如果有一个对象,当需要对其进行修改属性时,有2钟方法:

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

为了更好的保存属性的安全,即不能随意修改,一般的处理方式为:

  • 将属性定义为私有属性
  • 添加一个可以调用的方法,供调用

    11 class Person(object):
    12 def init(self,name): 13 self.name = name
    14 def getName(self):
    15 return self.
    name
    16 def setName(self,newName): 17 if len(newName)>=5: 18 self.name = newName 19 else:
    20 print('error:名字的长度要大于或者等于5') 21
    22 xiaoming = Person('XIAOYAFEI')
    23 print(xiaoming.
    name)

运行结果为:

Traceback (most recent call last):
  File "test.py", line 23, in <module>
    print(xiaoming.__name)
AttributeError: 'Person' object has no attribute '__name'

修改代码:

 11 class Person(object):    
 12     def __init__(self,name):
 13         self.__name = name
 14     def getName(self):   
 15         return self.__name
 16     def setName(self,newName):
 17         if len(newName)>=5:
 18             self.__name = newName
 19         else:            
 20             print('error:名字的长度要大于或者等于5')
 21                          
 22 xiaoming = Person('XIAOYAFEI')
 23                          
 24 xiaoming.setName("wang") 
 25 print(xiaoming.getName())                                                                           
 26                          
 27 xiaoming.setName('lisisi')
 28 print(xiaoming.getName())

运行结果:

error:名字的长度要大于或者等于5
XIAOYAFEI
lisisi

总结:

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

1.1面向对象编程介绍

__del__方法

创建对象后,python解释器默认调用__init__()方法;

当删除一个对象时,python解释器也会默认调用一个方法,这个方法为__del__()方法

澳门新濠3559 1

总结:

当有1个变量保存了对象的引用时,此对象的引用计数就会加1

当使用del删除变量指向的对象时,如果对象的引用计数不会1,比如3,那么此时只会让这个引用计数减1,即变为2,当再次调用del时,变为1,如果再调用1次del,此时会真的把对象进行删除,__del__会被调用

=

__del__()方法

创建对象后,python解释器默认调用__init__()方法;

当删除一个对象时,python解释器也会默认调用一个方法,这个方法为__del__()方法

  1 #!/usr/bin/python
  2 #coding=utf8 
  3 """          
  4 # Author: xiaoyafei
  5 # Created Time : 2018-04-08 15:28:14
  6              
  7 # File Name: test2.py
  8 # Description:
  9              
 10 """          
 11 import time  
 12 class Animal():
 13     #初始化方法
 14     #创建为对象后会自动被调用
 15     def __init__(self,name):
 16         print('???????__init__方法被调用???????')
 17         self.__name = name
 18              
 19     #析构方法
 20     #当对象被删除时,会自动被调用
 21     def __del__(self):
 22         print('__del__方法被调用')
 23         print('%s对象马上被干掉了......'%self.__name)
 24              
 25 #创建对象    
 26 dog = Animal('嗨皮')
 27 #删除对象    
 28 del dog      
 29              
 30 cat = Animal('波斯猫')
 31 cat2 = cat   
 32 cat3 = cat   
 33              
 34 print('马上删除cat对象')
 35 del cat      
 36 print('马上删除cat1对象')
 37 del cat2     
 38 print('马上删除cat2对象')
 39 del cat3     
 40              
 41 print('程序在2秒钟后结束')
 42 time.sleep(2) 

运行结果如下:

———————__init__方法被调用———————
__del__方法被调用
嗨皮对象马上被干掉了......
———————__init__方法被调用———————
马上删除cat对象
马上删除cat1对象
马上删除cat2对象
__del__方法被调用
波斯猫对象马上被干掉了......
程序在2秒钟后结束

总结:

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

·面向过程:根据业务逻辑从上到下写代码

继承

将共性的内容放在父类中,子类只需要关注自己特有的内容

python中所有的内容都是对象,所有的对象都直接或间接继承了object

在程序中,继承描述的是事物之间的所属关系,例如猫和狗都属于动物,程序中便可以描述为猫和狗继承自动物;同理,波斯猫和巴厘猫都继承自猫,而沙皮狗和斑点狗都继承足够。

说明:

虽然子类没有定义__init__方法,但是父类有,所以在子类继承父类的时候这个方法就被继承了,所以只要创建Bosi的对象,就默认执行了那个继承过来的__init__方法

总结:

子类在继承的时候,在定义类时,小括号()中为父类的名字

父类的属性、方法,会被继承给子类

class Animal:

'''

只是一个关于动物的类

'''

def __init__(self,name,color,breed):

'''

初始化动物的属性

name:动物名字

color:颜色

breed:品种

'''

self.name = name

self.color = color

self.breed = breed

def explain(self):

'''

这是一份关于此类的说明

'''

print('这是一个父类,用于描述动物的共有特征')

class Dog(Animal):

'''

这是一个关于狗的类

'''

def lookHouse(self):

'''

说明狗的用处的方法

'''

print('%s可以看家'%(self.name))

def __str__(self):

'''

打印狗狗的信息

'''

return 'name=%s,color=%s,breed=%s'%(self.name,self.color,self.breed)

class Cat(Animal):

'''

这是一个关于猫的类

'''

def catchMouse(self):

'''

说明猫的用处的方法

'''

print('%s可以捉老鼠'%(self.name))

def __str__(self):

'''

打印猫咪的信息

'''

return 'name=%s,color=%s,breed=%s'%(self.name,self.color,self.breed)

d1 = Dog('大黄','黑色','哈士奇')

d1.lookHouse()

print(d1)

d1.explain()

print('**************************************')

c1 = Cat('小白','白色','波斯猫')

c1.catchMouse()

print(c1)

c1.explain()

澳门新濠3559 2

1.1面向对象

继承

在程序中,继承描述的是事物之间的所属关系,例如猫和狗都属于动物,程序中便可以描述为狗和猫继承自动物;同理,波斯猫和巴厘猫都继承自猫,而沙皮狗和斑点狗都继承自狗

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

私有属性

私有的属性,不能通过对象直接访问,但是可以通过方法访问

私有的方法,不能通过对象直接访问

私有的属性、方法,不会被子类继承,也不能被访问

一般情况下,私有的属性、方法都是不对外公布的,往往用来做内部的事情,起到安全的作用

澳门新濠3559 3

面向对象(object-oriented ;简称: OO)至今还没有统一的概念 我这里把它定义为:按人们 认识客观世界的系统思维方式,采用基于对象(实体)的概念建立模型,模拟客观世界分析、设 计、实现软件的办法。

继承示例

#!/usr/bin/python
#coding=utf8
"""
# Author: xiaoyafei
# Created Time : 2018-04-04 11:35:02

# File Name: 03-单继承.py
# Description:

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


#定义一个子类,来继承Cat类
class Bosi(Cat):

    def __str__(self):
        return self.name
    def setNewName(self,newName):
        self.name = newName
    def eat(self):
        print("%s------在吃"%self.name)

bs = Bosi("lipeng")
bs.run()
bs.setNewName("小明")
print(bs)

运行结果为:

lipeng------在跑
小明

说明:

  •   虽然子类没有定义__init__方法,但是父类有,所以在子类继承父类的时候这个方法就被继承了,所以只要创建Bosi对象,就默认执行了那个继承过来的父类的__init__方法

总结:

  •   子类在继承的时候,在定义类时,小括号()中为父类的名字
  •    父类的属性、方法,会被继承给子类

面向过程的思路是将数据与函数按照执行的逻辑顺序组织在一起,数据与函数分开考虑。

单继承,覆盖

单继承就是一个子类只继承一个父类

澳门新濠3559 4

澳门新濠3559 5

面向对象编程(Object Oriented Programming-OOP)是一种解决软件复用的设计和编程方法。 这种方法把软件系统中相近相似的操作逻辑和操作 应用数据、状态,以类的型式描述出来,以对象实例的形式在软件系统中复用,以达到提高软件开发效率的作用。

注意点

  1 #!/usr/bin/python
  2 #coding=utf8
  3 """
  4 # Author: xiaoyafei
  5 # Created Time : 2018-04-08 15:45:07
  6  
  7 # File Name: 04-单继承-注意点.py
  8 # Description:
  9  
 10 """
 11 class Animal():
 12     def __init__(self,name='动物',color='白色'):
 13         self.__name = name
 14         self.color = color
 15     def __test(self):
 16         print(self.__name)
 17         print(self.color)
 18     def test(self):
 19         print(self.__name)
 20         print(self.color)
 21  
 22 class Dog(Animal):
 23     def dogTest1(self):
 24         #print(self.__name)
 25         print(self.color)
 26     def dogTest2(self):
 27         #self.__test()
 28         self.test()
 29  
 30 A = Animal()
 31 #print(A.__name)         #程序出现异常,不能直接访问私有属性
 32 print(A.color)
 33 #A.__test()          #程序出现异常,不能直接访问私有方法                                                                                                                                                                                                          
 34 A.test()
 35  
 36 print('----------------------------华丽的分割线----------------------------------')
 37 D = Dog(name = '小花狗',color = '黄色')
 38 D.dogTest1()
 39 D.dogTest2()
  • 私有的属性,不能通过对象直接访问,但是可以通过方法访问
  • 私有的方法,不能通过对象直接访问
  • 私有的属性、方法,不会被子类继承,也不能给访问
  • 一般情况下,私有的属性、方法都是不对外公布的,往往来做内部的事情,起到安全的作用

def发送邮件(内容)

多继承

多继承,即子类有多个父类,并且具有它们的特征

澳门新濠3559 6

修改代码,面向对象是一种设计思想。面向对象的理解:

多继承

所谓多继承,即子类有多个父类,并且具有它们的特征

python中多继承的格式如下:

 14 class a():
 15     def printA(self):
 16         print('-aaaaaaaaaaaaa')
 17      
 18 class b():
 19     def printB(self):
 20         print('------------b')
 21       
 22      
 23 class c(a,b):
 24     def printC(self):
 25         print('-cccccccccccccccccc')
 26      
 27 c  =  c()
 28 c.printA()
 29 c.printB()
 30 c.printC()

运行结果如下:

-aaaaaaaaaaaaa
------------b
-cccccccccccccccccc

说明:

  • python中是可以多继承的
  • 父类中的方法、属性,子类会继承

#发送邮件提醒

多态

什么是封装?

类是一种封装,将属性和方法封装。

函数也是一种封装,将具有一定共的逻辑代码封装到一个函数中,使用的时候调用即可

提高代码的扩展性。

什么是继承?

将公共的(共性的)属性和方法放在父类中,子类只关注自己特有的属性和方法。

提高代码的扩展性。

什么是多态?

一个对象在不同的情况下,具有不同的形态,用于强类型语言。是使用在继承和接口中实现。

Python中有两种说法:

1、python支持多态,python是一个弱类型,本身一个变量名,可以存储任何类型的值,可以理解为多种形态

2、python不支持多态,多态本身是用于强类型语言的,python是一个弱类型,所以不支持多态

所谓多态:定义时的类型和运行时的类型不一样,此时就成为多态

澳门新濠3559 7

python是一种弱类型语言,没有类型限制。

变量的类型永远是通过右侧的值判断的。

方法中的参数,传递任何值都行。但是要考虑方法内部的业务逻辑。

多态:

1、父类作为参数,可以传递父类和子类对象

2、接口作为参数,只能传递实现对象

所以有两种理解:

1、python不支持多态:

python是弱类型,没有类型限定,无法区分父和子,或者说接口和实现类

2、python处处是多态

python是弱类型,没有类型限定,传递任何内容都行

面向对象是一种设计思想

多继承-注意点

  1 #!/usr/bin/python
  2 #coding=utf8
  3 """  
  4 # Author: xiaoyafei
  5 # Created Time : 2018-04-04 14:29:20
  6      
  7 # File Name: 06-多继承注意点.py
  8 # Description:
  9     在多个父类中拥有相同的方法应该调用哪一个???
 10      
 11     可以使用__mro__方法去查看调用顺序                                                                                                                                                                                                                             
 12 """  
 13      
 14 class A():
 15     def printA(self):
 16         print('aaaaaaaaaaaaaaaaaa')
 17 class B():
 18      def printA(self):
 19          print('bbbbbbbbbbbbbbbbb')
 20      
 21 class S(A,B):
 22     def printS(self):
 23         print('SSSSSSSSSSSSSSSSSS')
 24      
 25 zi = S()
 26 zi.printS()
 27 zi. printA()
 28 print(S.__mro__)    #可以查看C类的对象搜索方法时的先后顺序

运行结果:

SSSSSSSSSSSSSSSSSS
aaaaaaaaaaaaaaaaaa
(<class '__main__.S'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>)

连接邮箱服务器

实例属性

在方法里通过self.属性 都是实例属性

澳门新濠3559 8

1.符合人们的思考习惯

重写父类方法和调用父类方法

发送邮件

类属性

直接在类中定义的,与方法平齐,不在方法里的属性就是 类属性

澳门新濠3559 9

2.把执行者变成指挥者

重写父类方法

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

 13 class Cat():
 14     def sayHello(self):
 15         print('Hello----1')                                                                                                                                                                                                                                       
 16          
 17 class Bosi(Cat):
 18     def sayHello(self):
 19         print('Hello----4')
 20 bosi = Bosi()
 21 bosi.sayHello()

运行结果如下:

Hello----4

关闭连接

类方法

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

澳门新濠3559 10

3.简化功能,把复杂的事情简单化

调用父类方法

  1 #!/usr/bin/python
  2 #coding=utf8
  3 """
  4 # Author: xiaoyafei
  5 # Created Time : 2018-04-08 17:28:14
  6  
  7 # File Name: 08-调用父类的方法-1.py
  8 # Description:
  9  
 10 """
 11 class Cat():
 12     def __init__(self,name):
 13         self.name = name
 14         self.color = 'yellow'
 15      
 16 class Bosi(Cat):
 17     def __init__(self,name):
 18         super().__init__(name)
 19  
 20     def getName(self):
 21         return self.name
 22  
 23 bosi = Bosi('波斯猫')
 24 print(bosi.name)                                                                                                                                                                                                                                                  
 25 print(bosi.color)

运行结果如下:

波斯猫
yellow

super()不是父类,而是继承顺序的下一个类

在多重继承是会涉及到继承顺序,super()相当于返回继承顺序的下一个类,而不是父类

while True:

静态方法

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

澳门新濠3559 11

总结:

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

面向对象有三大特征:

多态

多态的概念是应用于Java和c#这一类强语言中,而python崇尚"鸭子类型"

所谓多态:定义时的类型和运行时的类型不一样,此时就形成了多态

python鸭子类型代码:

 12 class F1(object):
 13     def show(self):
 14         print('F1.show')
 15 class S1(F1):
 16     def show(self):
 17         print('S1.show')
 18 class S2(F1):
 19     def show(self):
 20         print('S2.show')
 21  
 22 def Func(obj):
 23     print(obj.show())
 24  
 25 s1_obj = S1()
 26 Func(s1_obj)
 27  
 28 s2_obj = S2()
 29 Func(s2_obj)   

 

if cpu利用率> 90%:

1.封装

发送邮件('CPU报警')

2.继承

if硬盘使用空间> 90%:

3.多态

发送邮件('硬盘报警')

1.2类和对象

if内存占用> 80%:

面向对象编程的2个非常重要的概念:类和对象

发送邮件('内存报警')

对象是面向对象编程的核心,在使用对象的过程中,为了将具有共同特征和行为的一组对象抽象定义,提出了另外一个新的概念——类

面向对象编程(Object Oriented Programming,OOP,面向对象程序设计)

类就相当于制造飞机时的图纸,用它来进行创建的飞机就相当于对象

面向对象(object-oriented ;简称: OO)指按人们认识客观世界的系统思维方式,采用基于对象(实体)的概念建立模型,模拟客观世界分析、设计、实现软件的办法。

类是对事务的描述,是抽象的。

面向对象编程(Object Oriented Programming-OOP)是一种解决软件复用的设计和编程方法。这种方法把软件系统中相近相似的操作逻辑和操作应用数据、状态,以类的型式描述出来,以对象实例的形式在软件系统中复用,以达到提高软件开发效率的作用。

对象是类的具体体现。

面向对象的理解:

1.2.1  类

面向对象是一种设计思想

人以类聚物以群分。

1.符合人们的思考习惯

具有相似内部状态和运动规律的实体的集合(或统称为抽象)。

2.把执行者变成指挥者

具有相同属性和行为事物的统称

3.简化功能,把复杂的事情简单化

类是抽象的,在使用的时候通常会找到这个类的一个具体的存在,使用这个具体的存在。一个类可以找到多个对象

面向对象有三大特征:

1.2.2 对象

1.封装

某一个具体事物的存在,在现实世界中可以是看得见摸得着的。

2.继承

可以是直接使用的

3.多态

1.2.3 类和对象的关系

1.2类和对象

类>=对象

对象是面向对象编程的核心,在使用对象的过程中,为了将具有共同特征和行为的一组对象抽象定义,提出了另外一个新的概念——类

1.2.4 练习区分类和对象

类是对事务的描述,是抽象的。

奔驰汽车类

对象是类的具体体现。

奔驰smart类

1.2.1类

张三的那辆奔驰smart对象

类:

狗类

具有相似内部状态和运动规律的实体的集合(或统称为抽象)。

大黄狗类

具有相同属性和行为事物的统称

李四家那只大黄狗对象

类是抽象的,在使用的时候通常会找到这个类的一个具体的存在,使用这个具体的存在。一个类可以找到多个对象

水果类

1.2.2对象

苹果类

澳门新濠3559,对象:

红苹果类红富士苹果类

某一个具体事物的存在,在现实世界中可以是看得见摸得着的。

我嘴里吃了一半的苹果对象

可以是直接使用的

1.2.5 类的构成

1.2.3类和对象之间的关系

类(Class)由3个部分构成

类就是创建对象的模板

·类的名称:类名

1.2.4类的构成

·类的属性:一组数据成员变量

类(Class)由3个部分构成

·类的方法:允许对进行操作的方法(行为)成员方法

·类的名称:类名

举例:

·类的属性:一组数据成员变量

1)人类设计,只关心3样东西:

·类的方法:允许对进行操作的方法(行为)成员方法

·事物名称(类名):人(Person)

1.2.5类的抽象

·属性:身高(height)、年龄(age)

拥有相同(或者类似)属性和行为的对象都可以抽像出一个类

·方法(行为/功能):跑(run)、打架(fight)

方法:一般名词都是类(名词提炼法)

2)狗类的设计

1.3定义类

·类名:狗(Dog)

定义一个类,格式如下:

·属性:品种 、毛色、性别、名字、 腿儿的数量

class类名:

·方法(行为/功能):叫 、跑、咬人、吃、摇尾巴

方法列表

1.2.6 类的抽象

demo:定义一个Car类

如何把日常生活中的事物抽象成程序中的类?

#定义类

拥有相同(或者类似)属性和行为的对象都可以抽像出一个类

classCar:

方法:一般名词都是类(名词提炼法)

#方法

<1>坦克发射3颗炮弹轰掉了2架飞机

defgetCarInfo(self):

·坦克--》可以抽象成 类

print('车轮子个数:%d,颜色%s'%(self.wheelNum, self.color))

·炮弹--》可以抽象成类

defmove(self):

·飞机-》可以抽象成类

print("车正在移动...")

<2>小明在公车上牵着一条叼着热狗的狗

说明:

·小明--》 人类

·定义类时有2种:新式类和经典类,上面的Car为经典类,如果是Car(object)则为新式类

·公车--》 交通工具类

·类名的命名规则按照"大驼峰"

·热狗--》 食物类

1.4创建对象

·狗--》 狗类

创建对象的格式为:

1.3 定义类

对象名=类名()

定义一个类,格式如下:

创建对象demo:

class类名:

#定义类

方法列表

classCar:

demo:定义一个Car类

#移动

#定义类

defmove(self):

classCar:

print('车在奔跑...')

#方法

#鸣笛

defgetCarInfo(self):

deftoot(self):

print('车轮子个数:%d,颜色%s'%(self.wheelNum, self.color))

print("车在鸣笛...嘟嘟..")

defmove(self):

#创建一个对象,并用变量BMW来保存它的引用

print("车正在移动...")

BMW = Car()

说明:

BMW.color ='黑色'

·定义类时有2种:新式类和经典类,上面的Car为经典类,如果是Car(object)则为新式类

BMW.wheelNum =4#轮子数量

·类名的命名规则按照"大驼峰"

BMW.move()

1.4  创建对象

BMW.toot()

通过上一节课程,定义了一个Car类;就好比有车一个张图纸,那么接下来就应该把图纸交给生成工人们去生成了

print(BMW.color)

python中,可以根据已经定义的类去创建出一个个对象

print(BMW.wheelNum)

创建对象的格式为:

总结:

对象名=类名()

·BMW = Car(),这样就产生了一个Car的实例对象,此时也可以通过实例对象BMW来访问属性或者方法

创建对象demo:

·第一次使用BMW.color

#定义类

= '黑色'表示给BMW这个对象添加属性,如果后面再次出现BMW.color = xxx表示对属性进行修改

classCar:

·BMW是一个对象,它拥有属性(数据)和方法(函数)

#移动

·当创建一个对象时,就是用一个模子,来制造一个实物

defmove(self):

1.5__init__()方法

print('车在奔跑...')

在创建对象的时候,直接设置对象的属性。

#鸣笛

1.5.1使用方式

deftoot(self):

def类名:

print("车在鸣笛...嘟嘟..")

#初始化函数,用来完成一些默认的设定

#创建一个对象,并用变量BMW来保存它的引用

def__init__():

BMW = Car()

pass

BMW.color ='黑色'

1.5.2__init__()方法的调用

BMW.wheelNum =4#轮子数量

#定义汽车类

BMW.move()

classCar:

BMW.toot()

def__init__(self):

print(BMW.color)

self.wheelNum =4

print(BMW.wheelNum)

self.color ='蓝色'

总结:

defmove(self):

·BMW = Car(),这样就产生了一个Car的实例对象,此时也可以通过实例对象BMW来访问属性或者方法

print('车在跑,目标:夏威夷')

·第一次使用BMW.color = '黑色'表示给BMW这个对象添加属性,如果后面再次出现BMW.color = xxx表示对属性进行修改

#创建对象

·BMW是一个对象,它拥有属性(数据)和方法(函数)

BMW = Car()

·当创建一个对象时,就是用一个模子,来制造一个实物

print('车的颜色为:%s'%BMW.color)

1.5 __init__()方法

print('车轮胎数量为:%d'%BMW.wheelNum)

在上一小节的demo中,我们已经给BMW这个对象添加了2个属性,wheelNum(车的轮胎数量)以及color(车的颜色),试想如果再次创建一个对象的话,肯定也需要进行添加属性,显然这样做很费事,那么有没有办法能够在创建对象的时候,就顺便把车这个对象的属性给设置呢?

1.5.3总结1

答:__init__()方法

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

在java里叫构造方法

调用__init__()方法时传参:

1.5.1 使用方法

#定义汽车类

def类名:

classCar:

#初始化函数,用来完成一些默认的设定

def__init__(self, newWheelNum, newColor):

def__init__():

self.wheelNum = newWheelNum

pass

self.color = newColor

1.5.2 __init__()方法的调用

defmove(self):

#定义汽车类

print('车在跑,目标:夏威夷')

classCar:

#创建对象

def__init__(self):

BMW = Car(4,'green')

self.wheelNum =4

print('车的颜色为:%s'%BMW.color)

self.color ='蓝色'

print('车轮子数量为:%d'%BMW.wheelNum)

defmove(self):

1.5.4总结2

print('车在跑,目标:夏威夷')

·__init__()方法,在创建一个对象时默认被调用,不需要手动调用

#创建对象

·__init__(self)中,默认有1个参数名字为self,如果在创建对象时传递了2个实参,那么__init__(self)中出了self作为第一个形参外还需要2个形参,例如__init__(self,x,y)

BMW = Car()

·__init__(self)中的self参数,不需要开发者传递,python解释器会自动把当前的对象引用传递进去

print('车的颜色为:%s'%BMW.color)

1.6"魔法"方法

print('车轮胎数量为:%d'%BMW.wheelNum)

1.6.1打印id()

1.5.3 总结

print(对象名)

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

1.6.2定义__str__()方法

想一想

classCar:

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

def__init__(self, newWheelNum, newColor):

#定义汽车类

self.wheelNum = newWheelNum

classCar:

self.color = newColor

def__init__(self, newWheelNum, newColor):

def__str__(self):

self.wheelNum = newWheelNum

msg ="嘿。。。我的颜色是"+ self.color +"我有"+ int(self.wheelNum) +"个轮胎..."

self.color = newColor

returnmsg

defmove(self):

defmove(self):

print('车在跑,目标:夏威夷')

print('车在跑,目标:夏威夷')

#创建对象

BMW = Car(4,"白色")

BMW = Car(4,'green')

print(BMW)

print('车的颜色为:%s'%BMW.color)

1.6.3总结

print('车轮子数量为:%d'%BMW.wheelNum)

·在python中方法名如果是__xxxx__()的,那么就有特殊的功能,因此叫做“魔法”方法

1.5.4  总结2

·当使用print输出对象的时候,只要自己定义了__str__(self)方法,那么就会打印从在这个方法中return的数据

·__init__()方法,在创建一个对象时默认被调用,不需要手动调用

·

·__init__(self)中,默认有1个参数名字为self,如果在创建对象时传递了2个实参,那么__init__(self)中出了self作为第一个形参外还需要2个形参,例如__init__(self,x,y)

1.7self

·__init__(self)中的self参数,不需要开发者传递,python解释器会自动把当前的对象引用传递进去

1.7.1理解self

1.6 应用:创建多个对象

示例:

·根据上两节创建一个Car类

#定义一个类

·创建出多个汽车对象,比如BMW、AUDI等

classAnimal:

1.7 ‘魔法方法’

#方法

1.7.1 定义__str__()的方法

def__init__(self, name):

classCar:

self.name = name

def__init__(self, newWheelNum, newColor):

defprintName(self):

self.wheelNum = newWheelNum

print('名字为:%s'%self.name)

self.color = newColor

#定义一个函数

def__str__(self):

defmyPrint(animal):

msg ="嘿。。。我的颜色是"+ self.color +"我有"+ int(self.wheelNum) +"个轮胎..."

animal.printName()

returnmsg

dog1 = Animal('西西')

defmove(self):

myPrint(dog1)

print('车在跑,目标:夏威夷')

dog2 = Animal('北北')

BMW = Car(4,"白色")

myPrint(dog2)

print(BMW)

self表示是当前对象

1.7.2 总结

1.7.2总结

·在python中方法名如果是__xxxx__()的,那么就有特殊的功能,因此叫做“魔法”方法

·所谓的self,可以理解为自己

·当使用print输出对象的时候,只要自己定义了__str__(self)方法,那么就会打印从在这个方法中return的数据

·可以把self当做C++中类里面的this指针一样理解,就是对象自身的意思

1.8.1 理解self

·某个对象调用其方法时,python解释器会把这个对象作为第一个参数传递给self,所以开发者只需要传递后面的参数即可

看如下示例:

1.8保护对象的属性

#定义一个类

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

classAnimal:

·对象名.属性名=数据---->直接修改

#方法

·对象名.方法名() ---->间接修改

def__init__(self, name):

为了更好的保存属性安全,即不能随意修改,一般的处理方式为

self.name = name

·将属性定义为私有属性

defprintName(self):

·添加一个可以调用的方法,供调用

print('名字为:%s'%self.name)

classPeople(object):

#定义一个函数

def__init__(self, name):

defmyPrint(animal):

self.__name = name

animal.printName()

defgetName(self):

dog1 = Animal('西西')

returnself.__name

myPrint(dog1)

defsetName(self, newName):

dog2 = Animal('北北')

iflen(newName) >=5:

myPrint(dog2)

self.__name = newName

1.8.2 总结

else:

·所谓的self,可以理解为自己

print("error:名字长度需要大于或者等于5")

·可以把self当做C++中类里面的this指针一样理解,就是对象自身的意思

xiaoming = People("xx")

·某个对象调用其方法时,python解释器会把这个对象作为第一个参数传递给self,所以开发者只需要传递后面的参数即可

print(xiaoming.__name)

1.9 应用:烤地瓜

classPeople(object):

1.9.1 分析烤地瓜的属性和方法

def__init__(self, name):

示例属性如下:

self.__name = name

·cookedLevel :这是数字;0~3表示还是生的,超过3表示半生不熟,超过5表示已经烤好了,超过8表示已经烤成木炭了!我们的地瓜开始时时生的

defgetName(self):

·cookedString :这是字符串;描述地瓜的生熟程度

returnself.__name

·condiments :这是地瓜的配料列表,比如番茄酱、芥末酱等

defsetName(self, newName):

示例方法如下:

iflen(newName) >=5:

·cook():把地瓜烤一段时间

self.__name = newName

·addCondiments():给地瓜添加配料

else:

·__init__():设置默认的属性

print("error:名字长度需要大于或者等于5")

·__str__():让print的结果看起来更好一些

xiaoming = People("xx")

1.9.2定义类,并且定义__init__()方法

xiaoming.setName("yy")

#定义`地瓜`类

print(xiaoming.getName())

classSweetPotato:

xiaoming.setName("lisi")

'这是烤地瓜的类'

print(xiaoming.getName())

#定义初始化方法

总结

def__init__(self):

·Python中没有像关键字来区别公有属性和私有属性

self.cookedLevel =0

·它是以属性命名方式来区分,如果在属性名前面加了2个下划线'__',则表明该属性是私有属性,否则为公有属性(方法也是一样,方法名前面加了2个下划线的话表示该方法是私有的,否则为公有的)。

self.cookedString ="生的"

1.9__del__()方法

self.condiments = []

创建对象后,python解释器默认调用__init__()方法;

1.9.3 添加‘烤地瓜’的方法

当删除一个对象时,python解释器也会默认调用一个方法,这个方法为__del__()方法

#烤地瓜方法

importtime

defcook(self, time):

classAnimal(object):

self.cookedLevel += time

#初始化方法

ifself.cookedLevel >8:

#创建完对象后会自动被调用

self.cookedString ="烤成灰了"

def__init__(self, name):

elifself.cookedLevel >5:

print('__init__方法被调用')

self.cookedString ="烤好了"

self.__name = name

elifself.cookedLevel >3:

#析构方法

self.cookedString ="半生不熟"

#当对象被删除时,会自动被调用

else:

def__del__(self):

self.cookedString ="生的"

print("__del__方法被调用")

1.9.4 测试

print("%s对象马上被干掉了..."%self.__name)

把上面2块代码合并为一个程序后,在代码的下面添加以下代码进行测试

#创建对象

mySweetPotato = SweetPotato()

dog = Animal("哈皮狗")

print(mySweetPotato.cookedLevel)

#删除对象

print(mySweetPotato.cookedString)

deldog

print(mySweetPotato.condiments)

cat = Animal("波斯猫")

完整的代码为:

cat2 = cat

classSweetPotato:

cat3 = cat

'这是烤地瓜的类'

print("---马上删除cat对象")

#定义初始化方法

delcat

def__init__(self):

print("---马上删除cat2对象")

self.cookedLevel =0

delcat2

self.cookedString ="生的"

print("---马上删除cat3对象")

self.condiments = []

delcat3

#烤地瓜方法

print("程序2秒钟后结束")

defcook(self, time):

time.sleep(2)

self.cookedLevel += time

总结

ifself.cookedLevel >8:

·当有1个变量保存了对象的引用时,此对象的引用计数就会加1

self.cookedString ="烤成灰了"

·当使用del删除变量指向的对象时,如果对象的引用计数不会1,比如3,那么此时只会让这个引用计数减1,即变为2,当再次调用del时,变为1,如果再调用1次del,此时会真的把对象进行删除,__del__会被调用

elifself.cookedLevel >5:

1.10继承介绍以及单继承

self.cookedString ="烤好了"

为什么要继承:

elifself.cookedLevel >3:

将共性的内容放在父类中,子类只需要关注自己特有的内容

self.cookedString ="半生不熟"

1.10.1继承的概念

else:

继承描述的是事物之间的所属关系。

self.cookedString ="生的"

1.10.2继承示例

#用来进行测试

#定义一个父类,如下:

mySweetPotato = SweetPotato()

classCat(object):

print(mySweetPotato.cookedLevel)

def__init__(self, name, color="白色"):

print(mySweetPotato.cookedString)

self.name = name

print(mySweetPotato.condiments)

self.color = color

1.9.5 测试cook的方法是否好用

defrun(self):

在上面的代码最后面添加如下代码:

print("%s--在跑"%self.name)

print("------接下来要进行烤地瓜了-----")

#定义一个子类,继承Cat类如下:

mySweetPotato.cook(4)#烤4分钟

classBosi(Cat):

print(mySweetPotato.cookedLevel)

defsetNewName(self, newName):

print(mySweetPotato.cookedString)

self.name = newName

1.9.6 定义addCondiments()方法和__str__()方法

defeat(self):

def__str__(self):

print("%s--在吃"%self.name)

msg = self.cookedString +"地瓜"

bs = Bosi("印度猫")

iflen(self.condiments) >0:

print('bs的名字为:%s'%bs.name)

msg = msg +"("

print('bs的颜色为:%s'%bs.color)

fortempinself.condiments:

bs.eat()

msg = msg + temp +", "

bs.setNewName('波斯')

msg = msg.strip(", ")

bs.run()

msg = msg +")"

说明:

returnmsg

·虽然子类没有定义__init__方法,但是父类有,所以在子类继承父类的时候这个方法就被继承了,所以只要创建Bosi的对象,就默认执行了那个继承过来的__init__方法

defaddCondiments(self, condiments):

总结

self.condiments.append(condiments)

·子类在继承的时候,在定义类时,小括号()中为父类的名字

1.9.7  再次测试

·父类的属性、方法,会被继承给子类

完整的代码如下:

1.10.3注意点

classSweetPotato:

classAnimal(object):

"这是烤地瓜的类"

def__init__(self, name='动物', color='白色'):

#定义初始化方法

self.__name = name

def__init__(self):

self.color = color

self.cookedLevel =0

def__test(self):

self.cookedString ="生的"

print(self.__name)

self.condiments = []

print(self.color)

#定制print时的显示内容

deftest(self):

def__str__(self):

print(self.__name)

msg = self.cookedString +"地瓜"

print(self.color)

iflen(self.condiments) >0:

classDog(Animal):

msg = msg +"("

defdogTest1(self):

fortempinself.condiments:

#print(self.__name) #不能访问到父类的私有属性

msg = msg + temp +", "

print(self.color)

msg = msg.strip(", ")

defdogTest2(self):

msg = msg +")"

#self.__test() #不能访问父类中的私有方法

returnmsg

self.test()

#烤地瓜方法

A = Animal()

defcook(self, time):

#print(A.__name) #程序出现异常,不能访问私有属性

self.cookedLevel += time

print(A.color)

ifself.cookedLevel >8:

#A.__test() #程序出现异常,不能访问私有方法

self.cookedString ="烤成灰了"

A.test()

elifself.cookedLevel >5:

print("------分割线-----")

self.cookedString ="烤好了"

D = Dog(name ="小花狗", color ="黄色")

elifself.cookedLevel >3:

D.dogTest1()

self.cookedString ="半生不熟"

D.dogTest2()

else:

总结

self.cookedString ="生的"

·私有的属性,不能通过对象直接访问,但是可以通过方法访问

#添加配料

·私有的方法,不能通过对象直接访问

defaddCondiments(self, condiments):

·私有的属性、方法,不会被子类继承,也不能被访问

self.condiments.append(condiments)

·一般情况下,私有的属性、方法都是不对外公布的,往往用来做内部的事情,起到安全的作用

#用来进行测试

1.11多继承

mySweetPotato = SweetPotato()

所谓多继承,即子类有多个父类,并且具有它们的特征

print("------有了一个地瓜,还没有烤-----")

多继承的格式如下:

print(mySweetPotato.cookedLevel)

#定义一个父类

print(mySweetPotato.cookedString)

classA:

print(mySweetPotato.condiments)

defprintA(self):

print("------接下来要进行烤地瓜了-----")

print('----A----')

print("------地瓜经烤了4分钟-----")

#定义一个父类

mySweetPotato.cook(4)#烤4分钟

classB:

print(mySweetPotato)

defprintB(self):

print("------地瓜又经烤了3分钟-----")

print('----B----')

mySweetPotato.cook(3)#又烤了3分钟

#定义一个子类,继承自A、B

print(mySweetPotato)

classC(A,B):

print("------接下来要添加配料-番茄酱------")

defprintC(self):

mySweetPotato.addCondiments("番茄酱")

print('----C----')

print(mySweetPotato)

obj_C = C()

print("------地瓜又经烤了5分钟-----")

obj_C.printA()

mySweetPotato.cook(5)#又烤了5分钟

obj_C.printB()

print(mySweetPotato)

运行结果:

print("------接下来要添加配料-芥末酱------")

----A----

mySweetPotato.addCondiments("芥末酱")

----B----

print(mySweetPotato)

说明

1.10 应用:存放家具

·python中是可以多继承的,在java中叫接口

#定义一个home类

·父类中的方法、属性,子类会继承

classHome:

1.12重写/覆盖父类方法与调用父类方法

def__init__(self, area):

1.12.1重写父类方法

self.area = area#房间剩余的可用面积

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

#self.light = 'on' #灯默认是亮的

#coding=utf-8

self.containsItem = []

classCat(object):

def__str__(self):

defsayHello(self):

msg ="当前房间可用面积为:"+ str(self.area)

print("halou-----1")

iflen(self.containsItem) >0:

classBosi(Cat):

msg = msg +"容纳的物品有: "

defsayHello(self):

fortempinself.containsItem:

print("halou-----2")

msg = msg + temp.getName() +", "

bosi = Bosi()

msg = msg.strip(", ")

bosi.sayHello()

returnmsg

1.12.2调用父类的方法

#容纳物品

#coding=utf-8

defaccommodateItem(self,item):

classCat(object):

#如果可用面积大于物品的占用面积

def__init__(self,name):

needArea = item.getUsedArea()

self.name = name

ifself.area > needArea:

self.color ='yellow'

self.containsItem.append(item)

classBosi(Cat):

self.area -= needArea

def__init__(self,name):

print("ok:已经存放到房间中")

#调用父类的__init__方法1(python2)

else:

#Cat.__init__(self,name)

print("err:房间可用面积为:%d,但是当前要存放的物品需要的面积为%d"%(self.area, needArea))

#调用父类的__init__方法2

#定义bed类

#super(Bosi,self).__init__(name)

classBed:

#调用父类的__init__方法3

def__init__(self,area,name ='床'):

super().__init__(name)

self.name = name

defgetName(self):

self.area = area

returnself.name

def__str__(self):

bosi =

msg ='床的面积为:'+ str(self.area)

Bosi('xiaohua')

returnmsg

print(bosi.name)

#获取床的占用面积

print(bosi.color)

defgetUsedArea(self):

1.13多态

returnself.area

Python不支持多态,也不用支持多态,python是一种多态语言,崇尚鸭子类型。

defgetName(self):

在程序设计中,鸭子类型(英语:duck typing)是动态类型的一种风格。在这种风格中,一个对象有效的语义,不是由继承自特定的类或实现特定的接口,而是由当前方法和属性的集合决定。

returnself.name

在鸭子类型中,关注的不是对象的类型本身,而是它是如何使用的。

#创建一个新家对象

所谓多态:定义时的类型和运行时的类型不一样,就成为多态

newHome = Home(100)#100平米

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

print(newHome)

packagedemo1;

#创建一个床对象

/*

newBed = Bed(20)

多态:多种形态,必须依赖于继承完成的。

print(newBed)

场景:

#把床安放到家里

Animal

newHome.accommodateItem(newBed)

|Dog

print(newHome)

|Cat

#创建一个床对象

*/

newBed2 = Bed(30,'席梦思')

classAnimal{

print(newBed2)

public void eat(){

#把床安放到家里

System.out.println("animaleat...");

newHome.accommodateItem(newBed2)

}

print(newHome)

}

总结:

class Dogextends Animal{

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

public void eat(){

思维升华:

System.out.println("Dogeat...");

·添加“开、关”灯,让房间、床一起亮、灭

}

1.11 保护对象的属性

}

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

class Catextends Animal{

·对象名.属性名=数据---->直接修改

public void eat(){

·对象名.方法名() ---->间接修改

System.out.println("Cateat...");

为了更好的保存属性安全,即不能随意修改,一般的处理方式为

}

·将属性定义为私有属性

}

·添加一个可以调用的方法,供调用

classMyTest{

classPeople(object):

public static void tt(Animal animal){

def__init__(self, name):

animal.eat();

self.__name = name

}

defgetName(self):

public static void main(String[] args){

returnself.__name

Animal a = new Animal();

defsetName(self, newName):

tt(a);// animal eat...

iflen(newName) >=5:

Animal d = new Dog();

self.__name = newName

tt(d);// Animal animal = dDog eat...

else:

d = new Cat();

print("error:名字长度需要大于或者等于5")

tt(d);// Cat eat...

xiaoming = People("xx")

//int num= 10;

print(xiaoming.__name)

//tt(num);

classPeople(object):

}

def__init__(self, name):

}

self.__name = name

/**

defgetName(self):

* java,c#都是强类型语言,就是说在变量定义的时候必须类型名字

returnself.__name

*这样,在传递参数的时候,都类型有要求

defsetName(self, newName):

*

iflen(newName) >=5:

*所在在这样的语言中,多态的表现有两种:

self.__name = newName

*1、父类作为参数,既可以传递父类对象,也可以传递子类对象

else:

*这样,在方法中,调用的是子和父都有的方法,

print("error:名字长度需要大于或者等于5")

*如果传递的是父类对象,调用的就是父类的方法

xiaoming = People("xx")

*如果传递的是子类对象,调用的就是子类的方法

xiaoming.setName("yy")

*

print(xiaoming.getName())

*/

xiaoming.setName("lisi")

·Python “鸭子类型”

print(xiaoming.getName())

‘’’

总结

python是一种弱类型语言,没有类型限制。

·Python中没有像C++中public和private这些关键字来区别公有属性和私有属性

变量的类型永远是通过右侧的值判断的。

·它是以属性命名方式来区分,如果在属性名前面加了2个下划线'__',则表明该属性是私有属性,否则为公有属性(方法也是一样,方法名前面加了2个下划线的话表示该方法是私有的,否则为公有的)。

方法中的参数,传递任何值都行。但是要考虑方法内部的业务逻辑。

1.12 __del__()方法

多态:

创建对象后,python解释器默认调用__init__()方法;

1、父类作为参数,可以传递父类和子类对象

当删除一个对象时,python解释器也会默认调用一个方法,这个方法为__del__()方法

2、接口作为参数,只能传递实现对象

importtime

所以有两种理解:

classAnimal(object):

1、python不支持多态:

#初始化方法

python是弱类型,没有类型限定,无法区分父和子,或者说接口和实现类

#创建完对象后会自动被调用

2、python处处是多态

def__init__(self, name):

python是弱类型,没有类型限定,传递任何内容都行

print('__init__方法被调用')

‘’’

self.__name = name

classF1(object):

#析构方法

def show(self):

#当对象被删除时,会自动被调用

print('F1.show')

def__del__(self):

classS1(F1):

print("__del__方法被调用")

def show(self):

print("%s对象马上被干掉了..."%self.__name)

print('S1.show')

#创建对象

classS2(F1):

dog = Animal("哈皮狗")

def show(self):

#删除对象

print('S2.show')

deldog

deffunc(obj):

cat = Animal("波斯猫")

obj.show()

cat2 = cat

#print(type(obj))

cat3 = cat

s1_obj =S1()

print("---马上 删除cat对象")

func(s1_obj)

delcat

s2_obj =S2()

print("---马上 删除cat2对象")

func(s2_obj)

delcat2

f1 = F1()

print("---马上 删除cat3对象")

func(f1)

delcat3

#func(10)能传递值,但是业务逻辑可能不符合

print("程序2秒钟后结束")

1.14类属性、实例属性

time.sleep(2)

直接在类中定义的,与方法平齐,不在方法里的属性就是类属性

总结

在方法里通过self.属性都是实例属性

·当有1个变量保存了对象的引用时,此对象的引用计数就会加1

类属性和实例属性:

·当使用del删除变量指向的对象时,如果对象的引用计数不会1,比如3,那么此时只会让这个引用计数减1,即变为2,当再次调用del时,变为1,如果再调用1次del,此时会真的把对象进行删除,__del__会被调用

在前面的例子中我们接触到的就是实例属性(对象属性)。顾名思义,类属性就是类对象所拥有的属性,它被所有类对象的实例对象所共有,在内存中只存在一个副本。对于公有的类属性,在类外可以通过类对象和实例对象访问

1.13继承

1.14.1类属性

将共性的内容放在父类中,子类只需要关注自己特有的内容。在程序中,继承描述的是事物之间的所属关系,例如猫和狗都属于动物,程序中便可以描述为猫和狗继承自动物;同理,波斯猫和巴厘猫都继承自猫,而沙皮狗和斑点狗都继承自狗。

classPeople(object):

1.131 继承的实例

name ='Tom'#公有的类属性

lassCat(object):

__age =12#私有的类属性

def__init__(self, name, color="白色"):

p = People()

self.name = name

print(p.name)#正确

self.color = color

print(People.name)#正确

defrun(self):

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

print("%s--在跑"%self.name)

print(People.__age)#错误,不能在类外通过类对象访问私有的类属性

#定义一个子类,继承Cat类如下:

1.14.2实例属性(对象属性)

classBosi(Cat):

classPeople(object):

defsetNewName(self, newName):

address ='山东'#类属性

self.name = newName

def__init__(self):

defeat(self):

self.name ='xiaowang'#实例属性

print("%s--在吃"%self.name)

self.age =20#实例属性

bs = Bosi("印度猫")

p = People()

print('bs的名字为:%s'%bs.name)

p.age =12#实例属性

print('bs的颜色为:%s'%bs.color)

print(p.address)#正确

bs.eat()

print(p.name)#正确

bs.setNewName('波斯')

print(p.age)#正确

bs.run()

print(People.address)#正确

说明:

print(People.name)#错误

·虽然子类没有定义__init__方法,但是父类有,所以在子类继承父类的时候这个方法就被继承了,所以只要创建Bosi的对象,就默认执行了那个继承过来的__init__方法

print(People.age)#错误

总结

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

·子类在继承的时候,在定义类时,小括号()中为父类的名字

classPeople(object):

·父类的属性、方法,会被继承给子类

country ='china'#类属性

1.132注意点

print(People.country)

classAnimal(object):

p = People()

def__init__(self, name='动物', color='白色'):

print(p.country)

self.__name = name

p.country ='japan'

self.color = color

print(p.country)#实例属性会屏蔽掉同名的类属性

def__test(self):

print(People.country)

print(self.__name)

delp.country#删除实例属性

print(self.color)

print(p.country)

deftest(self):

总结

print(self.__name)

·如果需要在类外修改类属性,必须通过类对象去引用然后进行修改。如果通过实例对象去引用,会产生一个同名的实例属性,这种方式修改的是实例属性,不会影响到类属性,并且之后如果通过实例对象去引用该名称的属性,实例属性会强制屏蔽掉类属性,即引用的是实例属性,除非删除了该实例属性。

print(self.color)

·

classDog(Animal):

1.15静态方法和类方法

defdogTest1(self):

1.15.1类方法

#print(self.__name) #不能访问到父类的私有属性

类对象所拥有的方法,需要用修饰器@classmethod(注解、元数据)来标识其为类方法,对于类方法,第一个参数必须是类对象,一般以cls作为第一个参数,能够通过实例对象和类对象去访问。

print(self.color)

classPeople(object):

defdogTest2(self):

country ='china'

#self.__test() #不能访问父类中的私有方法

#类方法,用classmethod来进行修饰

self.test()

@classmethod

A = Animal()

defgetCountry(cls):

#print(A.__name) #程序出现异常,不能访问私有属性

print(type(cls))

print(A.color)

print(cls)

#A.__test() #程序出现异常,不能访问私有方法

returncls.country

A.test()

p = People()

print("------分割线-----")

p.country=1

D = Dog(name ="小花狗", color ="黄色")

print(p.getCountry())#可以用过实例对象引用china

D.dogTest1()

printPeople.getCountry()#可以通过类对象引用china

D.dogTest2()

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

总结

classPeople(object):

·私有的属性,不能通过对象直接访问,但是可以通过方法访问

country ='china'

·私有的方法,不能通过对象直接访问

#类方法,用classmethod来进行修饰

·私有的属性、方法,不会被子类继承,也不能被访问

@classmethod

·一般情况下,私有的属性、方法都是不对外公布的,往往用来做内部的事情,起到安全的作用

defgetCountry(cls):

1.14多继承

returncls.country

Python中多继承的格式如下:

@classmethod

#定义一个父类

defsetCountry(cls,country):

classA:

cls.country = country

defprintA(self):

p = People()

print('----A----')

print(p.getCountry())#可以用过实例对象引用

#定义一个父类

print(People.getCountry())#可以通过类对象引用

classB:

p.setCountry('japan')

defprintB(self):

printp.getCountry()

print('----B----')

printPeople.getCountry()

#定义一个子类,继承自A、B

1.15.2静态方法

classC(A,B):

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

defprintC(self):

classPeople(object):

print('----C----')

country ='china'

obj_C = C()

@staticmethod

obj_C.printA()

#静态方法

obj_C.printB()

defgetCountry():

运行结果:

returnPeople.country

----A----

printPeople.getCountry()

----B----

class People(object):

说明

country = 'china'

·python中是可以多继承的,在java中叫接口

__num = 100

·父类中的方法、属性,子类会继承

#类方法,用classmethod来进行修饰

注意点

@classmethod

·想一想:

def getCountry(cls):

如果在上面的多继承例子中,如果父类A和父类B中,有一个同名的方法,那么通过子类去调用的时候,调用哪个?

print(type(cls))

#coding=utf-8

print(cls)

classbase(object):

return cls.country

deftest(self):

@staticmethod

print('----base test----')

def myStaticMethod():

classA(base):

print('myStaticMethod...')

deftest(self):

print(People.__num)

print('----A test----')

p = People()

#定义一个父类

p.country=1

classB(base):

print(p.getCountry())#可以用过实例对象引用

deftest(self):

print(People.getCountry())#可以通过类对象引用

print('----B test----')

p.myStaticMethod()

#定义一个子类,继承自A、B

People.myStaticMethod()

classC(A,B):

'''

pass

1、类方法,实例和类对象都能访问

obj_C = C()

cls:类对象

obj_C.test()

2、静态方法:不传参,实例和类对象都能访问

print(C.__mro__)#可以查看C类的对象搜索方法时的先后顺序

'''

1.15重写父类与调用父类方法

总结

1.151重写父类的方法

类方法的第一个参数是类对象cls,那么通过cls引用的必定是类对象的属性和方法;而实例方法的第一个参数是实例对象self,那么通过self引用的可能是类属性、也有可能是实例属性,不过在存在相同名称的类属性和实例属性的情况下,实例属性优先级更高。静态方法中不需要额外定义参数,因此在静态方法中引用类属性的话,必须通过类对象来引用

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

1.16设计模式

#coding=utf-8

设计模式是软件开发人员在软件开发过程中面临的一般问题的解决方案。

classCat(object):

1.16.1设计模式六大原则

defsayHello(self):

1.设计模式六大原则(1):单一职责原则

print("halou-----1")

即一个类只负责一项职责

classBosi(Cat):

2.设计模式六大原则(2):里氏替换原则

defsayHello(self):

所有引用基类的地方必须能透明地使用其子类的对象

print("halou-----2")

3.设计模式六大原则(3):依赖倒置原则

bosi = Bosi()

高层模块不应该依赖低层模块,二者都应该依赖其抽象;抽象不应该依赖细节;细节应该依赖抽象。

bosi.sayHello()

4.设计模式六大原则(4):接口隔离原则

1.15.2调用父类的方法

客户端不应该依赖它不需要的接口;一个类对另一个类的依赖应该建立在最小的接口上。

#coding=utf-8

5.设计模式六大原则(5):迪米特法则

classCat(object):

一个对象应该对其他对象保持最少的了解。尽量降低类与类之间的耦合。

def__init__(self,name):

6.设计模式六大原则(6):开闭原则

self.name = name

一个软件实体如类、模块和函数应该对扩展开放,对修改关闭。

self.color ='yellow'

1.16.2分类

classBosi(Cat):

1.创建型模式

def__init__(self,name):

主要目的:创建对象

#调用父类的__init__方法1(python2)

共五种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。

#Cat.__init__(self,name)

2.结构型模式

#调用父类的__init__方法2

主要目的:对象的组成和对象的关系

#super(Bosi,self).__init__(name)

共七种:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。

#调用父类的__init__方法3

3.行为型模式

super().__init__(name)

主要目的:对象的行为,对象能做什么

defgetName(self):

共十一种:策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。

returnself.name

1.17工厂设计模式

bosi = Bosi('xiaohua')

工厂函数、工厂类对具体的生成环节进行了封装,这样有利于代码的后需扩展,即把功能划分的更具体。

print(bosi.name)

总结:

print(bosi.color)

在创建对象比较简单的时候,我们直接在主方法中做了,但是很多时候,创建对象需要一些初始化的操作,或者业务逻辑的处理。也就是说,有时候创建一个对象会做比较复杂的操作,这个时候,如果所有对象的创建操作都放在主方法中,就不合适了,可以使用简单工厂模式

1.6多态

简单工厂模式的组成:

多态的概念是应用于Java和C#这一类强类型语言中,而Python崇尚“鸭子类型”。

1.工厂类角色:这是本模式的核心,含有一定的商业逻辑和判断逻辑,用来创建产品

首先Python不支持多态,也不用支持多态,python是一种多态语言,崇尚鸭子类型。以下是维基百科中对鸭子类型得论述:

2.抽象产品角色:它一般是具体产品继承的父类或者实现的接口。

在程序设计中,鸭子类型(英语:duck typing)是动态类型的一种风格。在这种风格中,一个对象有效的语义,不是由继承自特定的类或实现特定的接口,而是由当前方法和属性的集合决定。这个概念的名字来源于由James Whitcomb Riley提出的鸭子测试,“鸭子测试”可以这样表述:

3.具体产品角色:工厂类所创建的对象就是此角色的实例。

“当看到一只鸟走起来像鸭子、游泳起来像鸭子、叫起来也像鸭子,那么这只鸟就可以被称为鸭子。”

简单工厂的优点和缺点

在鸭子类型中,关注的不是对象的类型本身,而是它是如何使用的。例如,在不使用鸭子类型的语言中,我们可以编写一个函数,它接受一个类型为鸭的对象,并调用它的走和叫方法。在使用鸭子类型的语言中,这样的一个函数可以接受一个任意类型的对象,并调用它的走和叫方法。如果这些需要被调用的方法不存在,那么将引发一个运行时错误。任何拥有这样的正确的走和叫方法的对象都可被函数接受的这种行为引出了以上表述,这种决定类型的方式因此得名。

对象创建比较复杂的时候,可以考虑使用简单工厂

鸭子类型通常得益于不测试方法和函数中参数的类型,而是依赖文档、清晰的代码和测试来确保正确使用。从静态类型语言转向动态类型语言的用户通常试图添加一些静态的(在运行之前的)类型检查,从而影响了鸭子类型的益处和可伸缩性,并约束了语言的动态特性。

1.优点:

所谓多态:定义时的类型和运行时的类型不一样,此时就成为多态

在简单工厂中主函数或者客户端不再负责对象的创建,而是把这个责任交给工厂类,主函数或者客户端在使用对象的时候只从工厂中调用就行了,从而明确了各个类的职责,符合单一职责原则)

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

2.缺点

classF1(object):

由于这个工厂类负责所有对象的创建,那么当子类增多时,我们就需要去修改工厂类的代码,这样呢,就违反了一个原则:开闭原则

defshow(self):

这个时候可以使用工厂方法模式

print'F1.show'

工厂方法模式组成:

classS1(F1):

1.抽象工厂角色:这是工厂方法模式的核心,它与应用程序无关。是具体工厂角色必须实现的接口或者必须继承的父类。

defshow(self):

2.具体工厂角色:它含有和具体业务逻辑有关的代码。由应用程序调用以创建对应的具体产品的对象。

print'S1.show'

3.抽象产品角色:它是具体产品继承的父类或者是实现的接口。

classS2(F1):

4.具体产品角色:具体工厂角色所创建的对象就是此角色的实例。

defshow(self):

工厂方法模式的优点和缺点

print'S2.show'

3.优点:

#由于在Java或C#中定义函数参数时,必须指定参数的类型

解决了简单工厂模式的违反开闭原则

#为了让Func函数既可以执行S1对象的show方法,又可以执行S2对象的show方法,所以,定义了一个S1和S2类的父类

4.缺点

#而实际传入的参数是:S1对象和S2对象

如果需要增加一个具体产品类角色,需要添加这个类和对应的工厂类。代码量大。

defFunc(F1 obj):

1.18__new__的使用

"""Func函数需要接收一个F1类型或者F1子类的类型"""

__new__和__init__的作用

printobj.show()

classA(object):

s1_obj = S1()

def__init__(self):

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

print("这是init方法")

s2_obj = S2()

def__new__(cls):

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

print("这是new方法")

·Python “鸭子类型”

returnobject.__new__(cls)

classF1(object):

A()

defshow(self):

总结

print'F1.show'

·__new__至少要有一个参数cls,代表要实例化的类,此参数在实例化时由Python解释器自动提供

classS1(F1):

·__new__必须要有返回值,返回实例化出来的实例,这点在自己实现__new__时要特别注意,可以return父类__new__出来的实例,或者直接是object的__new__出来的实例

defshow(self):

·__init__有一个参数self,就是这个__new__返回的实例,__init__在__new__的基础上可以完成一些其它初始化的动作,__init__不需要返回值

print'S1.show'

1.19单例设计模式

classS2(F1):

1.19.1单例是什么

defshow(self):

确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例,这个类称为单例类,单例模式是一种对象创建型模式。

print'S2.show'

1.19.2创建单例-保证只有1个对象

defFunc(obj):

#实例化一个单例

printobj.show()

classSingleton(object):

s1_obj = S1()

__instance =None

Func(s1_obj)

def__new__(cls, age, name):

s2_obj = S2()

#如果类数字能够__instance没有或者没有赋值

Func(s2_obj)

#那么就创建一个对象,并且赋值为这个对象的引用,保证下次调用这个方法时

1.17类属性、实例属性

#能够知道之前已经创建过对象了,这样就保证了只有1个对象

在了解了类基本的东西之后,下面看一下python中这几个概念的区别

ifnotcls.__instance:

先来谈一下类属性和实例属性

cls.__instance = object.__new__(cls)

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

returncls.__instance

1.17.1类属性

a = Singleton(18,"wangcai")

classPeople(object):

b = Singleton(8,"wangcai")

name ='Tom'#公有的类属性

print(id(a))

__age =12#私有的类属性

print(id(b))

p = People()

a.age =19#给a指向的对象添加一个属性

print(p.name)#正确

print(b.age)#获取b指向的对象的age属性

print(People.name)#正确

1.19.3创建单例时,只执行1次__init__方法

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

#实例化一个单例

print(People.__age)#错误,不能在类外通过类对象访问私有的类属性

classSingleton(object):

1.17.2实例属性

__instance =None

classPeople(object):

__first_init =False

address ='山东'#类属性

def__new__(cls, age, name):

def__init__(self):

ifnotcls.__instance:

self.name ='xiaowang'#实例属性

cls.__instance = object.__new__(cls)

self.age =20#实例属性

returncls.__instance

p = People()

def__init__(self, age, name):

p.age =12#实例属性

ifnotself.__first_init:

print(p.address)#正确

self.age = age

print(p.name)#正确

self.name = name

print(p.age)#正确

Singleton.__first_init =True

print(People.address)#正确

a = Singleton(18,"wangcai")

print(People.name)#错误

b = Singleton(8,"xiaoqiang")

print(People.age)#错误

print(id(a))

1.17.3通过实例对象修改类属性

print(id(b))

classPeople(object):

print(a.age)

country ='china'#类属性

print(b.age)

print(People.country)

a.age =19

p = People()

print(b.age)

print(p.country)

p.country ='japan'

print(p.country)#实例属性会屏蔽掉同名的类属性

print(People.country)

delp.country#删除实例属性

print(p.country)

总结

如果需要在类外修改类属性,必须通过类对象去引用然后进行修改。如果通过实例对象去引用,会产生一个同名的实例属性,这种方式修改的是实例属性,不会影响到类属性,并且之后如果通过实例对象去引用该名称的属性,实例属性会强制屏蔽掉类属性,即引用的是实例属性,除非删除了该实例属性。

1.18类方法和静态方法

1.18.1类方法

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

classPeople(object):

country ='china'

#类方法,用classmethod来进行修饰

@classmethod

defgetCountry(cls):

returncls.country

p = People()

printp.getCountry()#可以用过实例对象引用

printPeople.getCountry()#可以通过类对象引用

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

classPeople(object):

country ='china'

#类方法,用classmethod来进行修饰

@classmethod

defgetCountry(cls):

returncls.country

@classmethod

defsetCountry(cls,country):

cls.country = country

p = People()

printp.getCountry()#可以用过实例对象引用

printPeople.getCountry()#可以通过类对象引用

p.setCountry('japan')

printp.getCountry()

printPeople.getCountry()

1.18.2静态方法

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

classPeople(object):

country ='china'

@staticmethod

#静态方法

defgetCountry():

returnPeople.country

printPeople.getCountry()

总结

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

1.19工厂设计模型

设计一个卖车的4S店,该怎样做呢?

#定义车类

classCar(object):

#定义车的方法

defmove(self):

print("---车在移动---")

defstop(self):

print("---停车---")

#定义一个销售车的店类

classCarStore(object):

deforder(self):

self.car = Car()#找一辆车

self.car.move()

self.car.stop()

说明

上面的4s店,只能销售那一种类型的车

如果这个是个销售北京现代品牌的车,比如伊兰特、索纳塔等,该怎样做呢?

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

#定义伊兰特车类

classYilanteCar(object):

#定义车的方法

defmove(self):

print("---车在移动---")

defstop(self):

print("---停车---")

#定义索纳塔车类

classSuonataCar(object):

#定义车的方法

defmove(self):

print("---车在移动---")

defstop(self):

print("---停车---")

#定义一个销售北京现代车的店类

classCarStore(object):

deforder(self, typeName):

#根据客户的不同要求,生成不同的类型的车

iftypeName =="伊兰特":

car = YilanteCar()

eliftypeName =="索纳塔":

car = SuonataCar()

returncar

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

使用函数实现

#定义伊兰特车类

classYilanteCar(object):

#定义车的方法

defmove(self):

print("---车在移动---")

defstop(self):

print("---停车---")

#定义索纳塔车类

classSuonataCar(object):

#定义车的方法

defmove(self):

print("---车在移动---")

defstop(self):

print("---停车---")

#用来生成具体的对象

defcreateCar(typeName):

iftypeName =="伊兰特":

car = YilanteCar()

eliftypeName =="索纳塔":

car = SuonataCar()

returncar

#定义一个销售北京现代车的店类

classCarStore(object):

deforder(self, typeName):

#让工厂根据类型,生产一辆汽车

car = createCar(typeName)

returncar

使用类来实现

#定义伊兰特车类

classYilanteCar(object):

#定义车的方法

defmove(self):

print("---车在移动---")

defstop(self):

print("---停车---")

#定义索纳塔车类

classSuonataCar(object):

#定义车的方法

defmove(self):

print("---车在移动---")

defstop(self):

print("---停车---")

#定义一个生产汽车的工厂,让其根据具体的订单生产车

classCarFactory(object):

defcreateCar(self,typeName):

iftypeName =="伊兰特":

car = YilanteCar()

eliftypeName =="索纳塔":

car = SuonataCar()

returncar

#定义一个销售北京现代车的店类

classCarStore(object):

def__init__(self):

#设置4s店的指定生产汽车的工厂

self.carFactory = CarFactory()

deforder(self, typeName):

#让工厂根据类型,生产一辆汽车

car = self.carFactory.createCar(typeName)

returncar

咋一看来,好像只是把生产环节重新创建了一个类,这确实比较像是一种编程习惯,此种解决方式被称作简单工厂模式

工厂函数、工厂类对具体的生成环节进行了封装,这样有利于代码的后需扩展,即把功能划分的更具体,4s店只负责销售,汽车厂只负责制造

编辑:操作系统 本文来源:修改代码,面向对象是一种设计思想

关键词: