python_面向对象,以及类的相关知识

1、面向对象

类:就是把相同的事物的动做和特征整合到一块儿java

  类是一个抽象的。python

对象:基于类建立的一个具体的事物,程序员

   也是特征和动做整合一块儿的编程

#最初始的写法
people = {
    'name': '奥巴马',
    'gender': '男',
    'age': '50',
}

def ment1(people):
    print('这个叫【%s】的人,正在跑步'%people['name'])
def ment2(people):
    print('这个叫【%s】,今年【%s】岁的【%s】人,吃饭'%(people['name'],
                                      people['age'],people['gender']))

ment1(people)
ment2(people)

  

#使用函数去编写面向对象。
def peo():

    def ment1(people):
        print('这个叫【%s】的人,正在跑步'%people['name'])
    def ment2(people):
        print('这个叫【%s】,今年【%s】岁的【%s】人,吃饭'%(people['name'],
                                          people['age'],people['gender']))
    people = {
        'name': '奥巴马',
        'gender': '男',
        'age': '50',
        'run':ment1,
        'ect':ment2,
    }
    return people

f = peo()
f['run'](peo())

 

#使用函数去编写面向对象。优化版
# def peo(name,gender,age):
#     #要作的事:
#     def ment1(people):
#         print('这个叫【%s】的人,正在跑步'%people['name'])
#     def ment2(people):
#         print('这个叫【%s】,今年【%s】岁的【%s】人,吃饭'%(people['name'],
#                                           people['age'],people['gender']))
#     #将定义的字典,写入函数中
#     def init(name,gender,age):
#         people = {
#             'name': name,
#             'gender': gender,
#             'age': age,
#             'run': ment1,
#             'ect': ment2,
#         }
#         return people   #返回字典
#     res = init(name,gender,age)  #返回字典的这个函数
#     return res
# f = peo('奥巴马','男','20')  #这个返回值是init(name,gender,age)
# f1 = peo('奥巴马','男','20')
# #f['run'](f):调用的是ment1这个函数,由于他有一个参数,
# # 就是people,,这个字典,因此()中要跟一个参数就是peo('奥巴马','男','20')的返回值
# f['run'](f)
# f['ect'](f1)

 

PS.  编程语言

 面向对象编程,和程序设计面向对象 ,是没有关系的ide

  面向对象编程,是使用class类来进行编程的函数

  程序设计面向对象:是使用def()来编程的工具

 


 

2、类/对象相关的知识

class类的建立方法
声明类的方式,类名的开头最好是大写字母

大前提:
1.只有在python2中才分新式类和经典类,python3中统一都是新式类
2.新式类和经典类声明的最大不一样在于,全部新式类必须继承至少一个父类
3.全部类甭管是否显式声明父类,都有一个默认继承object父类(讲继承时会讲,先记住)
在python2中的区分
经典类:
class 类名:
    pass

经典类:
class 类名(父类):
    pass

在python3中,上述两种定义方式全都是新式类
经典类和新式类

 

一、类的属性

  dir(类名):查出的是类的一个名字列表学习

  类名.__dict__:查看的是一个类的属性字典,优化

 

class student:

    def __init__(self,name,age,sex):
        self.name = name
        self.age = age
        self.sex = sex
    def jineng(self):
        print('%s 走路'%self.name)

s1 = student('liu',23,'nan')
s1.jineng()

  

重点:输入输出不要写到特定的函数当中,若是写到特定的函数中,那么这样的可读性就低了,

 


 二、类的使用:

引用类的特征(类的变量)和技能(类的函数)
类:一:实例化,
  二:引用名字(类名.变量名,类名.函数名)实例:引用名字(实例名.类的变量,实例名.绑定方法,实例名.实例本身的变量名)类.数据属性,调用的都是在本身的属性字典去调用的
class Student:
    def __init__(self,name,age):
        self.name = name
        self.age = age
bart = Student('yang',20)
print(bart.age)

三、实例化使用

实例属性只有数据属性,没有函数属性

类名加括号就是实例化,会自动触发__init__函数的运行,能够用它来为每一个实例定制本身的特征

class Student:
    def __init__(self,id):
        self.id = id

s1 = Student('12345678890')
print(s1.id)

  

实例化:类名+括号

class Student:
    def __init__(self,id):
        self.id = id
s1 = Student('12345678890')

  self的做用是在实例化时自动将对象/实例自己传给__init__的第一个参数,self能够是任意名字,可是瞎几把写别人就看不懂了。

3.1查看类里面的属性

一:咱们定义的类的属性到底存到哪里了?有两种方式查看
dir(类名):查出的是一个名字列表
类名.__dict__:查出的是一个字典,key为属性名,value为属性值

二:特殊的类属性
类名.__name__# 类的名字(字符串)
类名.__doc__# 类的文档字符串
类名.__base__# 类的第一个父类(在讲继承时会讲)
类名.__bases__# 类全部父类构成的元组(在讲继承时会讲)
类名.__dict__# 类的字典属性
类名.__module__# 类定义所在的模块
类名.__class__# 实例对应的类(仅新式类中)
类名.__mro__#类的父级以及自己

  

数据封装

##将上面的代码,进行数据封装使用
def foo(std):
    print('%s : %s' %(std.name,std.age))

foo(bart)

4.对象/实例只有一种做用:属性引用

#对象/实例自己其实只有数据属性
>>> g1.nickname
'草丛伦'
>>> g1.aggressivity
>>> g1.life_value
'''
查看实例属性
一样是dir和内置__dict__两种方式
特殊实例属性
__class__
__dict__
....
'''

  对象/实例自己只有数据属性,可是python的class机制会将类的函数绑定到对象上,称为对象的方法,或者叫绑定方法,绑定方法惟一绑定一个对象,同一个类的方法绑定到不一样的对象上,属于不一样的方法,内存地址都不会同样

 

