day6_面向对象和类

来源:互联网 发布:焦大seo自媒体 编辑:程序博客网 时间:2024/06/02 17:26

subprocess模块

subprocess 是一个与系统命令进行交互的模块,先回顾下之前的与系统交互的os模块。

import os      >>> os.system('ls -l')      #执行操作系统命令,只返回命令的执行状态(0:成功,非0:失败),不返回命令的执行结果。总用量 25840drwxr-xr-x. 3 root root     4096 7月  14 19:19 a-rw-------. 1 root root     1546 625 05:56 anaconda-ks.cfgdrwxr-xr-x  3 root root     4096 9月   1 17:09 b-rw-r--r--. 1 root root    43389 625 05:56 install.log-rw-r--r--. 1 root root    10033 625 05:52 install.log.syslog-rw-r--r--. 1 root root 26377004 714 12:50 lnmp-install.logdrwxr-xr-x  3 root root     4096 9月  12 16:06 python>>> res  = os.system('ls -l')总用量 25840drwxr-xr-x. 3 root root     4096 7月  14 19:19 a-rw-------. 1 root root     1546 625 05:56 anaconda-ks.cfgdrwxr-xr-x  3 root root     4096 9月   1 17:09 b-rw-r--r--. 1 root root    43389 625 05:56 install.log-rw-r--r--. 1 root root    10033 625 05:52 install.log.syslog-rw-r--r--. 1 root root 26377004 714 12:50 lnmp-install.logdrwxr-xr-x  3 root root     4096 9月  12 16:06 python>>> res    #0表示成功0
>>> os.popen('pwd')     执行操作系统命令,不返回命令的执行状态,只返回命令的执行结果。<os._wrap_close object at 0x7febfc17fc50>>>> res = os.popen('pwd')>>> print(res)<os._wrap_close object at 0x7febfc0e5b70>>>> print(res.read)<built-in method read of _io.TextIOWrapper object at 0x7febfb7db120>>>> print(res.read())    #执行popen()不是直接返回命令的执行结果的,而是需要read一下,这是因为popen相当于打开了一个文件,它把结果存到文件中,只不过它是相当于存在内存中了,但是你好像打开文件的样子去取一样。/root

subprocess.run()运行命令,返回命令执行的结果(python3.5以后的版本才会有这个命令)

>>> import subprocess>>> subprocess.run(['df','-h'])Filesystem            Size  Used Avail Use% Mounted on/dev/mapper/VolGroup-lv_root                       47G  7.4G   37G  17% /tmpfs                 931M   72K  931M   1% /dev/shm/dev/sda1             477M   35M  418M   8% /bootCompletedProcess(args=['df', '-h'], returncode=0)

subprocess.call()

>>> res = subprocess.call(["ls","-l"])总用量 25840drwxr-xr-x. 3 root root     4096 7月  14 19:19 a-rw-------. 1 root root     1546 625 05:56 anaconda-ks.cfgdrwxr-xr-x  3 root root     4096 9月   1 17:09 b-rw-r--r--. 1 root root    43389 625 05:56 install.log-rw-r--r--. 1 root root    10033 625 05:52 install.log.syslog-rw-r--r--. 1 root root 26377004 714 12:50 lnmp-install.logdrwxr-xr-x  3 root root     4096 9月  12 16:06 python>>> res0

subprocess.check_call() 执行命令,如果执行结果为0,正常返回,否则抛异常

>>> res = subprocess.check_call(["ls","-l"])总用量 25840drwxr-xr-x. 3 root root     4096 7月  14 19:19 a-rw-------. 1 root root     1546 625 05:56 anaconda-ks.cfgdrwxr-xr-x  3 root root     4096 9月   1 17:09 b-rw-r--r--. 1 root root    43389 625 05:56 install.log-rw-r--r--. 1 root root    10033 625 05:52 install.log.syslog-rw-r--r--. 1 root root 26377004 714 12:50 lnmp-install.logdrwxr-xr-x  3 root root     4096 9月  12 16:06 python>>>>>> res0

