python基础day19笔记

2018.7.26

day18回顾

对象------------------------->类

实例变量(属性)       类变量

实例方法                     类方法(@classmethod)

 

静态方法  @staticmethod

类内的预制属性:

  __doc__ 绑定文档字符串

  __base__ 属性 绑定父类

 

__slots__列表

  限定一个类创建的对象只能有固定的属性(对象没有字典__dict__)

继承/派生

  一个父类<----->多个子类

  一个子类,只有一个父类的继承关系称为单继承

覆盖 overrride

子类要想调用父类中的被覆盖的方法:

  super(类,对象)

  super()

子类对象重新实现了__init__(self,...)  方法

class B(A):
    def __init__(self,aaa):
        super().__init__(aaa)

 

day19

用于类的函数

  issubclass(cls,class_or_tuple)

  判断一个类是否继承自其它类,如果此cls 是class 或tuple中的一个派生子类,则返回True,否则返回False

示例:

class A:
    pass

class B(A):
    pass

class C(B):
    pass

issubclass(C, B)  # True
issubclass(B, C)  # False
issubclass(C, (int, str))  # False
issubclass(C, (int, B, str))  # True

 

封装 enclosure

  封装是指隐藏类的实现细节,让使用者不关心这些细节

  封装的目的是让使用者通过尽可能少的方法(或属性)操作对象

私有属性和方法

  python类中以双下划线('__')开头,不以双下划线结尾的标识符为私有成员,私有成员或只能用类内的方法进行访问和修改

  以__开头的实例变量有私有属性

  以__开头的方法为私有方法

示例:

class A:
    def __init__(self):
        self.__p1 = 100  # 私有属性

    def show_A(self):
        print('self.__p1: ', self.__p1)
        self.__m1()  # 调用自己的方法

    def __m1(self):  # 私有方法
        print("__m1(self)方法被调用")


a = A()
a.show_A()  # a.__p1: 100
# print(a.__p1)  # 出错,在类外部不能访问a的私有属性__p1
# a.__m1()  # 出错,不能调用私有方法


class B(A):
    pass


b = B()
# print(b.__p1)  # 出错, 子类对象不能访问父类中的私有成员
# b.__m1()  # 出错

多态 polymorphic

  什么是多态:

  字面意思:多种状态

  多态是指在有继承/派生关系的类中,调用基类对象的方法,实际能调用之类的覆盖方法的现象叫多态

状态:

  静态(编译时状态)

  动态(运行时状态)

说明:

  多态调用方法与对象相关,不与类相关

  python的全部对象都只有‘运行时状态(动态)’

  没有‘c++语言’ 里的 ‘编译时状态(静态)’

示例:

# 此示例示意python中的运行时状态
class Shape:
    def draw(self):
        print('Shape的draw方法被调用')


class Point(Shape):
    def draw(self):
        print("正在画一个点")


class Circle(Shape):
    def draw(self):
        print("正在画一个圆")


def my_draw(s):
    s.draw()  # 此处调用哪儿方法呢? 此处显示出'动态'


s1 = Circle()
s2 = Point()
my_draw(s2)
my_draw(s1)

面向对象的语言的特征:

  继承

  封装

  多态

多继承 multiple inheritance

  多继承是指一个子类继承自两个或两个以上的基类

语法: 

class 类名(基类名1,基类名2,...):

    ...

 

说明:

  1,一个子类同时继承自多个父类,父类中的方法可以同时被继承下来
  2,如果两个父类中有同名的方法,而在子类中又没有覆盖此方法时,调用结果难以确定

示例:

# 此示例示意用多继承来派生新类
class Car:
    def run(self, speed):
        print('汽车以', speed, 'km/h的速度行驶')


class Plane:
    def fly(self, height):
        print("飞机以海拔", height, '米的高度飞行')


class PlaneCar(Car, Plane):
    '''PlaneCar类同时继承自汽车和飞机'''


p1 = PlaneCar()
p1.fly(10000)
p1.run(300)

 

多继承的问题(缺陷)

  标识符(名字空间)冲突的问题

  要谨慎使用继承

示例:

# 此示例示意多继承名字冲突问题
# 小张写了一个类A
class A:
    def m(self):
        print('A.m()被调用')


# 小李写了一个类B
class B:
    def m(self):
        print('B.m()被调用')


# 小王感觉小张和小李写的两个类自己可以用
class AB(A, B):
    pass


ab = AB()
ab.m()  #  请问会发生什么?

多继承的MRO(Method Resolution Order) 问题

  类的__mro__ 属性

  此属性用来记录类的方法查找顺序

示例见:

# mro.py


class A:
    def go(self):
        print('A')
        # super().go()  # error

class B(A):
    def go(self):
        print('B')
        super().go()

class C(A):
    def go(self):
        print('C')
        super().go()

class D(B, C):
    def go(self):
        print('D')
        super().go()

d = D()
d.go()  # 

练习:

  写一个类Bicycle类,有run方法,调用时显示骑行里程km