5.对象之间的交互

class Riven:
    camp='Noxus'  #全部玩家的英雄(锐雯)的阵营都是Noxus;
    def __init__(self,nickname,aggressivity=54,life_value=414): #英雄的初始攻击力54;
        self.nickname=nickname  #为本身的锐雯起个别名;
        self.aggressivity=aggressivity #英雄都有本身的攻击力;
        self.life_value=life_value #英雄都有本身的生命值;
    def attack(self,enemy):   #普通攻击技能,enemy是敌人;
        enemy.life_value-=self.aggressivity #根据本身的攻击力,攻击敌人就减掉敌人的生命值。

实例出一个Riven来

>>> r1=Riven('锐雯雯')

交互:锐雯雯攻击草丛伦,反之同样

>>> g1.life_value
455
>>> r1.attack(g1)
>>> g1.life_value
401 

6.类名称空间与对象/实例名称空间

建立一个类就会建立一个类的名称空间,用来存储类中定义的全部名字,这些名字称为类的属性

而类有两种属性:数据属性和函数属性

其中类的数据属性是共享给全部对象的

>>> id(r1.camp) #本质就是在引用类的camp属性,两者id同样
4315241024
>>> id(Riven.camp)
4315241024

 

而类的函数属性是绑定到全部对象的:

>>> id(r1.attack) 
4302501512
>>> id(Riven.attack)
4315244200

'''
r1.attack就是在执行Riven.attack的功能,python的class机制会将Riven的函数属性attack绑定给r1,r1至关于拿到了一个指针,指向Riven类的attack功能

除此以外r1.attack()会将r1传给attack的第一个参数
'''

建立一个对象/实例就会建立一个对象/实例的名称空间,存放对象/实例的名字,称为对象/实例的属性

在obj.name会先从obj本身的名称空间里找name,找不到则去类中找,类也找不到就找父类...最后都找不到就抛出异常  

 

使用多个类作的交互:

 

class Riven:
    camp='Noxus'
    def __init__(self,nickname,
                 aggressivity=54,
                 life_value=414,
                 money=1001,
                 armor=3):
        self.nickname=nickname
        self.aggressivity=aggressivity
        self.life_value=life_value
        self.money=money
        self.armor=armor
    def attack(self,enemy):
        damage_value=self.aggressivity-enemy.armor
        enemy.life_value-=damage_value

class Garen:
    camp='Demacia'
    def __init__(self,nickname,    #名称
                 aggressivity=58,  #初始攻击力
                 life_value=455,   #生命值
                 money=100,        #价格
                 armor=10):        #护甲
        self.nickname=nickname
        self.aggressivity=aggressivity
        self.life_value=life_value
        self.money=money
        self.armor=armor
    def attack(self,enemy):    #enemy:敌人
        '攻击力-护甲,生命值减攻击,获得新的生命值'
        damage_value=self.aggressivity-enemy.armor  
        enemy.life_value-=damage_value

class BlackCleaver:
    def __init__(self,price=475,aggrev=9,life_value=100):
        self.price=price   #装备的金额
        self.aggrev=aggrev  #加9点攻击
        self.life_value=life_value     #生命
    def update(self,obj):
        obj.money-=self.price #减钱
        obj.aggressivity+=self.aggrev #加攻击
        obj.life_value+=self.life_value #加生命值
    def fire(self,obj): #这是该装备的主动技能,喷火,烧死对方
        obj.life_value-=1000 #假设火烧的攻击力是1000
r1=Riven('草丛伦')
g1=Garen('盖文')
b1=BlackCleaver()
print(r1.aggressivity,r1.life_value,r1.money) #r1的攻击力,生命值,护甲
if r1.money > b1.price:
    r1.b1=b1
    b1.update(r1)
print(r1.aggressivity,r1.life_value,r1.money) #r1的攻击力,生命值,护甲
print(g1.life_value)
r1.attack(g1) #普通攻击
print(g1.life_value)
r1.b1.fire(g1) #用装备攻击
print(g1.life_value) #g1的生命值小于0就死了
类之间的交互

 

 

 

  

7.类的增删改查

 

class pro:
    sex = 'nan'
    sex1 = '男'
    def __init__(self,name,age):
        self.name = name
        self.age = age
    def tu_tan(self):
        print('随地吐痰')
s = pro('yang',23)
#增
s.qian = '20000'
print(s.qian)
#删
del s.qian
print(s.__dict__)
#改
s.sex = '11'
print(s.sex)
#查
print(s)
#############从类外部的增删改查
#改,经过外部的函数,去更改类下面的函数
def food(self):
    print('正在吃东西')
pro.tu_tan = food
pro.tu_tan(s)
#增 ,将类外部定义的函数,增长到类当中
def eat_food(self,food):
    print('正在吃%s'%food)

pro.eat = eat_food
pro.eat(s,'香蕉')

 

 8.实例的增删改查

根据实例去改变的话,我在去用类.变量,不会改变个人元素

class pro:
    sex = 'nan'
    sex1 = '男'
    def __init__(self,name,age):
        self.name = name
        self.age = age
    def tu_tan(self):
        print('随地吐痰')

s = pro('yang',23)
#增
s.qian = '20000'
print(s.qian)

#删
del s.qian
print(s.__dict__)

#改
s.sex = '11'
print(s.sex)

#查
print(s)

 

9.类使用的方法须要注意的

类和实例化里面的属性,都是经过.的方式去查看__dict__里面的属性,没用经过.的方式去查看的那都不会调用类里面的属性,而是从全局做用域里面去找的

class Chinese:
    country='China'
    def __init__(self,name):
        self.name=name
    def play_ball(self,ball):
        print('%s 正在打 %s' %(self.name,ball))