subprocess.getstatusoutput() 接收字符串形式的命令,返回元组形式,第1个元素是执行状态,第二个是命令结果

>>> subprocess.getstatusoutput('ls /bin/ls')(0, '/bin/ls')

subprocess.getoutput() 接收字符串形式的命令,并且返回命令的结果

>>> subprocess.getoutput('ls /bin/ls')'/bin/ls'

subprocess.check_output() 执行命令,并且返回结果,不是打印

>>> res = subprocess.check_output(["ls","-l"])>>> resb'\xe6\x80\xbb\xe7\x94\xa8\xe9\x87\x8f 25840\ndrwxr-xr-x. 3 root root     4096 7\xe6\x9c\x88  14 19:19 a\n-rw-------. 1 root root     1546 6\xe6\x9c\x88  25 05:56 anaconda-ks.cfg\ndrwxr-xr-x  3 root root     4096 9\xe6\x9c\x88   1 17:09 b\n-rw-r--r--. 1 root root    43389 6\xe6\x9c\x88  25 05:56 install.log\n-rw-r--r--. 1 root root    10033 6\xe6\x9c\x88  25 05:52 install.log.syslog\n-rw-r--r--. 1 root root 26377004 7\xe6\x9c\x88  14 12:50 lnmp-install.log\ndrwxr-xr-x  3 root root     4096 9\xe6\x9c\x88  12 16:06 python\n'>>>

面向对象

面向过程又被称为top-down languages, 就是程序从上到下一步步执行,一步步从上到下,从头到尾的解决问题 。基本设计思路就是程序一开始是要着手解决一个大的问题,然后把一个大问题分解成很多个小问题或子过程,这些子过程再执行的过程再继续分解直到小问题足够简单到可以在一个小步骤范围内解决。
面向过程的缺点就是如果你要对程序进行修改,对你修改的那部分有依赖的各个部分你都也要跟着修改,所以一般的,我们认为,如果只是写一些简单的脚本,去做一些一次性任务,用面向过程的方式是极好的,但如果你要处理的任务是复杂的,且需要不断迭代和维护 的, 那还是用面向对象最方便了。
面向对象(OOP编程)是利用“类”和“对象”来创建各种模型来实现对真实世界的描述,使用面向对象编程的原因一方面是因为它可以使程序的维护和扩展变得更简单,并且可以大大提高程序开发效率 ,另外,基于面向对象的程序可以使它人更加容易理解你的代码逻辑,从而使团队开发变得更从容。


面向对象的核心

class类
一个类即是对一类拥有相同属性的对象的抽象、蓝图、原型。在类中定义了这些对象的都具备的属性(variables(data))、共同的方法。


Object 对象
一个对象即是一个类的实例化后实例,一个类必须经过实例化后方可在程序中调用,一个类可以实例化多个对象,每个对象亦可以有不同的属性,就像人类是指所有人,每个人是指具体的对象,人与人之前有共性,亦有不同


Encapsulation 封装
在类中对数据的赋值、内部调用对外部用户是透明的,这使类变成了一个胶囊或容器,里面包含着类的数据和方法
封装的作用:
防止对象的数据被随意修改
使外部程序不需要关注对象内部的构造,只需要通过此对象对外提供的接口进行直接访问即可


Inheritance 继承
一个类可以派生出子类,在这个父类里定义的属性、方法自动被子类继承。
通过父类–>子类的方式以最小代码量的方式实现,不同角色的共同点和不同点的同时存在。


Polymorphism 多态
多态是面向对象的重要特性,简单点说:“一个接口,多种实现”,指一个基类中派生出了不同的子类,且每个子类在继承了同样的方法名的同时又对父类的方法做了不同的实现,这就是同一种事物表现出的多种形态。


写代码的原则:
1、写重复代码是非常不好的低级行为
2、你写的代码需要经常变更
用oop写一个简单cs游戏,警和匪具有相同的属性,都有枪,又有不同的属性,警察不能杀人质等。我们可以用简单的类来定义

