当前位置: 首页 > news >正文

python归档:笔记转化


一、主题:

面向对象

 

二、目的:

归纳总结,将之前笔记转化为自己能够记住并理解的东西

 

三、大纲

1、概述

2、详述

四、内容:

概述

面向对象在很多语言中都会涉及,各种百科给出的答案也是十分详细,但站在当前学习的初级阶段,在此概述时,仅涉及面向对象三大基本特性的内容,即:封装、继承、多态。

封装就是把客观事物封装成抽象的类,并且类可以把自己的数据和方法只让可信的类或者对象操作,对不可信的进行信息隐藏。

继承是指这样的一种能力:它可以使用自己当前现有的所有功能,并且在无需编写原来的类的情况下对这些功能进行扩展。

多态是指一个类实例的相同方法在不同情形下有不同表现形式,多态机制使不同内部结构的对象可以共享相同的外部接口。这意味着,虽然针对不同对象的具体操作不同,但通过一个公共的类,他们可以通过相同的方式予以调用。

 

详述

 

一、封装

封装是做什么的前面已经提及,在这里主要说的是为什么要封装以及如何来封装。

1、 为什么要封装

在说明为什么要封装之前,首先要知道什么才需要进行封装,即封装的主体要确定。确定主体最简单的方式就是反推,现在拿一个类来进行分析:

# -*- coding:utf-8 -*-

class Person():
    def __init__(self,name,age,gender):
        self.name=name
        self.age=age
        self.gender=gender

    def talking(self):
        print("我叫%s,今年%s岁,我是%s生"%(self.name,self.age,self.gender))

只是从之前的知识上来看,上述代码中存在了数据name,age,gender和函数talking,再观察其他的类会发现,存在的也都为此两类,最多只是形式上不同,不会牵扯进其他新的内容。

那么我们就能够了解到,类中存在数据和函数两种情况。

对于数据的封装,考虑最多的还是安全性,是为了更好的保护隐私。

对于函数的封装,隔离复杂度。举个例子的话就是我们在使用各个系统时,不需要知道其内部是怎么运行的,只需要知道在需要某个功能时,将对应的选择框勾选上即可。

PS.对于函数的封装,多数提到的是方法的封装。其实,方法即为类中定义的函数。函数和方法的封装可参考此处说明http://blog.csdn.net/lastinglate/article/details/7295248 

2、怎么进行封装

  上述提到的代码其实就已经完成了一个最简单的封装。如果在不考虑面向对象的前提下,封装就是将数据和函数放入类下即可。比如:

class Fangzi():
    def __init__(self,weizhi,jiage,mianji):
        self.weizhi=weizhi
        self.__jiage=jiage
        self.mianji=mianji

    def shuoming(self):
        '''
        方法主要是对此套房子进行说明
        :return: 无返回值
        '''
        print("这套房子位于%s,单价是%s元"%(self.weizhi,self.__jiage))
    def maidiao(self):
        '''
        方法时用来计算当前房子的总价并返回其值
        :return: 房子的总价
        '''
        self.zongjia=int(self.__jiage)*int(self.mianji)
        return self.zongjia

    def swimming(self):
        '''
        此方法没有啥用
        :return:
        '''
        print('小明会游泳')

  简单介绍下代码内容:

    在此代码中,class为创建类的关键词,表示创建的此项内容为类。

    def __init__(self,weizhi,jiage,mianji)为构造函数,或者叫构造方法。代表的是传入的参数。
    self指的是实例本身,也可以理解为传入参数后形成的对象的内容,他的作用主要是起到连通类内部,使得类内多个方法都需要的值在self中可以随时调用到。
    self.weizhi=weizhi是将传入的weizhi赋值给了self.weizhi,保证了在类内部的通行。
    self.__weizhi代表了私有属性,表示外部无法访问到此属性。不过外部在某些时候可能也需要在允许的情况对私有属性进行访问,那么这时候可以使用如下形式:
P=Fangzi("1",10000,200)
shuxingming=P._Fangzi__jiage   #具体格式为 实例化对象._(一个横线)类名__(这两个横线一般为私有属性前面的那个横线)属性名
print(shuxingming)

 

 

  另一方面,加上面向函数概念的话,那么类就需要做到包含某一客观对象存在的共性。因此,在封装成类的时候,就需要考虑封装的数据和方法是否与成类的函数存在关联。比如上述函数,不应该将swimming方法封装到Fangzi这个类中,毕竟房子与游泳完全没有联系,而且后续使用过程中也不会牵扯到相关方面。这样抽象成的类不符合面向对象思想,甚至还会影响到正常的逻辑思维,严重的会干扰后续系统设计的思路,完全把自己带进沟里。

 