p1=Chinese('alex')
print(p1.country)
p1.country='日本'  #经过实例去更改属性,用实例去打印的更改了,类.的打印没有更改
print('类的--->',Chinese.country)
print('实例的',p1.country)
country='中国'
class Chinese:
    def __init__(self,name):
        self.name=name

    def play_ball(self,ball):
        print('%s 正在打 %s' %(self.name,ball))
p1=Chinese('alex')
print(p1.country)   #在类的外部定义一个变量,再经过类.变量打印,是报错的,提示在当前这个类里面没有country这个属性

动态读取:

country='中国'
class Chinese:
    def __init__(self,name):
        self.name=name

    def play_ball(self,ball):
        print('%s 正在打 %s' %(self.name,ball))

def shi_li_hua():
    name=input('>>: ')     #想动态添加,最好是在类的外部从新定义一个函数,去进行添加。直接在类的内部添加,可读性不高,别人会把你当傻逼
    p1=Chinese(name)
    # print(p1.country)
    print(p1.name)
shi_li_hua()

 

只要是.的方式去调用的都是类或实例的引用,其余的都不是调用类里面的内容

country='中国-------------------'
class Chinese:
    country='中国'
    def __init__(self,name):
        self.name=name
        print('--->',country)  #没用调用类里面的内容

    def play_ball(self,ball):
        print('%s 正在打 %s' %(self.name,ball))

print(Chinese.__dict__)
#只要是.的方式不是类的调用,就是实例的调用,
print(Chinese.country)
p1=Chinese('alex')
print('实例--------》',p1.country)

  

 

3、继承和派生

继承:就是将不一样的类的相同性,放到父级类里面,在从父级类调用到子类里面,最大化的减小相同的代码。

例如:

class Hero:   #父级类
    def __init__(self, nickname,aggressivity,life_value):
        self.nickname = nickname     #名字
        self.aggressivity = aggressivity   #攻击力
        self.life_value = life_value        #生命
    def attack(self,enemy):             #攻击
        print('from Hero attack')
        enemy.life_value-=self.aggressivity

class Garen(Hero):  #子类调用分类
    camp='Demacia'

class Riven(Hero): #子类调用分类
    camp='Noxus'

g1 = Garen('yang',200,454) #子类写入本身的属性
r1 = Riven('r1',250,500)   #子类写入本身的属性

print(g1.nickname)
print(g1.aggressivity)
print(g1.life_value)
print(r1.nickname)
print(r1.aggressivity)
print(r1.life_value)

 

1.继承的重要性

==========================第一部分
例如

  猫能够:喵喵叫、吃、喝、拉、撒

  狗能够:汪汪叫、吃、喝、拉、撒

若是咱们要分别为猫和狗建立一个类,那么就须要为 猫 和 狗 实现他们全部的功能,伪代码以下:
 

#猫和狗有大量相同的内容
class 猫:

    def 喵喵叫(self):
        print '喵喵叫'

    def 吃(self):
        # do something

    def 喝(self):
        # do something

    def 拉(self):
        # do something

    def 撒(self):
        # do something

class 狗:

    def 汪汪叫(self):
        print '喵喵叫'

    def 吃(self):
        # do something

    def 喝(self):
        # do something

    def 拉(self):
        # do something

    def 撒(self):
        # do something



==========================第二部分
上述代码不难看出,吃、喝、拉、撒是猫和狗都具备的功能,而咱们却分别的猫和狗的类中编写了两次。若是使用 继承 的思想,以下实现:

  动物:吃、喝、拉、撒

     猫:喵喵叫(猫继承动物的功能)

     狗:汪汪叫(狗继承动物的功能)

伪代码以下:
class 动物:

    def 吃(self):
        # do something

    def 喝(self):
        # do something

    def 拉(self):
        # do something

    def 撒(self):
        # do something

# 在类后面括号中写入另一个类名,表示当前类继承另一个类
class 猫(动物):

    def 喵喵叫(self):
        print '喵喵叫'
        
# 在类后面括号中写入另一个类名,表示当前类继承另一个类
class 狗(动物):

    def 汪汪叫(self):
        print '喵喵叫'




==========================第三部分
#继承的代码实现
class Animal:

    def eat(self):
        print("%s 吃 " %self.name)

    def drink(self):
        print ("%s 喝 " %self.name)

    def shit(self):
        print ("%s 拉 " %self.name)

    def pee(self):
        print ("%s 撒 " %self.name)


class Cat(Animal):

    def __init__(self, name):
        self.name = name
        self.breed = ''

    def cry(self):
        print('喵喵叫')

class Dog(Animal):

    def __init__(self, name):
        self.name = name
        self.breed=''

    def cry(self):
        print('汪汪叫')


# ######### 执行 #########

c1 = Cat('小白家的小黑猫')
c1.eat()

c2 = Cat('小黑的小白猫')
c2.drink()

d1 = Dog('胖子家的小瘦狗')
d1.eat()
继承的重要性的案例

 

在开发程序的过程当中,若是咱们定义了一个类A,而后又想新创建另一个类B,可是类B的大部份内容与类A的相同时

咱们不可能从头开始写一个类B,这就用到了类的继承的概念。

经过继承的方式新建类B,让B继承A,B会‘遗传’A的全部属性(数据属性和函数属性),实现代码重用

 

二、派生的用法

派生:就是在调用父级的内容以后,在继续使用父级的内容,还能够在子类里面添加本身的新功能,且还能保留父类的功能

固然子类也能够添加本身新的属性或者在本身这里从新定义这些属性(不会影响到父类),须要注意的是,一旦从新定义了本身的属性且与父类重名,那么调用新增的属性时,就以本身为准了。

 

 

class Hero:   #父级类
    def __init__(self, nickname,aggressivity,life_value):
        self.nickname = nickname     #名字
        self.aggressivity = aggressivity   #攻击力
        self.life_value = life_value        #生命
    def attack(self,enemy):             #攻击
        print('from Hero attack')
        enemy.life_value-=self.aggressivity