#!/usr/bin/env python# -*- coding:utf-8 -*-class Role(object):    def __init__(self, name, role, weapon, life_value=100, money=15000):        self.name = name        self.role = role        self.weapon = weapon        self.life_value = life_value        self.money = money    def shot(self):        print("shooting...")    def got_shot(self):        print("ah...,I got shot...")    def buy_gun(self, gun_name):        print("just bought %s" % gun_name)r1 = Role('Alex', 'police', 'AK47') #生成一个角色r2 = Role('Jack', 'terrorist', 'B22')  #生成一个角色

相比靠函数拼凑出来的写法,上面用面向对象中的类来写最直接的改进有以下2点:
1、代码量少了近一半
2、角色和它所具有的功能可以一目了然看出来


类的概述


类的定义

#!/usr/bin/env python# -*- coding:utf-8 -*-#Author:liyananclass dog(object):    def __init__(self,name): #构造函数        self.NAME = name    def sayhi(self):        print("hello ,I am a dog.my name is ",self.NAME)print(dog)d = dog('li')d2 = dog('li2')d.sayhi()d2.sayhi()#输出<class '__main__.dog'>hello ,I am a dog.my name is  lihello ,I am a dog.my name is  li2

self?其实self 这个关键字相当于实例化对象本身(self相当于d),在实例化过程中,把自己传进去了。

这里写图片描述

在类中init()函数叫构造函数,又叫构造方法,也可以叫初始化函数。它的作用就是初始化实例时,初始化传入实例的的默认值。如果不写init(),就会调用的默认为空的init(),说白了,这个方法不管你写不写,都会调用,而且,一旦实例化就会调用。d实例化后产生的对象叫做实例。
大致过程:
这里写图片描述
其实self,就是实例本身!你实例化时python会自动把这个实例本身通过self参数传进去。


类的几个关键字:
1、定义类(class dog(object))-> 实例化(d = dog()) -> 实例化对象(d)
2、__init__()构造函数
3、self.name = name 被称为属性、成员变量、字段
4、def sayhi(self) 被称为方法、动态属性


私有属性:

类属性一旦被定义成私有的,对外是不可以被访问的,也是不可以随意被改变的。

class Role(object):    gb = 'JP'  #公有属性    def __init__(self, name, role, weapon, life_value=100, money=15000):        self.name = name        self.role = role        self.weapon = weapon        self.life_value = life_value        self.money = money        self.__heart = 'normal'  #私有属性    def shot(self):        print("%s is shooting..."% self.name)r1 = Role('Alex', 'police', 'AK47') #生成一个角色r2 = Role('Jack', 'terrorist', 'B22')  #生成一个角色print(r1.__heart)#输出Traceback (most recent call last):  File "D:/[4]python/untitled/学习/day6/公有属性.py", line 33, in <module>    print(r1.__heart)AttributeError: 'Role' object has no attribute '__heart'     #报错,说没有__heart这个属性

get方法访问私有属性
虽然我们外部不能访问私有属性,但是我们在类内部可以访问私有属性,所以我们用如下方法,访问私有属性

class Role(object):    gb = 'JP'  #公有属性    def __init__(self, name, role, weapon, life_value=100, money=15000):        self.name = name        self.role = role        self.weapon = weapon        self.life_value = life_value        self.money = money        self.__heart = 'normal'  #私有属性    def shot(self):        print("%s is shooting..."% self.name)r1 = Role('Alex', 'police', 'AK47') #生成一个角色r2 = Role('Jack', 'terrorist', 'B22')  #生成一个角色print(r1.get_heart())#输出normal    #输出r1定义的私有属性默认normal

强制访问私有属性
上面的方法只能访问,但是不能修改,下面这种方法就更为暴力,可以访问也可以修改,就是:对象名.类名_属性名