class Bicycle:

    def run(self,km):

        print('自行车骑行了',km,'公里)

再写一个类EBicycle(电动自行车类),

在Bicycle类的基础上添加了电池电量 volume 属性, 有两个方法:
    1, fill_charge(self, vol)  用来充电, vol为电量
    2, run(self, km) 方法每骑行10km消耗电量1度,同时显示当前电量,当电量耗尽时调用 父类的run方法继续骑行

    b = EBicycle(5)  # 新买的电动有内有5度电
    b.run(10)  # 电动骑行了10km还剩 4 度电
    b.run(100)  #电动骑行了40km,还剩0度电,其余60用脚登骑行
    b.fill_charge(10)  # 又充了10度电
    b.run(50)  # 骑行了50公里剩5度电

解析:

class Bicycle:
    def run(self, km):
        print('自行车骑行了', km, '公里')


# 1. fill_charge(self, vol)  用来充电, vol为电量
# 2. run(self, km) 方法每骑行10km消耗电量1度,同时显示当前电量,当电量耗尽时调用 父类的run方法继续骑行
class EBicycle(Bicycle):
    def __init__(self, vol):
        self.volume = vol  # 电量

    def fill_charge(self, vol):
        self.volume += vol
        print("电动自行车充电%d度" % vol)

    def run(self, km):
        # 先算电走的里程,和要行驶的里程,哪儿个最小
        e_km = min(km, self.volume * 10)  # 电行驶里程
        self.volume -= e_km / 10  # 消耗电量
        if e_km > 0:
            print("电动自行车骑行了", e_km, '公里,剩余电量',
                  self.volume, '度')
        if km > e_km:  # 有路程没走完
            super().run(km - e_km)

b = EBicycle(5)  # 新买的电动有内有5度电
b.run(10)  # 电动骑行了10km还剩 4 度电
b.run(100)  #电动骑行了40km,还剩0度电,其余60用脚登骑行
b.fill_charge(10)  # 又充了10度电
b.run(50)  # 骑行了50公里剩5度电

 

函数重写:

  在自定义类内添加相应的方法,让自定义类创建的实例能像内建对象一样进行内建函数操作

对象转字符串函数:

  repr(obj) 返回一个能代表此对象的表达式字符串,通常eval(repr(obj))==obj(这个字符串通常是给python解释执行器运行用的)

  str(obj) 通过给定的对象返回一个字符串(这个字符串通常是给人阅读的)

 

对象转字符串函数的重写方法

repr(obj) 函数的重写方法:

  def __repr__(self):

str(obj) 函数的重写方法:

  def __str__(self):

说明:

  1,str(obj) 函数先查找,obj.__str__() 方法,调用此方法并返回结果

  2,如果没有obj.__str__()方法时,则返回obj.__repr__() 方法的结果并返回

  3,如果obj.__repr__方法不存在,则调用object类的__repr__ 实例方法显示 <__main__.XXXX object at 0xAABBCCDD>格式的字符串

示例:

# 此示例示意通过重写 repr 和 str方法改变转为字符串的规则
class MyNumber:
    def __init__(self, value):
        '构造函数,初始化MyNumber对象'
        self.data = value

    def __str__(self):
        '''转换为普通人识别的字符串'''
        # print("__str__方法被调用!")
        return "自定义数字类型对象: %d" % self.data

    def __repr__(self):
        '''转换为eval能够识别的字符串'''
        return 'MyNumber(%d)' % self.data


n1 = MyNumber(100)
n2 = MyNumber(200)
print('repr(n1) ====>', repr(n1))
print('str(n2)  ====>', str(n2))

示例2:

# 此示例示意通过重写 repr 和 str方法改变转为字符串的规则
class MyNumber:
    def __init__(self, value):
        '构造函数,初始化MyNumber对象'
        self.data = value

    # def __str__(self):
    #     '''转换为普通人识别的字符串'''
    #     # print("__str__方法被调用!")
    #     return "自定义数字类型对象: %d" % self.data

    def __repr__(self):
        '''转换为eval能够识别的字符串'''
        return 'MyNumber(%d)' % self.data


n1 = MyNumber(100)
n2 = MyNumber(200)
print('repr(n1) ====>', repr(n1))
print('str(n2)  ====>', str(n2))

 

 

其它内建函数的重写方法:
  __abs__       abs(obj)  函数
  __len__       len(obj)  函数(必须返回整数)
  __reversed__  reversed(obj) 函数(必须返回可迭代对象
  __round__     round(obj)  函数

示例见:

# 此示例示意abs 函数的重写
class MyInteger:
    def __init__(self, v):
        self.data = v

    def __repr__(self):
        return 'MyInteger(%d)' % self.data

    def __abs__(self):
        v = abs(self.data)
        return MyInteger(v)  # 用v创建另一个MyInteger对象

    def __len__(self):
        return 10000


I1 = MyInteger(-10)
print('I1 =', I1)

I2 = abs(I1)
print("I2 =", I2)

print('len(I2)=', len(I2))  # 10000

 

数值转换函数的重写

  __complex__       complex(obj) 函数

  __int__                 int(obj) 函数

  __float__              float(obj) 函数

  __bool__              bool(obj)函数

 

示例:

# 此示例示意数据转换构造函数的重写方法
class MyNumber:
    def __init__(self, value):
        self.data = value

    def __repr__(self):
        return 'MyNumber(%d)' % self.data

    def __int__(self):
        return self.data


n1 = MyNumber(100)
x = int(n1)  # 转为整数?
print(x)

print(bool(n1))  # True
n2 = MyNumber(0)
print(bool(n2))  # ????

布尔测试函数重写

格式:

  __bool__

作用:

  用于bool(obj)函数取值

  用于if语句的真值表达式

  用于while 语句的真值表达式

说明:

  1,当自定义的类有__bool__(self) 方法时,以此方法的返回值作为bool(obj) 的返回值

  2,当不存在__bool__(self) 方法时,bool(x) 返回__len__(self) 方法的返回值是否为零来测试布尔值

  3,当不存在__len__(self) 方法时,则直接返回True

示例:

# 此示例示意bool(x) 函数的重写
class MyList:
    '自定义类型的列表,用来保存数据,内部用一个列表来存储数据'
    def __init__(self, iterable=()):
        self.data = [x for x in iterable]

    def __repr__(self):
        return 'MyList(%s)' % self.data

    def __len__(self):
        '''返回长度'''
        print("__len__方法被调用")
        return len(self.data)

    def __bool__(self):
        print("__bool__方法调用")
        for x in self.data:
            if not x:
                return False
        return True
        # return False  # <<=== 所有对象都为False


myl = MyList([0, -1, 2, -3])
# myl = MyList()
print(myl)
print(bool(myl))
if myl:
    print("myl为真值")
else:
    print('myl为假值')

 

迭代器(高级)

什么是迭代器

  可以通过next(it)函数取值的对象就是迭代器

迭代器协议

  迭代器协议是指对象能够使用next函数获取下一项数据,在没有下一项数据时触发一个StopIteration异常来终止迭代的约定

迭代器协议实现方法:

  __next__(self) 方法来实现迭代器协议

语法形式:

class MyIterator:
    def __next__(self):
        迭代器协议
        return 数据

 

什么是可迭代对象:
  是指能用iter(obj) 函数返回迭代器的对象(实例)
  可迭代对象内部需要定义__iter__(self) 方法来返回迭代器对象

# 此示例示意让自定义的作为可迭代对象能让 for 语句迭代访问
class MyList:
    def __init__(self, iterable=()):
        self.data = [x for x in iterable]

    def __repr__(self):
        return 'MyList(%s)' % self.data

    def __iter__(self):
        '''此方法必须返回一个迭代器对象
        此方法创建一个迭代器对象并返回
        '''
        return MyListIterator(self.data)

class MyListIterator:
    '''此类用来创建迭代器,此类型的迭代器可以迭代访问
    MyList类型的对象'''
    def __init__(self, lst):
        self.data = lst
        self.cur_index = 0  # 初始化迭代器的起始位置

    def __next__(self):
        '''此方法用于实现迭代器协议'''
        if self.cur_index >= len(self.data):
            # 如果索引越界就发终止迭代通知
            raise StopIteration
        value = self.data[self.cur_index]  # 要返回的值
        self.cur_index += 1
        return value


myl = MyList([0, -1, 2, -3])
print(myl)

# it = iter(myl)
# print(next(it))

for x in myl:  # 迭代访问自定义类型的对象
    print(x)

 

练习

  1,修改原有的学生信息管理系统,将学生对象的,全部属性都变为私有属性,不让外部直接来实现封装

  2,写一个列表类MyList实现存储整数列表,写类的定义如下:

class MyList:

    def __init__(self,iterator):

        self .data=...

让此类的对象能用for语句进行迭代访问

L = MyList(range(5))
print(L)
L2 = [x ** 2 for x in L]
print(L2)  # [0, 1, 4, 9, 16]

  3,写一个类Fibonacci 实现迭代器协议,此类的对象可以作为可迭代对象生成相应的斐波那契数1 1 2 3 5

class Fibonacci:

    def __init__(self,n):

        ...

    ...

实现如下操作:

for x in Fibonacci(10):
          print(x)  # 1 1 3 5 8 ....
      L = [x for x in Fibonacii(50)]
      print(L)
      F = fibonicci(30)
      print(sum(F))  

class Fibonacci:
    def __init__(self, n):  # n代表数据的个数
        self.__count = n

    def __iter__(self):
        self.cur = 0  # 当前已生成的个数
        self.a = 0
        self.b = 1  # 当前的第一个斐波那契数
        return self

    def __next__(self):
        if self.cur >= self.__count:  # 不需要再生成
            raise StopIteration
        self.cur += 1  # 已生成的个数加1
        v = self.b  # 绑定当前的数,待返回
        # 计算下一个数,待下次返回
        self.a, self.b = self.b, self.a + self.b
        return v  # 把当前值返回


for x in Fibonacci(10):
    print(x)  # 1 1 3 5 8 ....
L = [x for x in Fibonacci(50)]
print(L)
F = Fibonacci(30)
print(sum(F))

 


上课期间出去1个多小时,整理不是很完整,如果错误请在文章下面留言哦

 

 

 

 

  

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值