class Garen(Hero):  #子类调用分类

    def __init__(self, nickname, aggressivity, life_value, script):
        Hero.__init__(self, nickname, aggressivity, life_value)
        self.script = script

    def attack(self, enemy):  #在本身的子类中写入父类的这个方法,在添加新的功能
        Hero.attack(self, enemy)    #调用父类的功能
        print('from Garen attack')

class Riven(Hero): #子类调用分类
    pass
g1 = Garen('yang',200,454,12012) #子类写入本身的属性
r1 = Riven('r1',250,500)   #子类写入本身的属性
print(g1.script)
g1.attack(g1)

'''
在保留父级的功能,本身写的新功能也有
结果:
    from Hero attack
    from Garen attack
'''

4、组合的重要性

  组合指的是,在一个类中以另一个类的对象做为数据属性,称为类的组合

'''
组合、继承
组合是:有效的;利用相同的资源,
例如:老师是教授“python"课程的,学生是学习”python“课程的
那么就能够写一个课程的类,来让双方调用。

'''
class Course:  #课程的类
    def __init__(self,course_name,course_price,course_time):
        self.course_name = course_name
        self.course_price = course_price
        self.course_time = course_time

class Hero:  #父类
    def __init__(self,name,age,course):
        self.name = name
        self.age = age
        self.course = course    #course = course_obj = Course('python',15800,'7m')
    '''
     def kecheng(self):
        '这里就至关于被调用的子类均可以使用,可是是被写死的,学生就不能使用了,使用课程下的类的实例化属性,'
        print('%s正在教授【%s】课程....'%(self.name,self.course.course_name))
    '''

class Teacher(Hero):
    teacher = '老师'

    def kecheng(self):
        '写在本身的类当中,写死了也没毛病,学生要用在本身去写去,使用课程下的类的实例化属性,'
        print('%s正在教授【%s】课程....' % (self.name, self.course.course_name))

class Student(Hero):
    student = '学生'
    def kecheng(self):
        print('%s正在学习【%s】课程....' % (self.name,self.course.course_name))

course_obj  = Course('python',15800,'7m') #将课程的类实例化,在引入你须要的类当中
t1 = Teacher('engo',20,course_obj)    #
s1 = Student('engo',20,course_obj)

t1.kecheng()  #调用老师里面的课程的函数属性。
'''
其实还能够在将课程的这个函数属性写入父类里面,在进行调用,若是在须要单独添加功能,再去本身类的函数中添加
以下:

    #父类的

  def kecheng(self):
        print('这是父类写的功能)


#子类的

    def kecheng(self):
        print('%s正在学习【%s】课程....' % (self.name,self.course.course_name))

'''

 

五、接口与归一化设计

 使用python模拟一个借口的效果

class Hero:
    def run(self):  #模拟跑的接口
        pass

class People(Hero):
    def run(self):      #人在跑
        print('people running')


class Dog(Hero):
    def run(self): #狗在跑
        print('dog running')

p1 = People()
p1.run()
d1 = Dog()
d1.run()
'''
结果:
people running
dog running
'''
模拟接口

 

 强行让子类使用某个功能,添加抛出异常

class Animal:
    def run(self):
        raise AttributeError('子类必须实现这个方法') #抛出异常
    def speak(self):
        raise AttributeError('子类必须实现这个方法')、
class People(Animal): def run(self): print('人正在走') def speak(self): print('说话') class Pig(Animal): def run(self): print('pig is walking') def speak(self): print('哼哼哼') peo1=People() # peo1.run() peo1.speak() #如今people这个类的speak函数是没有的,就在父类里面找,父类里面的speak函数是一个报错异常,就是让子类必须执行speak这个函数

 

6、抽象类

1 什么是抽象类

    与java同样,python也有抽象类的概念可是一样须要借助模块实现,抽象类是一个特殊的类,它的特殊之处在于只能被继承,不能被实例化

2 为何要有抽象类

    若是说类是从一堆对象中抽取相同的内容而来的,那么抽象类是从一堆中抽取相同的内容而来的,内容包括数据属性和函数属性。

  好比咱们有香蕉的类,有苹果的类,有桃子的类,从这些类抽取相同的内容就是水果这个抽象的类,你吃水果时,要么是吃一个具体的香蕉,要么是吃一个具体的桃子。。。。。。你永远没法吃到一个叫作水果的东西。

    从设计角度去看,若是类是从现实对象抽象而来的,那么抽象类就是基于类抽象而来的。

  从实现角度来看,抽象类与普通类的不一样之处在于:抽象类中只能有抽象方法(没有实现功能),该类不能被实例化,只能被继承,且子类必须实现抽象方法。这一点与接口有点相似,但实际上是不一样的,即将揭晓答案

3. 在python中实现抽象类

import abc
#使用abc模块进行强制抛出异常,
#就是在父类的函数上加一个@abc.abstractmethod装饰器的功能,那么子类就必需要使用这个函数功能,不然就报错。
class Hero:
    @abc.abstractmethod
    def run(self):
        pass
    @abc.abstractmethod
    def speak(self):
        pass
class Teacher(Hero):
    def run(self):
        print('run')
    def speak(self):
        print('speak')


class Student(Hero):
    def run(self):
        print('run')
    def speak(self):
        print('speak')

t1 = Teacher()
s1 = Student()
t1.run()
抽象类

7、继承原理(子类的优先级)

在python3中是广度优先,看下面的实例

能够经过.__mro__的方式去查看绑定的父类

#python3是以广度优先的原理来进行继承的关系,广度优先是的分支不会一次性找到最后一个
# class A(object):
#     def test(self):
#         print('from A')
#     pass
# class B(A):
#     # def test(self):
#     #     print('from B')
#     pass
# class C(A):
#     # def test(self):
#     #     print('from C')
#     pass
# class D(B):
#     # def test(self):
#     #     print('from D')
#     pass
# class E(C):
#     # def test(self):
#     #     print('from E')
#     pass
#
# class F(D,E):
#     # def test(self):
#     #     print('from F')
#     pass
# f1=F()
# f1.test()
#f->d->b->e->c->a->a(object)