#!/usr/bin/env python# -*- coding:utf-8 -*-class Role(object):    gb = 'JP'  #公有属性    def __init__(self, name, role, weapon, life_value=100, money=15000):        self.name = name        self.role = role        self.weapon = weapon        self.life_value = life_value        self.money = money        self.__heart = 'normal'  #私有属性    def shot(self):        print("%s is shooting..."% self.name)    def get_heart(self):        return self.__heart    def got_shot(self):        print("ah...,I got shot...")    def buy_gun(self, gun_name):        print("just bought %s" % gun_name)def shot2(self):    print('run my own shot',self.name)r1 = Role('Alex', 'police', 'AK47') #生成一个角色r2 = Role('Jack', 'terrorist', 'B22')  #生成一个角色#print(r1.__heart)print(r1.get_heart())print(r1._Role__heart)r1._Role__heart = 100    #修改私有属性print(r1._Role__heart)#输出normalnormal100

公有属性

现在我们来说说类的公有属性,这边很容易被人弄混淆,有人觉的,在init()构造方法中,除了私有属性,其他的都是公有属性了,其实这是一个错误的结论,并不是定义在init()初始化方法中的属性是公有属性(除私有属性),那什么是公有属性呢?揭起了大家的好奇心。
定义:指的是所属这个类的所有对象,都可以访问的属性,叫做公有属性。
定义:

class Role(object):    gb = 'JP'  #定义公有属性    def __init__(self, name, role, weapon, life_value=100, money=15000):        self.name = name        self.role = role        self.weapon = weapon        self.life_value = life_value        self.money = money        self.__heart = 'normal'  #私有属性    def shot(self):        print("%s is shooting..."% self.name)    def get_heart(self):        return self.__heart    def got_shot(self):        print("ah...,I got shot...")    def buy_gun(self, gun_name):        print("just bought %s" % gun_name)def shot2(self):    print('run my own shot',self.name)r1 = Role('Alex', 'police', 'AK47') #生成一个角色r2 = Role('Jack', 'terrorist', 'B22')  #生成一个角色print(r1.gb)print(r2.gb)#输出JPJP

r1.name,r2.name也可以访问,也可以修改, 为什么不能叫公有属性呢?代码如下

class Role(object):    gb = 'JP'  #公有属性    def __init__(self, name, role, weapon, life_value=100, money=15000):        self.name = name        self.role = role        self.weapon = weapon        self.life_value = life_value        self.money = money        self.__heart = 'normal'  #私有属性    def shot(self):        print("%s is shooting..."% self.name)    def get_heart(self):        return self.__heart    def got_shot(self):        print("ah...,I got shot...")    def buy_gun(self, gun_name):        print("just bought %s" % gun_name)print(r1.name)print(r2.name)#输出AlexJack

很明显,上面的name是每个对象的属性,并不是共享,而是独立的 。


类访问公有属性
公有属性不仅可以通过所属类的所有对象访问,还可以通过类本身直接访问和修改

class Role(object):    gb = 'JP'  #公有属性    def __init__(self, name, role, weapon, life_value=100, money=15000):        self.name = name        self.role = role        self.weapon = weapon        self.life_value = life_value        self.money = money        self.__heart = 'normal'  #私有属性    def shot(self):        print("%s is shooting..."% self.name)    def get_heart(self):        return self.__heart    def got_shot(self):        print("ah...,I got shot...")    def buy_gun(self, gun_name):        print("just bought %s" % gun_name)print(r1.gb) #访问公有属性print(r2.gb)#访问公有属性r1.gb = 'CN'#修改公有属性print(r1.gb)#输出JPJPCN

这里写图片描述
结论:
1、对象r1去访问nationality属性时,如果在成员属性中找不到,就会找公共属性,也就是说自己的属性找不到就去找父亲的属性
2、r1.nationality=”CN” 相当于在自己对象内部又重新创建了一个新的局部变量,这个局部变量已经脱离了class本身,跟这个类已经没有半毛钱关系了,只是名字一样而已,如果不改,还是找全局的。


析构函数

定义

class Role(object):    gb = 'JP'  #公有属性    def __init__(self, name, role, weapon, life_value=100, money=15000):        self.name = name        self.role = role        self.weapon = weapon        self.life_value = life_value        self.money = money        self.__heart = 'normal'  #私有属性    def shot(self):        print("%s is shooting..."% self.name)    def get_heart(self):        return self.__heart    def got_shot(self):        print("ah...,I got shot...")    def buy_gun(self, gun_name):        print("just bought %s" % gun_name)    def __del__(self):#定义一个析构函数        print('del对象')r1 = Role('Alex', 'police', 'AK47')del r1#析构函数的使用方法#输出del对象