3、特殊的封装

  前面说明了如何进行封装,也介绍了进行封装的形式,基本上类可以用这类形式直接构造出来。但事物总是复杂的,用来描述事物的类自然也需要适应这种复杂。那么除了这种普通的封装形式,自然要延伸出特殊的封装形式。

  特殊的封装形式在python中主要包含了以下几种:

  1)、classmethod 类方法 

    方式:在类前使用关键词@classmethod,将方法更改为类方法。

    与普通类的不同点:类方法只能使用全局下的属性,而不能使用构造方法中的self.属性

    举例:

class Person():
    name="li"
    def __init__(self,name,age,gender):
        self.name=name
        self.age=age
        self.gender=gender
#若在前加@classmethod,则只能使用全局下的name,而不能使用构造函数中的self.name
    @classmethod
    def talk(self):
        print("%s is talking"%self.name)

 

  调用以上代码

d=Person("lu",26,"male")
d.talk()

  结果为:

  

   若要测试更改为类方法后,是否还可以调用构造方法中的值,可以取一个全局没有的值,比如age

    @classmethod
    def talk(self):
        print("%s is talking"%self.age)

       运行结果为:

  在以上测试中,类方法在括号内的值可以改为cls,不用默认的self。这样可以区分类方法与其余方法的不同,类方法在使用关键词classmethod后,自身变为类方法,而类方法默认的第一个参数变为类本身(此处可以理解为就是类这个代码自身),而不是self代表的实例本身。此处仍旧使用self是为了证实第二步调用self.name报错的直观性,不至于误会是因为没有调用self内的name而导致的出错。

    2)、property 属性方法

    方式: 在类前面使用关键词@property,将方法改为属性方法

    与普通方法的不同:在将方法变为一个属性方法后,调用时就不需要加括号了。 直接调用即可。

    调用时不使用括号这种形式正跟属性调用类似,而且配合setter装饰器,可以有效的控制重要函数值的传参。

    举例:  

class Person():
    name="li"
    def __init__(self,name,age,gender):
        self.name=name
        self.age=age
        self.gender=gender
    @property
    def talk(self):
        print("%s is talking"%self.name)

#调用如下: d= Person("liu",26,"male") d.talk

    现在结合setter装饰器一块说明:

class Person():
    @property
    def description(self):
        aihao="打麻将"
        return aihao


#调用如下:
d=Person()
print(d.description)

 

    此结果很明显,会直接输出打麻将

    

    但下面这些代码,尝试修改descrption的值:

class Person():
    @property
    def description(self):
        aihao="打麻将"
        return aihao


#调用如下:
d=Person()
d.description="游泳"
print(d.description)

    就会发现直接出现报错,提示不能设置属性

    

 

    若要设置description的属性,则需要

class Person():
    #设定登录名是从认证函数中调取出来的,不允许私自更改。
    @property
    def description(self):
        self.__username="wanglei"
        return self.__username
    @description.setter
    def decs(self,value):
        self.__username=value
        return self.__username
#调用如下:
d=Person()
d.description="zhangsan"
print(d.description)
    3)、staticmethod 静态方法

     方式: 在类前面使用关键词@staticmethod,将方法改为静态方法

    与普通方法的不同:这样写完以后,方法实际上跟类没什么关系了。相当于跟类的关系截断了。只是名义上归类管理,实际上在静态方法里访问不了实例中的属性,只能获取到类中的属性。

    举例:

class Person():
    #设定登录名是从认证函数中调取出来的,不允许私自更改。
    user="laowang"
    def test(self):
        self.username="laoli"
    @staticmethod
    def statictest(self):
        print(self.username,",Hello")
#调用如下:
d=Person()
d.statictest(d)

    此处在创建函数时仍旧调用了self,但经过测试,即使此处是self,也是无法调用self下的其他值。这样使用只会出现报错,提示无法找到属性username:

    如下调用即可正常显示:

class Person():
    #设定登录名是从认证函数中调取出来的,不允许私自更改。
    user="laowang"
    @staticmethod
    def statictest(self):
        print(self.user,",Hello")
