Python 基础学习第十六天(三)

Python面向对象三大特性

一.封装

把很多数据封装到?个对象中. 把固定功能的代码封装到?个代码块, 函数, 对象, 打包成模块. 这都属于封装的思想. 具体的情况具体分析. 比如. 你写了?个很?B的函数. 那这个也可以被称为封装. 在?向对象思想中. 是把?些看似?关紧要的内容组合到?起统?进?存储和使?. 这就是封装.

封装,顾名思义就是将内容封装到某个地方,以后再去调用被封装在某处的内容。

所以,在使用面向对象的封装特性时,需要:

  • 将内容封装到某处
  • 从某处调用被封装的内容

第一步:将内容封装到某处

self 是一个形式参数,当执行 obj1 = Foo(‘wupeiqi‘, 18 ) 时,self 等于 obj1

当执行 obj2 = Foo(‘alex‘, 78 ) 时,self 等于 obj2

所以,内容其实被封装到了对象 obj1 和 obj2 中,每个对象中都有 name 和 age 属性,在内存里类似于下图来保存。

第二步:从某处调用被封装的内容

调用被封装的内容时,有两种情况:

  • 通过对象直接调用
  • 通过self间接调用

1、通过对象直接调用被封装的内容

上图展示了对象 obj1 和 obj2 在内存中保存的方式,根据保存格式可以如此调用被封装的内容:对象.属性名

class Foo:

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

obj1 = Foo('wupeiqi', 18)
print obj1.name    # 直接调用obj1对象的name属性
print obj1.age     # 直接调用obj1对象的age属性

obj2 = Foo('alex', 73)
print obj2.name    # 直接调用obj2对象的name属性
print obj2.age     # 直接调用obj2对象的age属性

2、通过self间接调用被封装的内容

执行类中的方法时,需要通过self间接调用被封装的内容

class Foo:

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

    def detail(self):
        print self.name
        print self.age

obj1 = Foo('wupeiqi', 18)
obj1.detail()  # Python默认会将obj1传给self参数,即:obj1.detail(obj1),所以,此时方法内部的 self = obj1,即:self.name 是 wupeiqi ;self.age 是 18

obj2 = Foo('alex', 73)
obj2.detail()  # Python默认会将obj2传给self参数,即:obj1.detail(obj2),所以,此时方法内部的 self = obj2,即:self.name 是 alex ; self.age 是 78

综上所述,对于面向对象的封装来说,其实就是使用构造方法将内容封装到 对象 中,然后通过对象直接或者self间接获取被封装的内容

二.继承

?类可以?动拥有?类中除了私有属性外的其他所有内容. 说?了, ??可以随便?爹的东?. 但是朋友们, ?定要认清楚?个事情. 必须先有爹, 后有??. 顺序不能乱, 在python中实现继承非常简单. 在声明类的时候, 在类名后?添加?个?括号,就可以完成继承关系. 那么什么情况可以使?继承呢? 单纯的从代码层?上来看. 两个类具有相同的功能或者特征的时候. 可以采?继承的形式. 提取?个?类, 这个?类中编写着两个类相同的部分. 然后两个类分别取继承这个类就可以了. 这样写的好处是我们可以避免写很多重复的功能和代码. 如果从语义中去分析的话. 会简单很多. 如果语境中出现了x是?种y. 这时, y是?种泛化的概念. x比y更加具体. 那这时x就是y的?类. 比如. 猫是?种动物. 猫继承动物. 动物能动. 猫也能动. 这时猫在创建的时候就有了动物的"动"这个属性. 再比如, ?骨精是?个妖怪. 妖怪天?就有?个比较不好的功能叫"吃?", ?骨精?出?就知道如何"吃?". 此时 ?骨精继承妖精.

三.多态

同?个对象, 多种形态. 这个在python中其实是很不容易说明?的. 因为我们?直在?. 只是没有具体的说. 比如. 我们创建?个变量a = 10 , 我们知道此时a是整数类型. 但是我们可以通过程序让a = "alex", 这时, a?变成了字符串类型. 这是我们都知道的. 但是, 我要告诉你的是. 这个就是多态性. 同?个变量a可以是多种形态。

多态,同一个对象,多种形态。python默认支持多态。

# 在java或者c#定义变量或者给函数传值必须定义数据类型,否则就报错。

def func(int a):
    print('a必须是数字')