其实每一个对象都是一个应用,就像每一个房间都有门牌号一样, 只要这个对象的引用被清空时,就会自动执行,就像上面的del r1,其实python中有自动垃圾回收机制,会定时去的去回收一些被清空的应用,而析构函数就是在引用被清空之后会自动执行。


类的继承

之前我们说到了类的公有属性和类的私有属性,其实就是类的封装,下面我们来讲讲继承
面向对象编程 (OOP) 语言的一个主要功能就是“继承”。继承是指这样一种能力:它可以使用现有类的所有功能,并在无需重新编写原来的类的情况下对这些功能进行扩展。
通过继承创建的新类称为“子类”或“派生类”,被继承的类称为“基类”、“父类”或“超类”,继承的过程,就是从一般到特殊的过程。在某些 OOP 语言中,一个子类可以继承多个基类。但是一般情况下,一个子类只能有一个基类,要实现多重继承,可以通过多级继承来实现。
继承概念的实现方式主要有2类:实现继承、接口继承。
1、实现继承是指使用基类的属性和方法而无需额外编码的能力。
2、接口继承是指仅使用属性和方法的名称、但是子类必须提供实现的能力(子类重构爹类方法)。


继承的定义:
在类名的括号中写入需要继承的类名即可
方法的继承:
因为子类有自己的属性,但是又想继承父类的属性,所以需要先继承,再重构

#!/usr/bin/env python# -*- coding:utf-8 -*-class person(object):    def __init__(self,name,age):        self.name = name        self.age = age        self.sex = 'noraml'    def talk1(self):        print('person is talking...')class blackperson(person):#继承person这个父类    def __init__(self,name,age,strength):#先继承再重构                #person.__init__(self,name,age)#也可以写成:super(BlackPerson,self).__init__(name,age)        super(blackperson, self).__init__(name, age)        self.strength = strength #定义子类自己的属性        print(self.name,self.age,self.sex)    def talk2(self):        print('black person is balabala')b = blackperson('liyanan','24','rain')b.talk1()b.talk2()#输出liyanan 24 noramlperson is talking...black person is balabala

继承类的构造方法2种写法:
1、父类.__init(self,name,age)
2、super(子类,self).__init__(name,age)
注:建议使用新式类的写法,因为使用经典类的写法,在多继承的情况下,会出现重复调用参数的可能
经典类和新式类 两种方法的特点:
1、新式类继承object类,经典类不继承任何类
2、新式类用super关键字继承构造方法,经典类用 父类.__init(self)来继承
3、新式类:广度优先查询,经典类:深度优先查询(因为新式类讲究的是新,所以要找最近的,最新的;然后经典的讲究古老,所以更远更深的)
4、在python3中不管是经典类还是新式类,都是采用的是广度优先查询


子类对父类的重写
重写的条件:
1、重写方法的方法名必须和父类中被重写的方法名一模一样
2、重写方法的传入的参数名和参数的个数必须和父类中被重写的方法一样

class Person(object):    def talk(self,food):        print("person is talking...{0}".format(food))class BlackPerson(Person):    def talk(self,food):  #重写父类的方法(方法名和传入的参数名以及参数的个数与父类的方法一样)        print("BlackPerson is talking ...{0}".format(food))

小练习:

#!/usr/bin/env python# -*- coding:utf-8 -*-class SchoolMember(object):    '''学校成员基类'''    member = 0 #公共属性    def __init__(self,name,age,sex):        self.name = name        self.age = age        self.sex = sex        self.enroll()    def enroll(self):        '''注册'''        print("a new school member [%s]" % self.name)        SchoolMember.member +=1    def tell(self):        print('-----info:%s-----'%self.name)        for k,v in self.__dict__.items():#__dict__()函数是获取对象的属性,以字典的形式返回            print('\t',k,v)        print('-----end-----')    def __del__(self):        print('开除了[%s]'%self.name)        SchoolMember.member -=1class Teacher(SchoolMember):    '''讲师'''    def __init__(self,name,age,sex,salary,course):        SchoolMember.__init__(self,name,age,sex)        self.salary = salary        self.course = course    def teaching(self):        print('Teacher [%s] is teaching [%s]'%(self.name,self.course))class Student(SchoolMember):    '''学生'''    def __init__(self,name,age,sex,course,tuition):        SchoolMember.__init__(self,name,age,sex)        self.course = course        self.tuition = tuition        self.amount = 0    def pay_tuition(self,amount):        print('student [%s] has just paied [%s]'%(self.name,amount) )        self.amount +=amountt1 = Teacher('wusir',28,'F',3000,'python')s1 = Student('haitao',25,'F','pys15',300000)s2 = Student('liyanan',24,'F','pys15',0)print(SchoolMember.member)t1.tell()s2.tell()del s2print(SchoolMember.member)#输出a new school member [wusir]a new school member [haitao]a new school member [liyanan]3-----info:wusir-----     name wusir     age 28     sex F     salary 3000     course python-----end----------info:liyanan-----     name liyanan     age 24     sex F     course pys15     tuition 0     amount 0-----end-----开除了[liyanan]2开除了[wusir]开除了[haitao]    #del析构函数删除一个对象后还会重新运行

多继承
子类可以继承多个父类

class SchoolMember(object):  #SchoolMember类    '''学校成员基类'''    def tell(self):        print("the schoolmeber is tell...")class School(object):     #School类    """学校类"""    def open_branch(self,addr):        print("openning a new branch in",addr)class Teacher(SchoolMember,School):   #子类Teacher同时继承了SchoolMember,School两个类    "讲师类"    def teaching(self):        "讲课方法"        print("Teacher xiaogao is teaching python")t1 = Teacher()t1.tell()   #拥有父类SchoolMember的tell方法t1.open_branch("shanghai")  #拥有父类School的open_branch方法#输出the schoolmeber is tell...openning a new branch in shanghai

多态

多态的作用:
我们知道,封装可以隐藏实现细节,使得代码模块化;继承可以扩展已存在的代码模块(类);它们的目的都是为了——代码重用。而多态则是为了实现另一个目的——接口重用!多态的作用,就是为了类在继承和派生的时候,保证使用“家谱”中任一类的实例的某一属性时的正确调用。
很遗憾,在python不能直接的支持多态,所以我们只能间接的去执行


多态定义:多态其实就是用父类调用子类的方法,根据传入的子类的实例,得知具体调用哪个子类的方法

#!/usr/bin/env python# -*- coding:utf-8 -*-class Animal:    def __init__(self,name):        self.name = name    def talk(self):        raise NotImplementedError('subclass must implement abstract method')class Cat(Animal):    def talk(self):        return 'meow!'class Dog(Animal):    def talk(self):        return 'woof!woof!'d = Dog('d1')c = Cat('c1')# Animal.talk(d) #我们想要实现的调用方法def animal_talk(obj): #间接实现的方法    print(obj.talk())animal_talk(d)animal_talk(c)#输出woof!woof!meow!

补充和回顾

什么是面向对象?

在学面向对象之前我们都是用:函数
面向对象编程其实就是:类 + 对象

什么是类,什么是对象,它们之前又有什么关系?
class 类名:    def 函数1():        pass    def 函数2():        pass# obj是对象,是一个实例化的obj = 类名()obj.函数1()
面向对象的使用场景:

1、提取公共功能,我们把一些公共的功能,可以提取出来,并且在公共的功能中创建属于这个对象的属性,然后其他的方法就可以使用这个对象的属性了
2、根据一个模板去创建某些东西
3、多个函数传入共同参数

类的组成

字段:1.普通字段(保存在对象中),2静态字段(保存在类中)
方法:普通方法(保存在类中,用对象去调用)

class F1:    age = 18  #静态字段    def __init__(self,name):        self.name = name  #普通字段    def a1(self):   #普通方法        print('F1a1')