#调用如下:
d=Person()
d.statictest(d)

    结果为

  4、特殊成员方法

  类中除了将方法使用特殊形式封装外,还提供了特殊的成员方法,其形式主要是以为  __方法名__  这种形式存在,现在主要是介绍下此类特殊成员方法

    1)__doc__

    作用: 打印这个类的描述信息

    示例:

class Person():
    __doc__ = "存储了人的行为"
    def __init__(self,name):
        self.name=name
    def damajiang(self):
        print("%s在打麻将"%self.name)
    def dushu(self):
        print("%s在读书"%self.name)


d=Person("zhangsan")
print(d.__doc__)

    2)、__moudile__

    作用:表示当前操作的对象在哪个模块中

    示例:使用之前写过的一个作业来进行说明。首先开始程序是在一个文件夹下,调用的核心程序是在另一个文件夹下的classset.py文件内,使用__module__就可以直接看到调用了哪个模块的内容。

    while True:#开启程序的界面
        msg=[]
        print(display)
        select=input("请选择:").strip()
        if select=="1" or select=="管理界面":
            msg.append("administrator")
            msg.append(None)
            adminmgr=AdminMgr(msg)
            print(adminmgr.__module__)
            adminmgr.maincore(msg)
#核心程序界面 
@denglu
    def maincore(self):
        print("欢迎进入选课系统管理界面".center(50,"-"))
        while True:
            msg='''
                        1.创建校区
                        2.创建讲师
                        3.创建课程
                        4.创建班级
                        5.查看在职讲师
                        6.查看在校学生
                        7.查看开课课程
                        8.退出
            '''
            print(msg)
            select=input("请选择:").strip()

    最终得到的结果为:

    

 

    3)、__class__

    作用:表示当前操作的对象的类是什么

    示例:

    正好可以拿上面的示例来做对比,看下__module__跟__class__得出的结果是否存在不同

    while True:
        msg=[]
        print(display)
        select=input("请选择:").strip()
        if select=="1" or select=="管理界面":
            msg.append("administrator")
            msg.append(None)
            adminmgr=AdminMgr(msg)
           #将此处代码改为__class__
            print(adminmgr.__class__)
            adminmgr.maincore(msg)        

    得到的结果为:

    

    可以看出__class__的结果已经精确到了AdminMgr这个类上了。

 

     4)、__init__

    作用:构造函数,也成为构造方法

    前面已经讲完,不再重复叙述。

 

    5)、__del__ 析构函数  或者是析构方法

    作用:当对象在内存中被释放时,自动触发执行。

    示例:

    可用文字描述下使用场景:比如软件是以server和client的模式存在,当前两者都正常运行,现在server端想要停机维护,如果直接停机的话,可能会引起当前仍旧在线的客户端传输出现问题,那么此时在server在退出时,可以设置析构函数,告诉server在退出时,发送断开信息给客户端,然后再将所有客户端连接断开,这样客户端在收到信息后,可执行自身无法连接至服务器的流程,消除了两者都可能引起崩溃的情况。

    

    6)、__call__ 

    作用:对象后面加扩展,直接执行

    示例: 

class Person():
    def __init__(self,name,age,gender):
        self.name=name
        self.age=age
        self.gender=gender
    def talk(self):
        print("%s is talking"%self.name)

    def __call__(self, *args, **kwargs):
        print("this is %s call"%self.name)

d=Person("liu",26,"male")
d()

    

    7)、__dict__

    作用:查看对象中所有的成员  

        PS.类.__dict__ 打印类里的所有属性,不包括实例属性

          实例.__dict__打印所有实例属性,不包括类里的属性

class Person():
    def __init__(self,name,age,gender):
        self.name=name
        self.age=age
        self.gender=gender
    def talk(self):
        print("talking")

d=Person("liu",26,"male")

print(d.__dict__)
print(Person.__dict__)

    结果为:

    

 

     8)、__str__

    作用:打印对象时,会直接将__str__内的返回值打印出来。

    示例:

class Person():
    def __init__(self,name,age,gender):
        self.name=name
        self.age=age
        self.gender=gender
    def talk(self):
        print("talking")
    def __str__(self):
        return "123"

d=Person("liu",26,"male")
print(d)

    9)、__getitem__

    作用:用于索引操作,表示获取数据

    示例:

class Value():
    def __init__(self):
        self.dict={
            1:"A",
            2:"B",
            3:"C",
            4:"D"
        }
    def __getitem__(self, item):
        if item in self.dict.keys():
            return self.dict[item]



s=Value()
print(s[1])

 

     10)、__setitem__

    作用:用于索引操作,表示设置数据

     示例:

# -*- coding:utf-8 -*-

class Value():
    def __init__(self):
        self.dict={
            1:"A",
            2:"B",
            3:"C",
            4:"D"
        }

    def valuestr(self):
        return self.dict
    def __setitem__(self, key, value):
        self.dict[key]=value
    def __getitem__(self, item):
        if item in self.dict.keys():
            return self.dict[item]



s=Value()
s[1]="qwe"
print(s[1])
print(s.valuestr())

    最后的结果为:

    

    11)、__delitem__

    作用:删除给定键对应的元素。

    示例:

    

class Value():
    def __init__(self):
        self.dict={
            1:"A",
            2:"B",
            3:"C",
            4:"D"
        }

    def valuestr(self):
        return self.dict
    def __setitem__(self, key, value):
        self.dict[key]=value
    def __getitem__(self, item):
        if item in self.dict.keys():
            return self.dict[item]
    def __delitem__(self, key):
        del self.dict[key]


s=Value()
s[1]="qwe"
del s[2]
print(s.valuestr())

    最终结果为:

    

 

    12)、__iter__

    作用:用于迭代器,之所以列表、字典、元组可以进行for循环,是因为类型内部定义了 __iter__

 

    13)、__new__

   作用:是在新式类中出现的方法,它作用在构造方法建造实例之前.

      __new__()可以决定是否 要使用当前类__init__()方法,因为__new__()同样也可以调用其他类的构造方法或者直接返回别的对象来作为本类 的实例。

   从继承的角度来说,如果类在定义时没有重写__new__()方法,Python默认调用该类的父类__new__()方法来构造该类实例,若父类中也未进行重写,那么就一直追溯至object的__new__()方法,因为object是所有新式类的基类。

         而如果新式类中重写了__new__()方法,那么可以在重写__new__()方法后,调用任意新式类的__new__()方法来进行实例的创造。
 
   14)、__metaclass__
  作用:__metaclass__称为“元类”,元类就是用来创建类的东西。
  可以这样简单理解:
  
MyClass = MetaClass()
MyObject = MyClass()

  在此还要提到type创建类的使用方法:

class Person():

    def __init__(self,name,age,gender):
        self.name=name
        self.age=age
        self.gender=gender
    def talk(self):
        print("talking")


d=Person("liu",26,"male")
print(type(d))
print(type(Person))

  在以上函数中,d通过Person成为实例化对象,在此,d跟Person其实都是一个实例。通过打印d 和Person的类型来看,二者都是通过类来创建的。

def __init__(self,name,age,gender):
    self.name=name
    self.age=age
    self.gender=gender

def talk(self):
    print(" %s is talking"%self.name)

def eat(self):
    print("%s is eat, he/she is %s"%(self.name,self.age))

Person=type("Person",(object,),{"talk":talk,"__init__":__init__})

d=Person("liu",25,"male")

d.talk()

    这两者创建的类最终结果都一样,因此也就了解到了,type实际上就是一个元类,type就是Python在背后用来创建所有类的元类。

    继续说明的话希望借助此处的一篇文章来进行进一步的说明。http://www.maiziedu.com/article/27320/

    

二、继承

  继承的模式如下示例:

class A():
    def __init__(self,value):
        self.value=value

    def output(self):
        print("A")


class B(A):
    def __init__(self,value,value1):
        super(B, self).__init__(value)
        self.value1=value1

    def output1(self):
        print("B")


s=B("1","2")
s.output()
s.output1()

   正如其说明,在B原有的功能上,添加了A中的功能,使得由B创建的对象可以调用A中的output方法。

   在这里,需要说明的是__init__中的super关键词。

   提到super关键词,就需要说明新式类和经典类。python2.X中,默认采用的是经典类,只有显式继承了object的才是新式类。python3.X中,默认采用的都是新式类,不必显式的继承object。

     显示继承如下:

class A(object):
    def __init__(self,value):
        self.value=value

    def output(self):
        print("A")

   而super关键词只是用在新式类中的写法,经典类中是使用另外一种来进行书写,写法如下:

 A.__init__(self,value)

  除了super关键词使用不同以外,还有一个不同点是在继承关系上。

  新式类在进行搜索时候,使用的是广度优先搜索,经典类使用的是深度优先搜索。

  那下面的例子来进行说明:

class A():
    def output(self):
        print("A")


class B(A):
    def output1(self):
        print("B")

class C(A):
    def output2(self):
        print("C")


class D(B,C):
    def output3(self):
        print("D")