'''
python3中是广度优先的分支不会一次性找到最后一个,
这是只有一个父类的时候。
到了最后一个就会找第二个分支的父类,一直找到最后一个也没找到的话,
就继续往下一个分支去找,一直找到最后一个分支都没有找到就找最后的那个头
'''
一个父类的实例
class x(object):
    def test(self):
        print('from X')

class y(object):
    def test(self):
        print('from Y')

class b(x):
    def test(self):
        print('from B')

class c(y):
    def test(self):
        print('from C')

class d(b):
    def test(self):
        print('from D')

class e(c):
    def test(self):
        print('from E')

class f(d,e):
    def test(self):
        print('from F')

print(f.mro())  #f>>>d>>>b>>>x>>>e>>>c>>>y>>>(object)

'''
python3中,当有两个父类的时候,
就不太同样了,先找第一条的路线,一直找到最后一个,
当最后一个也没有的话就找第二条的父类,直到找到为止。
两个父类的实例

 图详解:


 

 

在python2中(深度优先)

在python2不能使用.__mro__的方式去查看

#python2中经典类的继承,在查找属性时遵循:深度优先
# class A:
#     # def test(self):
#     #     print('from A')
#     pass
# class B(A):
#     # def test(self):
#     #     print('from B')
#     pass
# class C(A):
#     # def test(self):
#     #     print('from C')
#     pass
# class D(B):
#     # def test(self):
#     #     print('from D')
#     pass
#
# class E(C):
#     # def test(self):
#     #     print('from E')
#     pass
# class F(D,E):
#     # def test(self):
#     #     print('from F')
#     pass
# f1=F()
# f1.test()

# F->D->B->A->E->C
'''
python2中经典类的继承,在查找属性时遵循:深度优先
在python2中是从一条道走到最后的父类,若是没有找到的话,在走第二条路线。这样找的。
'''
python2中深度优先实例

 

 

8、super()的使用

子类继承了父类的方法,而后想进行修改,注意了是基于原有的基础上修改,那么就须要在子类中调用父类的方法

# #super在python2中的用法:
#     # 1:super(本身的类,self).父类的函数名字
#     # 2:super只能用于新式类
# class People(object):
#     def __init__(self,name,sex,age):
#         self.name=name
#         self.age=age
#         self.sex=sex
#     def walk(self):
#         print('%s is walking' %self.name)
# class Chinese(People):
#     country='China'
#     def __init__(self,name,sex,age,language='Chinese'):
#         # self.name=name
#         # self.sex=sex
#         # self.age=age
#         # People.__init__(self,name,sex,age)
#         super(Chinese,self).__init__(name,sex,age)
#         self.language=language
# c=Chinese('egon','male',18)
# print c.name,c.age,c.sex,c.language
python2中super的使用

 

#python3的super()用法
class people:
    def __init__(self,name,age,sex):
        self.name = name
        self.age = age
        self.sex = sex

class chinese(people):
    def __init__(self,name,age,sex,language):
        # super(people,self) 就至关于实例自己 在python3中super()等同于super(Subway,self)
        super().__init__(name,age,sex)
        self.language = language

print(chinese.mro()) #一个新的方法,查看父类。
c = chinese('yang','male',20,'chinese')
print(c.name,c.age,c.sex,c.language)

'''
使用super调用的全部属性,都是从mro列表当前的位置日后找,千万不要经过看代码去找继承关系,必定要看mro列表
'''
python3中super的使用

 

 

9、多态与多态性

不少人喜欢将两者混为一谈,而后百思不得其解,其实只要分开看,就会很明朗    

九.1多态

多态指的就是常使用的多态性,方法相同结果不一样。

多态指的是一类事物有多种形态,(一个抽象类有多个子类,于是多态的概念依赖于继承)

 

 

 

#多态:同一种事物的多种形态动物分为人类、狗类等等....
class Hero:
    def run(self):
        print('这是父类定义的这个函数')
class People(Hero):
    def run(self):
        print('人在跑')

class Dog(Hero):
    def run(self):
        print('人在跑')

class Big(Hero):
    def run(self):
        print('人在跑')

'''
同一种类的不一样对象,调用的属性相同

'''
多态

 

 

九.2多态性

  多态指的是一类事物有多种形态,(一个抽象类有多个子类,于是多态的概念依赖于继承)

 

 

其实你们从上面多态性的例子能够看出,咱们并无增长什么新的知识,也就是说python自己就是支持多态性的,这么作的好处是什么呢?

1.增长了程序的灵活性

  以不变应万变,不论对象变幻无穷,使用者都是同一种形式去调用,如func(animal)

2.增长了程序额可扩展性

经过继承animal类建立了一个新的类,使用者无需更改本身的代码,仍是用func(animal)去调用 

#定义类的阶段,多态性

class Hero:
    def run(self):
        print('这是父类定义的这个函数')
class People(Hero):
    def run(self):
        print('人在跑')

class Dog(Hero):
    def run(self):
        print('人在跑')

class Big(Hero):
    def run(self):
        print('人在跑')

p1 = People()
p2 = Big()
d1 = Dog()
# p1.run()
# p2.run()
# d1.run()

#多态性,一种调用方式,不一样的执行效果
#这是至关定义一个接口,那么使用者就能够直接传参就可使用了。。
def func(obj):#obj这个参数没有类型限制,能够传入不一样类型的值
    obj.run()#调用的逻辑都同样,执行的结果却不同
'''
同一个接口,传入的参数没有类型限制,实现不一样的功能。。
多态性:
    1.继承父类的共同特征和技能
    2.