# 而类似于python这种弱定义类语言,a可以是任意形态(str,int,object等等)。
def func(a):
    print('a是什么都可以')

# 再比如:
class F1:
    pass

class S1(F1):

    def show(self):
        print 'S1.show'

class S2(F1):

    def show(self):
        print 'S2.show'

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

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

    print obj.show()

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

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

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

鸭子类型

python中有一句谚语说的好,你看起来像鸭子,那么你就是鸭子。
对于代码上的解释其实很简答:
class A:
    def f1(self):
        print('in A f1')

    def f2(self):
        print('in A f2')

class B:
    def f1(self):
        print('in A f1')

    def f2(self):
        print('in A f2')

obj = A()
obj.f1()
obj.f2()

obj2 = B()
obj2.f1()
obj2.f2()
# A 和 B两个类完全没有耦合性,但是在某种意义上他们却统一了一个标准。
# 对相同的功能设定了相同的名字,这样方便开发,这两个方法就可以互成为鸭子类型。

# 这样的例子比比皆是:str  tuple list 都有 index方法,这就是统一了规范。
# str bytes 等等 这就是互称为鸭子类型。

四.类的约束

?先, 你要清楚. 约束是对类的约束.

用一个例子说话:

公司让小明给他们的网站完善一个支付功能,小明写了两个类,如下:

class QQpay:
    def pay(self,money):
        print('使用qq支付%s元' % money)

class Alipay:
    def pay(self,money):
        print('使用阿里支付%s元' % money)

a = Alipay()
a.pay(100)

b = QQpay()
b.pay(200)

但是上面这样写不太放方便,也不合理,老大说让他整改,统一一下付款的方式,小明开始加班整理:

class QQpay:
    def pay(self,money):
        print('使用qq支付%s元' % money)

class Alipay:
    def pay(self,money):
        print('使用阿里支付%s元' % money)

def pay(obj,money):  # 这个函数就是统一支付规则,这个叫做: 归一化设计。
    obj.pay(money)

a = Alipay()
b = QQpay()

pay(a,100)
pay(b,200)

写了半年的接口,小明终于接了大项目了,结果公司没品位,招了一个野生的程序员春哥接替小明的工作,老大给春哥安排了任务,让他写一个微信支付的功能:

class QQpay:
    def pay(self,money):
        print('使用qq支付%s元' % money)

class Alipay:
    def pay(self,money):
        print('使用阿里支付%s元' % money)

class Wechatpay:  # 野生程序员一般不会看别人怎么写,自己才是最好,结果......
    def fuqian(self,money):
        print('使用微信支付%s元' % money)

def pay(obj,money):
    obj.pay(money)

a = Alipay()
b = QQpay()

pay(a,100)
pay(b,200)

c = Wechatpay()
c.fuqian(300)

结果春哥,受惩罚了,限期整改,那么春哥,发奋图强,python的相关资料,重新梳理的代码:

class Payment:
  """ 此类什么都不做,就是制定一个标准,谁继承我,必须定义我里面的方法。
   """
    def pay(self,money):pass

class QQpay(Payment):
    def pay(self,money):
        print('使用qq支付%s元' % money)

class Alipay(Payment):
    def pay(self,money):
        print('使用阿里支付%s元' % money)

class Wechatpay(Payment):
    def fuqian(self,money):
        print('使用微信支付%s元' % money)

def pay(obj,money):
    obj.pay(money)

a = Alipay()
b = QQpay()

pay(a,100)
pay(b,200)

c = Wechatpay()
c.fuqian(300)

但是,这样还会有问题,如果再来野生程序员,他不看其他的支付方式,也不知道为什么继承的类中要定义一个没有意义的方法,所以他会是会我行我素:

class Payment:
  """ 此类什么都不做,就是制定一个标准,谁继承我,必须定义我里面的方法。
   """
    def pay(self,money):pass

class QQpay(Payment):
    def pay(self,money):
        print('使用qq支付%s元' % money)

class Alipay(Payment):
    def pay(self,money):
        print('使用阿里支付%s元' % money)

class Wechatpay(Payment):
    def fuqian(self,money):
        print('使用微信支付%s元' % money)

def pay(obj,money):
    obj.pay(money)

a = Alipay()
b = QQpay()

pay(a,100)
pay(b,200)

c = Wechatpay()
c.fuqian(300)

所以此时我们要用到对类的约束,对类的约束有两种:

1.提取?类. 然后在?类中定义好?法. 在这个?法中什么都不??. 就抛?个异常就可以了. 这样所有的?类都必须重写这个?法. 否则. 访问的时候就会报错.

2.使?元类来描述?类. 在元类中给出?个抽象?法. 这样?类就不得不给出抽象?法的具体实现. 也可以起到约束的效果.

先用第一种方式解决:

class Payment:
    """
    此类什么都不做,就是制定一个标准,谁继承我,必须定义我里面的方法。
    """
    def pay(self,money):
        raise Exception("你没有实现pay方法")

class QQpay(Payment):
    def pay(self,money):
        print('使用qq支付%s元' % money)

class Alipay(Payment):
    def pay(self,money):
        print('使用阿里支付%s元' % money)

class Wechatpay(Payment):
    def fuqian(self,money):
        print('使用微信支付%s元' % money)

def pay(obj,money):
    obj.pay(money)

a = Alipay()
b = QQpay()
c = Wechatpay()
pay(a,100)
pay(b,200)
pay(c,300)

第二种方式:引入抽象类的概念处理

from abc import ABCMeta,abstractmethod
class Payment(metaclass=ABCMeta):    # 抽象类 接口类  规范和约束  metaclass指定的是一个元类
    @abstractmethod
    def pay(self):pass  # 抽象方法

class Alipay(Payment):
    def pay(self,money):
        print('使用支付宝支付了%s元'%money)

class QQpay(Payment):
    def pay(self,money):
        print('使用qq支付了%s元'%money)

class Wechatpay(Payment):
    # def pay(self,money):
    #     print('使用微信支付了%s元'%money)
    def recharge(self):pass

def pay(a,money):
    a.pay(money)

a = Alipay()
a.pay(100)
pay(a,100)    # 归一化设计:不管是哪一个类的对象,都调用同一个函数去完成相似的功能
q = QQpay()
q.pay(100)
pay(q,100)
w = Wechatpay()
pay(w,100)   # 到用的时候才会报错

# 抽象类和接口类做的事情 :建立规范
# 制定一个类的metaclass是ABCMeta,
# 那么这个类就变成了一个抽象类(接口类)
# 这个类的主要功能就是建立一个规范

总结: 约束. 其实就是?类对?类进?约束. ?类必须要写xxx?法. 在python中约束的?式和?法有两种:

1. 使?抽象类和抽象?法, 由于该?案来源是java和c#. 所以使?频率还是很少的

2. 使??为抛出异常的?案. 并且尽量抛出的是NotImplementError. 这样比较专业, ?且错误比较明确.(推荐)

五.super

super是严格按照类的继承顺序执行!!!

class A:
    def f1(self):
        print('in A f1')

    def f2(self):
        print('in A f2')

class Foo(A):
    def f1(self):
        super().f2()
        print('in A Foo')

obj = Foo()
obj.f1()

super可以下一个类的其他方法

super()严格按照类的mro顺序执行

class A:
    def f1(self):
        print('in A')

class Foo(A):
    def f1(self):
        super().f1()
        print('in Foo')

class Bar(A):
    def f1(self):
        print('in Bar')

class Info(Foo,Bar):
    def f1(self):
        super().f1()
        print('in Info f1')

obj = Info()
obj.f1()

'''
in Bar
in Foo
in Info f1
'''
print(Info.mro())  # [<class '__main__.Info'>, <class '__main__.Foo'>, <class '__main__.Bar'>, <class '__main__.A'>, <class 'object'>]

原文地址:https://www.cnblogs.com/bky20061005/p/12141673.html

时间: 2024-10-05 04:45:06

Python 基础学习第十六天(三)的相关文章

Python 基础学习第十六天(一)

Python面向对象之类成员 一.细分类的组成成员 之前咱们讲过类大致分两块区域,如下图所示: 每个区域详细划分又可以分为: class A: company_name = '老男孩教育' # 静态变量(静态字段) __iphone = '1353333xxxx' # 私有静态变量(私有静态字段) def __init__(self,name,age): #特殊方法 self.name = name #对象属性(普通字段) self.__age = age # 私有对象属性(私有普通字段) de

Python 基础学习第十六天(二)