s=D()

  使用类D创建一个对象,然后调用方法output

  那么新式类的搜索方式是在D里先找,找不到的话去B里面找,然后再去C,最后去A。

  经典类的顺序则是D---B--A--C。即:“从左至右,深度查找”

三、多态

   多态的实例如下:

  

class Person():
    def __init__(self,name,age,gender):
        self.name=name
        self.age=age
        self.gender=gender
    def talk(self):
        print("%s is talking"%self.name)

class Child(Person):
    def __init__(self,name,age,gender):
        super(Child, self).__init__(name,age,gender)
    def talk(self):
        print("%s is child"%self.name)

class Adult(Person):
    def __init__(self,name,age,gender):
        super(Adult, self).__init__(name,age,gender)
    def talk(self):
        print("%s is adult"%self.name)

#此处定义的函数,是独立于类之外的,即为了实现多态,重新定义了一个新的类,让其能够满足一个接口,多种形态。
def talk(obj):
    obj.talk()

d=Child("liu",10,"male")
e=Adult("lu",26,"male")

talk(d)

  结果为:

    

 

五、总结

  整篇笔记是以面向对象的三大特性为骨架进行填充整理的,基础部分在此多数都已涉及,但此篇归档在__metaclass__和__iter__两个类上尚且存在疑问,后续也会针对相关内容进行查缺补漏。

转载于:https://www.cnblogs.com/mstzkot/p/7488050.html

相关文章:

  • 理解JS中的call、apply、bind方法
  • Number Math
  • 初学JAVA的变量作用域
  • Inno Setup自定义安装界面脚本
  • Spring AOP简单的配置(注解和xml配置)
  • Swift,枚举
  • java操作Excel
  • 'NoneType' object is not iterable
  • AngularJS
  • C++ 清空队列(queue)的几种方法
  • MIME 类型(HttpContext.Response.ContentType)列表
  • 从微信官方获取微信公众号名片:https://open.weixin.qq.com/qr/code?username=haihongruanjian...
  • 分享 - 27 个机器学习、数学、Python 速查表
  • 浅析设计模式
  • 【BZOJ3331】[BeiJing2013]压力 Tarjan求点双
  • [rust! #004] [译] Rust 的内置 Traits, 使用场景, 方式, 和原因
  • 《深入 React 技术栈》
  • 「前端」从UglifyJSPlugin强制开启css压缩探究webpack插件运行机制
  • 【干货分享】SpringCloud微服务架构分布式组件如何共享session对象
  • 【前端学习】-粗谈选择器
  • docker-consul
  • Git的一些常用操作
  • HTTP中的ETag在移动客户端的应用
  • Intervention/image 图片处理扩展包的安装和使用
  • Java深入 - 深入理解Java集合
  • Laravel Telescope:优雅的应用调试工具
  • October CMS - 快速入门 9 Images And Galleries
  • PHP那些事儿
  • V4L2视频输入框架概述
  • 闭包,sync使用细节
  • 工作手记之html2canvas使用概述
  • 回流、重绘及其优化
  • 前端相关框架总和
  • 微信开源mars源码分析1—上层samples分析
  • 硬币翻转问题,区间操作
  • Salesforce和SAP Netweaver里数据库表的元数据设计
  • ​TypeScript都不会用,也敢说会前端?
  • #我与Java虚拟机的故事#连载10: 如何在阿里、腾讯、百度、及字节跳动等公司面试中脱颖而出...
  • (3)STL算法之搜索
  • (4.10~4.16)
  • (Demo分享)利用原生JavaScript-随机数-实现做一个烟花案例
  • (html5)在移动端input输入搜索项后 输入法下面为什么不想百度那样出现前往? 而我的出现的是换行...
  • (层次遍历)104. 二叉树的最大深度
  • (二)c52学习之旅-简单了解单片机
  • (四)图像的%2线性拉伸
  • (原創) 如何讓IE7按第二次Ctrl + Tab時,回到原來的索引標籤? (Web) (IE) (OS) (Windows)...
  • (中等) HDU 4370 0 or 1,建模+Dijkstra。
  • (转)Linux整合apache和tomcat构建Web服务器
  • *上位机的定义
  • . ./ bash dash source 这五种执行shell脚本方式 区别
  • .NET : 在VS2008中计算代码度量值
  • .net下简单快捷的数值高低位切换
  • @31省区市高考时间表来了,祝考试成功
  • @AliasFor注解
  • @GlobalLock注解作用与原理解析