多态性:定义赞成的接口,能够传入不一样类型的值,可是调用的逻辑都同样,执行结果却不一样,
'''
func(p1)
func(p2)
func(d1)
多态性

 

10、封装

封装数据的主要缘由是:保护隐私(做为男人的你,脸上就写着:我喜欢男人,你惧怕么?)

封装方法的主要缘由是:隔离复杂度(快门就是傻瓜相机为傻瓜们提供的方法,该方法将内部复杂的照相功能都隐藏起来了,好比你没必要知道你本身的尿是怎么流出来的,你直接掏出本身的接口就能用尿这个功能)

你的身体没有一处不体现着封装的概念:你的身体把膀胱尿道等等这些尿的功能隐藏了起来,而后为你提供一个尿的接口就能够了(接口就是你的。。。,),你总不能把膀胱挂在身体外面,上厕所的时候就跟别人炫耀:hi,man,你瞅个人膀胱,看看我是怎么尿的。还有你的头把你的脑子封装到了脑袋里,而后提供了眼睛这个接口....

提示:在编程语言里,对外提供的接口(接口可理解为了一个入口),就是函数,称为接口函数,这与接口的概念还不同,接口表明一组接口函数的集合体。

 



 

class A:
    __x = 1   #_A__x = 1 变形
    def __init__(self,name):
        self.name = name
    def __test(self):
        print('from a')


a = A('yang')
A.__x = 2
a.__x = 2
print(A.__dict__)
print(a.__dict__)
# print(A.__x)
# print(a._A__x)
print(A._A__x)
print(a.__x)
a._A__test()  #
A._A__test(1111)
'''
这是引用变量的方式
print(A._A__x):在类里面已经变形了,因此在打印的时候是类名._A__x的方式去打印出来
print(a.__x) :在类里面已经变形了,因此在打印的时候是对象._A__x的方式去打印出来
这是引用函数的方式
a._A__test()  :在类里面已经变形了,因此在打印的时候是对象._A__x的方式去打印出来
A._A__test(1111) :也是同样的,在类里面就已经变形了,因此引用的方式是类名._A__x的方式
在外部增长新的变量,
A.__x = 2 :这是经过类名.__x的方式去增长的,因此你打印的话也是这样去引用,并无在类里面去定义,
a.__x = 2 :这是经过对象.__x的方式去增长的,因此你打印的话也是这样去引用,这也是定义在实例化里面
...............................
以上的方式均可以经过类.__dict__的方式去查看,
以上的方式均可以经过对象.__dict__的方式去查看,

#__名字,这种语法,只在定义的时候才会有变形的效果,若是类或者对象已经产生了,就不会有变形的效果了
'''

 

封装的

class A:
    def fa(self):
        print('from a')
    def test(self):
        self.fa()
class B(A):
    def fa(self):
        print('from b')
    pass


b = B()
# b.fa()
b.test()#寻找的过程是b.test-->B-->A--->A.test()--->A.

'''
b.test()
这个找的过程是。
b.test-->B-->A--->A.test-->b.fa()
若是B里面没有fa()这个函数,那么就在A里面去找了,A里面也没有那么久报错了

'''

 


在内部能够直接用__名字来访问到变形的属性
class A:
    def __init__(self):
        self.__x = 1
    def tell(self):
        print(self.__x)  #在内部能够直接用__名字来访问到变形的属性

a = A()
# print(a.__dict__)
A.tell(a)

 

 

class A:
    def __fa(self):
        print('from a')
    def test(self):
        self.__fa()
class B(A):
    def __fa(self):
        print('from b')
    pass

b = B()
b.test()
'''
#由于在定义的阶段已经变形了因此子类在引用父类的时候,
# 调用的test()里面的__fa()就已是_A__fa()
'''
在定义阶段就会变形

 

 十一特性

 1 #property优先级,是先找property下面的,在找类里面的
 2 #@property(age):在函数上面加一个相似装饰器的函数,再次执行类里面的函数就可使用对象.属性的方式去执行,不须要加()执行了
 3 #@age.setter:能够进行动态修改已经被修装的属性对象,
 4 # @age.deleter:绑定方法删除功能
 5 
 6 #检测BMI指数
 7 # class people:
 8 #     def __init__(self,name,width,height):
 9 #         self.name = name
10 #         self.width = width
11 #         self.height = height
12 #     @property
13 #     #在函数上面加一个相似装饰器的函数,再次执行类里面的函数就可使用对象.属性的方式去执行,不须要加()执行了
14 #     def bodyindex(self):
15 #         return self.width/(self.height ** 2)
16 #
17 # p = people('yang',80,1.80)
18 # print(p.bodyindex)
19 
20 
21 
22 class People:
23     def __init__(self,name,age):
24         self.name = name
25         # self.__age = age #这个就不会再初始化的时候执行函数属性的额方法
26         self.age = age   #若是是这样的话,在初始化的时候,就会执行函数属性的方法,p.age = 222
27 
28     @property
29 #在函数上面加一个相似装饰器的函数,再次执行类里面的函数就可使用对象.属性的方式去执行,不须要加()执行了
30     def age(self):
31         return self.__age   #p.__age = 222
32 
33     '''
34     1.这个是能够进行动态修改已经被修装的属性对象,
35     2.将已经有的函数进行一个装饰器的方法,这是固定的,将已有的函数进行更改,该函数下面有一个setter固定的方法
36     3.须要更改内容,是要添加一个参数,
37     4.咱们要改什么属性,就将该属性 = 你的参数
38     '''
39     @age.setter
40     def age(self,value):
41         if not isinstance(value,int): #判断若是不是你指定的类型,
42             raise TypeError('必须是整数型') #进行一个主动抛出异常的用法
43         self.__age = value  #须要修改的类型,是这个已经变形的对象  p.__age = 222
44 
45     @age.deleter
46     def age(self):
47         del self.__age #del p.__age
48 
49 #在初始化的时候,__对象的方式是不会被修改的,可是.对象的方式就会修改,是将一个函数的以属性的方式给的
50 p = People('yang',222)
51 # print(p.age)
52 # p.age = 222
53 print(p.age)
54 del p.age
55 print(People.__dict__)
property的功能

 

 12、静态方法和类方法

有三种方法:

  • 1.被对象绑定的方法
  • 2.不被绑定的方法staticmethod
  • 3.新的实例化绑定classmethod

  1.静态方法

  初识staticmethod

class Foo:
    def spam(x,y,z): #类里面的一个函数,而且x,y,z都是参数和self都是同样的
        print(x,y,z)
    spam=staticmethod(spam)#把spam函数作成静态方法
l = Foo()
l.spam(1,2,3)

 

将staticmethod设置成装饰器

 1 class Foo:
 2     @staticmethod  #spam = staticmethod(spam) 使用这个装饰器,那么当前的这个函数就适用于这个类
 3     def spam(x,y,z):
 4         print(x,y,z)
 5 print(type(Foo.spam)) #他的类型就是一个函数,
 6 Foo.spam(1,2,3)  #使用类.函数属性(加上你的参数)
 7 f = Foo()
 8 f.spam(1,2,3) #使用实例对象.函数属性(加上你的参数)
 9 '''