Python 面向对象继承 一 什么是面向对象的继承 比较官方的说法就是: 继承(英语:inheritance)是面向对象软件技术当中的一个概念.如果一个类别A"继承自"另一个类别B,就把这个A称为"B的子类别",而把B称为"A的父类别"也可以称"B是A的超类".继承可以使得子类别具有父类别的各种属性和方法,而不需要再次编写相同的代码.在令子类别继承父类别的同时,可以重新定义某些属性,并重写某些方法,即覆盖父类别的原有属性和方

Python基础学习(十)

Python I/O模型 同步IO和异步IO,阻塞IO和非阻塞IO分别是什么,到底有什么区别?不同的人在不同的上下文下给出的答案是不同的.所以先限定一下本文的上下文. 概念说明 在进行解释之前,首先要说明几个概念: 用户空间和内核空间 进程切换 进程的阻塞 文件描述符 缓存 I/O 用户空间与内核空间 现在操作系统都是采用虚拟存储器,那么对32位操作系统而言,它的寻址空间(虚拟存储空间)为4G(2的32次方).操作系统的核心是内核,独立于普通的应用程序,可以访问受保护的内存空间,也有访问底层硬件

python 基础学习第十四天(一)

一. 包 我们今天来讲解一下模块和包,模块我们已经知道是什么东西了,我们现在来看看这个包是个什么? 我说的包可不是女同胞一看见就走不动的包,而是程序中一种组织文件的形式. 只要文件夹下含有__init__.py文件就是一个包,包是干什么的呢? 回想一下,之前我们没有学习模块的时候将一个整体的功能写入到文件中,为了能够充分的将某个功能进行重用 我们使用了模块,但是慢慢的模块就会越来越多.我们想提高程序的结构性可维护性,就使用包将模块进行统一管理 包能够管理多个模块,我们想要使用包里的模块怎么办呢?

python基础学习(十二)

模块 前面有简单介绍如何使用import从外部模块获取函数并且为自己的程序所用: >>> import math >>> math.sin(0) #sin为正弦函数 0.0 模块是程序 任何python程序都可以作为模块导入.假设写如下程序,并且将它保存为以C:\python\hello.py #hello.py print "hello,world!" 下面通过python解释器调用: >>> import sys >>

【Python基础学习篇十】Python正则表达式(2015-01-01)

一.正则表达式简介 正则表达式用于文本匹配的工具,在源字符串中查找与给定的正则表达式相匹配的部分.一个正则表达式是由字母.数字和特殊字符组成的.正则表达式中有许多特殊的字符,这些特殊字符是构成正则表达式的要素. 1.正则表达式中的特殊字符: 2.正则表达式中的常用限定符: 利用{}可以控制字符重复的次数. 例如,\d{1,4}表示1位到3位的数字: 某些地区的电话号码是8位数,区号也有可能是3位或4位数字. \d{3}-\d{8}|\d{4}-\d{7} 3.限定符与"?"的组合 二.

python基础学习(十)字符串

字符串的定义 字符串 就是 一串字符,是编程语言中表示文本的数据类型 在 Python 中可以使用 一对双引号 " 或者 一对单引号 ' 定义一个字符串 虽然可以使用 \" 或者 \' 做字符串的转义,但是在实际开发中: 如果字符串内部需要使用 ":,可以使用 ' 定义字符串,例如:'zhangsan "hello" ' 如果字符串内部需要使用 ',可以使用 " 定义字符串 可以使用 索引 获取一个字符串中 指定位置的字符,索引计数从 0 开始

python 基础学习第十四天(二)

一.模块和包 我们今天来讲解一下模块和包,模块我们已经知道是什么东西了,我们现在来看看这个包是个什么? 我说的包可不是女同胞一看见就走不动的包,而是程序中一种组织文件的形式. 只要文件夹下含有__init__.py文件就是一个包,包是干什么的呢? 回想一下,之前我们没有学习模块的时候将一个整体的功能写入到文件中,为了能够充分的将某个功能进行重用 我们使用了模块,但是慢慢的模块就会越来越多.我们想提高程序的结构性可维护性,就使用包将模块进行统一管理 包能够管理多个模块,我们想要使用包里的模块怎么办

javascript基础学习(十五)

javascript之cookie 学习要点: cookie介绍 创建与获取cookie cookie的编码 cookie的生存期 cookie的路径 cookie的domain cookie的secure 一.cookie介绍 cookie实际上就是一些信息,这些信息以文件的形式存储在客户端计算机上.在javascript中,cookie主要用来保存状态,或用于识别身份. 二.创建与获取cookie 创建cookie的语法代码如下所示:document.cookie="name=value&q