10 <class 'function'>
11 1 2 3
12 1 2 3
13 '''

应用场景:编写类时须要采用不少不一样的方式来建立实例,而咱们只有一个__init__函数,此时静态方法就派上用场了

 1 import time
 2 class Date:
 3     def __init__(self,year,month,day):
 4         self.year = year
 5         self.month = month
 6         self.day = day
 7     @staticmethod   #若是不加staticmethod方法类能够调用,实例就不能调用了
 8     def today():#用Date.today()的方式去建立实例,该实例用的是当前的时间
 9         #获取结构化的时间{time.struct_time(tm_year=2017, tm_mon=4, tm_mday=22, tm_hour=16, tm_min=27, tm_sec=46, tm_wday=5, tm_yday=112, tm_isdst=0)}
10         t = time.localtime()
11         # print(t)
12         obj = Date(t.tm_year,t.tm_mon,t.tm_mday)#直接在内部进行了实例化,而且给一个返回值
13         return obj
14     @staticmethod
15     def tomorrow():
16         t = time.localtime(time.time()+86400)
17         # print(t)
18         obj = Date(t.tm_year,t.tm_mon,t.tm_mday)#直接在内部进行了实例化,而且给一个返回值
19         return obj
20 
21 #但凡是定义在类的内部,而且没有被任何装饰器修饰过的方法,都是绑定方法:有自动传值功能
22 a = Date(2017,2,4)#定义本身的时间
23 a1 = a.today() #绑定的方法也是有返回值的。在进行调用
24 print(a1.year,a1.day)
25 print(Date.today())
26 
27 #但凡是定义在类的内部,而且被staticmethod装饰器修饰过的方法,都是解除绑定的方法,实际上就函数:就没有自动传值功能了
28 b = Date.today()#采用当前的时间
29 c = Date.tomorrow()
30 print(b.day,b.month,b.year)
31 print(c.day,c.month,c.year)

 

 

2.类方法

@classmethod也不须要self参数,但第一个参数须要是表示自身类的cls参数。

class Foo:
    def bar(self):#这个属于绑定方法,直接.的方式就能使用
        pass
    # 把一个方法绑定给类,类.绑定到类的方法(),
    # 会把类自己当作第一个参数自动给绑定到类的方法
    @classmethod
    def test(cls,x):
        print(cls,x)#拿掉一个类的内存地址后,就可实例化或者引用类的属性了

f = Foo()
Foo.test(1)#
f.test(1)#也是直接将对象传给第一个值,

classmethod的使用场景

import time
class Date:
    def __init__(self,year,month,day):
        self.year = year
        self.month = month
        self.day = day
    @classmethod #产生新的实例去使用
    def now(cls):#用Date.now()的形式去产生实例,该实例用的是当前时间
        print(cls)
        t = time.localtime()#获取结构化的时间格式
        obj = cls(t.tm_year,t.tm_mon,t.tm_mday)#新建实力而且返回
        return obj

    @classmethod
    def tomorrow(cls):#用Date.tomorrow()的形式去产生实例,该实例用的是当前时间
        print(cls)
        t = time.localtime(time.time()+86400)
        obj = cls(t.tm_year, t.tm_mon, t.tm_mday)
        return obj

class Eurodate(Date):
    def __str__(self):
        return '年:%s,月:%s,日:%s'%(self.year,self.month,self.day)

# f = Eurodate(2017,1,1)
f = Eurodate.now()
print(f)

 

在类内部定义的函数无非三种用途

一:绑定到对象的方法
    只要是在类内部定义的,而且没有被任何装饰器修饰过的方法,都是绑定到对象的
    
    class Foo:
        def test(self): #绑定到对象的方法
            pass
        def test1(): #也是绑定到对象的方法,只是对象.test1(),会把对象自己自动传给test1,因test1没有参数因此会抛出异常
            pass
    
    绑定到对象,指的是:就给对象去用,
    使用方式:对象.对象的绑定方法(),不用为self传值
    特性:调用时会把对象自己当作第一个参数传给对象的绑定方法
    

    
二:绑定到类的方法:classmethod
    在类内部定义的,而且被装饰器@classmethod修饰过的方法,都是绑定到类的
    
    class Foo:
        def test(self): #绑定到对象的方法
            pass
        def test1(): #也是绑定到对象的方法,只是对象.test1(),会把对象自己自动传给test1,因test1没有参数因此会抛出异常
            pass
    
    绑定到对象,指的是:就给对象去用,
    使用方式:对象.对象的绑定方法()
    特性:调用时会把对象自己当作第一个参数传给对象的绑定方法
    
    
三:解除绑定的方法:staticmethod
    既不与类绑定,也不与对象绑定,不与任何事物绑定
    绑定的特性:自动传值(绑定到类的就是自动传类,绑定到对象的就自动传对象)
    解除绑定的特性:无论是类仍是对象来调用,都没有自动传值这么一说了
    
    因此说staticmethod就是至关于一个普通的工具包
    
    
class Foo:
    def test1(self):
        pass
    def test2():
        pass
    

    
    @classmethod
    def test3(cls):
        pass
    @classmethod
    def test4():
        pass
        
        
        
    @staticmethod
    def test5():
        pass
        
test1与test2都是绑定到对象方法:调用时就是操做对象自己
    <function Foo.test1 at 0x0000000000D8E488>
    <function Foo.test2 at 0x0000000000D8E510>
test3与test4都是绑定到类的方法:调用时就是操做类自己
    <bound method Foo.test3 of <class '__main__.Foo'>>
    <bound method Foo.test4 of <class '__main__.Foo'>>
test5是不与任何事物绑定的:就是一个工具包,谁来均可以用,没说专门操做谁这么一说
    <function Foo.test5 at 0x0000000000D8E6A8>

 

小白容易犯的错误

1.面向对象的程序设计看起来高大上,因此我在编程时就应该保证通篇class,这样写出的程序必定是好的程序(面向对象只适合那些可扩展性要求比较高的场景)

2.不少人喜欢说面向对象三大特性(这是从哪传出来的,封装,多态,继承?漏洞太多太多,好吧暂且称为三大特性),那么我在基于面向对象编程时,我必定要让我定义的类中完整的包含这三种特性,这样写确定是好的程序

好家伙,我说降龙十八掌有十八掌,那么你每次跟人干仗都要从第一掌打到第18掌这才显得你会了是么,我来一万我的你须要打10000*18掌对么,傻叉

3.类有类属性,实例有实例属性,因此咱们在定义class时必定要定义出那么几个类属性,想不到怎么办,那就使劲的想,定义的越多越牛逼

这就犯了一个严重的错误,程序越早面向对象,死的越早,为啥面向对象,由于咱们要将数据与功能结合到一块儿,程序总体的结构都没有出来,或者说须要考虑的问题你都没有搞清楚个八九不离十,你就开始面向对象了,这就致使了,你在那里干想,自觉得想通了,定义了一堆属性,结果后来又都用不到,或者想不通到底应该定义啥,那就一直想吧,想着想着就疯了。

你见过哪家公司要开发一个软件,上来就开始写,确定是频繁的开会讨论计划,请看第八节

4.既然这么麻烦,那么我完全解脱了,咱们不要用面向对象编程了,你啊,你有大才,你能成事啊,傻叉。

 

python中关于OOP的经常使用术语

抽象/实现

抽象指对现实世界问题和实体的本质表现,行为和特征建模,创建一个相关的子集,能够用于 绘程序结构,从而实现这种模型。抽象不只包括这种模型的数据属性,还定义了这些数据的接口。

对某种抽象的实现就是对此数据及与之相关接口的现实化(realization)。现实化这个过程对于客户 程序应当是透明并且无关的。 

封装/接口

封装描述了对数据/信息进行隐藏的观念,它对数据属性提供接口和访问函数。经过任何客户端直接对数据的访问,无视接口,与封装性都是背道而驰的,除非程序员容许这些操做。做为实现的 一部分,客户端根本就不须要知道在封装以后,数据属性是如何组织的。在Python中,全部的类属性都是公开的,但名字可能被“混淆”了,以阻止未经受权的访问,但仅此而已,再没有其余预防措施了。这就须要在设计时,对数据提供相应的接口,以避免客户程序经过不规范的操做来存取封装的数据属性。

注意:封装毫不是等于“把不想让别人看到、之后可能修改的东西用private隐藏起来”

真正的封装是,通过深刻的思考,作出良好的抽象,给出“完整且最小”的接口,并使得内部细节能够对外透明

(注意:对外透明的意思是外部调用者能够顺利的获得本身想要的任何功能,彻底意识不到内部细节的存在)

合成

合成扩充了对类的 述,使得多个不一样的类合成为一个大的类,来解决现实问题。合成 述了 一个异常复杂的系统,好比一个类由其它类组成,更小的组件也多是其它的类,数据属性及行为, 全部这些合在一块儿,彼此是“有一个”的关系。

派生/继承/继承结构

派生描述了子类衍生出新的特性,新类保留已存类类型中全部须要的数据和行为,但容许修改或者其它的自定义操做,都不会修改原类的定义。
继承描述了子类属性从祖先类继承这样一种方式
继承结构表示多“代”派生,能够述成一个“族谱”,连续的子类,与祖先类都有关系。

泛化/特化

基于继承
泛化表示全部子类与其父类及祖先类有同样的特色。
特化描述全部子类的自定义,也就是,什么属性让它与其祖先类不一样。

多态与多态性

多态指的是同一种事物的多种状态:水这种事物有多种不一样的状态:冰,水蒸气

多态性的概念指出了对象如何经过他们共同的属性和动做来操做及访问,而不需考虑他们具体的类。

冰,水蒸气,都继承于水,它们都有一个同名的方法就是变成云,可是冰.变云(),与水蒸气.变云()是大相径庭的过程,虽然调用的方法都同样

自省/反射

自省也称做反射,这个性质展现了某对象是如何在运行期取得自身信息的。若是传一个对象给你,你能够查出它有什么能力,这是一项强大的特性。若是Python不支持某种形式的自省功能,dir和type内建函数,将很难正常工做。还有那些特殊属性,像__dict__,__name__及__doc__

相关文章
相关标签/搜索