面向对象自学笔记(Python版)

笔记初始

基于生疏的C++面向对象基础,为了巩固以及更好的学习了解Python,突发奇想,作此拙作。
课程来源:撩课学院
推荐该课程是因为每集时长短,符合当今快节奏的社会,在娱乐至死的大潮中,可以压缩碎片化时间,为自己的未来添砖加瓦,且附一个异常精致的思维导图——XMind(B站介绍有,在此出于版权,不便附上,但深表钦佩)

第一章——基础理论(1-5)

重点:面向过程和面向对象的区别(做饭的例子非常形象)

第二章——面向对象在python中的实践(6-82)

定义一个类(6)

class 类名:
        pass

怎样通过类,创建出一个对象?(7-8)

  1. 根据类创建对象-`one = Money()
  2. 类的定义
  3. 根据类,创建出一个对象
  4. 将对象的唯一标识返回

属性相关(9-23)

属性和变量的区别及判定依据?

思维导图很清楚,就不过多赘述

对象属性


  • 尤其初始化——init

  • del 该变量

  • 注意访问不到时的报错:
    AttributeError: ‘Person’ object has no attribute ‘sex’
    查看对象的所有属性?
    dict

类属性

  • 1、类也是对象
  • 2、增
    分成从类的内部和从外部增加
  • 3、查
    优先从对像自身上查找属性,找到则结束,如果没有找到,根据class找到对象对应的类,到这个类里面查找。
  • 4、改
    不能通过对象修改类属性
  • 5、删
    不能通过对象删除,del语句只能删除直系属性
  • 6、注意、
    类的属性的增、删、改只能通过类来访问,查询的时候可以通过对象和类来访问!
  • 7、补充

对象属性和类属性的区别和联系

  • 两者不同:
    1、存储位置不同(一个是类,一个是对象)
# 1. 定义一个类
class Person:
	age = 10
    pass

# 2. 根据类, 创建一个对象
p = Person()

2、抽象层级不同
类是抽象的
对象是具化的
3、宿主不同(以上面为例)
类——Person
对象——p
4、补充:
p.age += 1
Person.age 与 p.age 打印的结果分别是多少?
10
11

方法相关(24-33)

1、方法概念——def
2、分类:
实例方法:

class Person:
	def run(self):
	pass

一般使用对象来调用
类调用:必须传递一个对象,因为实例方法要求。
对象调用:不用手动传,解释器会默认把调用对象本身传递过去。
类方法:

class Person:
	@classmethod
	def countPerson(cls):

一般使用类来调用
类调用:不用手动传递第一个参数,会自动的把调用的类本身给传递过去。
对象调用:不用手动传递第一个参数,会自动的把调用的对象对应的类给传递过去。
静态方法()

class Person:
	@staticemethod
	def countPerson():

类调用:直接调用就可以, 不需要考虑第一个参数。
对象调用:直接调用就可以
直接调用就可以, 不需要考虑第一个参数
划分依据等等:方法的第一个参数必须要接收的数据类型。
不管是哪一种类型的方法,都是存储在类当中;没有在实例当中的
函数和方法的区别
函数都是独立的个体,函数之间几乎没有共享的数据,
方法有宿主。

补充(34-82)

类相关补充

1、元类(type型):结构图figure12、生成项目文件/类的描述及生成html(37-38)

属性相关补充

私有化属性

1、概念
2、意义
3、注意
4、x 公有属性

5、_y 受保护属性
6、__z 私有属性
私有属性的实现机制——名字重整(Name Mangling),重改__x为另外一个名称, 如_类名__x
应用场景:

class Person:

    # 主要作用, 当我们创建好一个实例对象之后, 会自动的调用这个方法, 来初始化这个对象
    def __init__(self):
        self.__age = 18

    def setAge(self, value):
        if isinstance(value, int) and 0 < value < 200:
            self.__age = value
        else:
            print("你输入的数据有问题, 请重新输入")

    def getAge(self):
        return self.__age
p1 = Person()
p2 = Person()
p1.setAge(20)
print(p1.getAge())
p2.setAge(240)
print(p2.getAge())

输出是
20
你输入的数据有问题, 请重新输入
18

只读属性(主要应用在实例属性)

有些属性, 只限在内部根据不同场景进行修改, 而对外界来说, 不能修改, 只能读取
1、方案一:
私有化的部分:通过"属性前置双下划线"实现
部分公开:优化-加装饰器@property
eg:

class Person(object):
    def __init__(self):
        self.__age = 18

    # 主要作用就是, 可以以使用属性的方式, 来使用这个方法
    #将一些"属性的操作方法"关联到某一个属性中
    @property
    def age(self):
        return self.__age
p1 = Person()
# p1._Person__age = 999
p1.__dict__["_Person__age"] = 999
print(p1.age)
print(p1.__dict__)

输出:
999
{’_Person__age’: 999}

经典类和新式类
经典类:没有继承object
新式类:继承object
且:在python2中,定义一个类,没有显式的继承自object,那么这个类就是一个继承类,显式的继承自object,他才是一个新式类。
在python3中,定义一个类,会隐式的继承object,所以默认情况下,就已经是一个新式类。
建议,无论在python2和3,都显式的继承object。

property的作用
将一些"属性的操作方法"关联到某一个属性中,即将一个属性的删改查关联到不同方法里面。
官方文档解释:

def __init__(self, fget=None, fset=None, fdel=None, doc=None): 
Property attribute.
        
          fget
            function to be used for getting an attribute value
          fset
            function to be used for setting an attribute value
          fdel
            function to be used for del'ing an attribute
          doc
            docstring

property作为函数在新式类的使用方法(用例出自视频)

class Person(object):
    def __init__(self):
        self.__age = 18


    def get_age(self):
        print("----, get")
        return self.__age

    def set_age(self, value):
        print("----, set")
        self.__age = value
    age = property(get_age, set_age)
p = Person()
print(p.age)

p.age = 90
print(p.age)

print(p.__dict__)

输出:
----, get
18
----, set
----, get
90
{’_Person__age’: 90}
property作为装饰器在新式类的使用方法(用例出自视频)
官方文档

class C(object):
        @property
        def x(self):
            "I am the 'x' property."
            return self._x
        @x.setter
        def x(self, value):
            self._x = value
        @x.deleter
        def x(self):
            del self._x
    """

视频用例:

class Person(object):
    def __init__(self):
        self.__age = 18

    @property
    def age(self):
        print("----- get")
        return self.__age

    @age.setter
    def age(self, value):
        print("----- set")
        self.__age = value

p = Person()
print(p.age)

p.age = 10
print(p.age)

property在经典类中的使用(切换版版本为python2)
在经典类中,property只会关联读取方法,不会关联设置和删除方法。
一般不用

2、方案二:
关键在只读两个要求:(1)可以读取。(2)不能写入
故,引入__setattr__(self, key, value):
有这一步操作

class Person:
    # 当我们通过 "实例.属性 = 值", 给一个实例增加一个属性, 或者说, 修改一下属性值的时候, 都会调用这个方法
    # 在这个方法内部, 才会真正的把, 这个属性, 以及对应的数据, 给存储到__dict__字典里面
    def __setattr__(self, key, value):
        print(key, value)

        # 1. 判定, key, 是否是我们要设置的只读属性的名称
        if key == "age" and key in self.__dict__.keys():
            print("这个属性是只读属性, 不能设置数据")
        # 2. 如果说不是, 只读属性的名称, 真正的给它添加到这个实例里面去
        else:
            # self.key = value
            self.__dict__[key] = value
p1 = Person()
p1.age = 18
print(p1.age)
print(p1.__dict__)

重点:由上例
if key == “age” and key in self.dict.keys():
解释:self.dict.keys()——字典型
使得一开始该字典中无age然后继续循环故第一次添加成功,后字典中有了age故只读取。

系统内置特殊属性

(1)类属性

__dict__:类属性
__bases__:类的所有父类构成元组
__doc__类的文档字符
__name__类名
__module__类定义所在模块

(2)实例属性

__dict__:类的实例
__class__:实例对应的类

方法相关补充

私有化方法

在函数名前加两个下划线,与属性私有化相同,名字重整机制是相同的。

def __方法():
	pass

注意:不要定义 “_类名__方法名” 这种方法

内置特殊方法(完成特定功能)
  1. 信息格式化操作
    (1)、__str__
    作用:一个对象的描述字符串, 更加方便用户阅读, 对用户更友好
 def __str__(self):
	return "描述

用例:

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

    def __str__(self):
        return "这个人的姓名是%s, 这个人的年龄是:%s" % (self.name, self.age)

p1 = Person("sz", 18)
print(p1)

p2 = Person("zhangsan", 19)
print(p2)
s = str(p1)
print(s, type(s))

(2)__repr__面向开发人员

def __repr__(self):
	return "描述

触发__str__的方法:

直接打印:print(p1)
str方法:s=str(p1) print(s)

触发__repr__的方法:

s=repr(p1) print(s)
在交互模式里面将对象名称写出,敲回车
  1. 调用操作(__call__
    使得“对象”具备当做函数,来调用的能力——即将函数变成类的方法
    实例:
class Person:
    def __call__(self, *args, **kwargs):
        print("xxx", args, kwargs)
        pass

p = Person()

p(123, 456, name="sz")

输出:
xxx (123, 456) {‘name’: ‘sz’}(元组加字典)
应用场景:
可以将"常变参数"和"不常变参数"进行分离

  1. 索引操作—— 可以对一个实例对象进行索引操作
    (使对象与字典相似)
    实例:
class Person:
    def __init__(self):
        self.cache = {}#初始化一个字典

    def __setitem__(self, key, value):
        # print("setitem", key, value)
        self.cache[key] = value#对字典中的key进行操作

    def __getitem__(self, item):
        # print("getitem", item)
        return self.cache[item]

    def __delitem__(self, key):
        # print("delitem", key)
        del self.cache[key]

p = Person()
p["name"] = "sz"#执行这行代码的时候,会调用第一个方法
print(p["name"])#调用第二个方法
del p["name"]#调用第三个方法
print(p.cache)

输出:
sz
{}
对上述实例的解释:注释掉的那一版操作会有一个后果——就是value传不进sz无法有索引key操作。因此需要一个字典属性,才可以对对象进行索引操作

  1. 切片操作

主要在python3中,‘切片操作’统一由‘索引操作’进行管理!

def __setitem__(self, key, value):
def __getitem__(self, item):
def __delitem__(self, key):
  1. 比较操作
    可以自定义对象 “比较大小, 相等以及真假” 规则。有六种方法:< , > , == , >= , <= , != .
    一、使对象可以像数一样被比较
class Person:
    def __init__(self, age, height):
        self.age = age
        self.height = height#先初始化
    def __eq__(self, other):
        return self.age == other.age   #指定相等的比较通过哪个属性比较,
    def __ne__(self, other):
        return self.age != other.age   #指定相等的比较通过哪个属性比较,
    def __gt__(self, other):#   >
    pass

	def __ge__(self, other):#   >=
    pass

	def __lt__(self, other):#   <
    # print("lt")
    print(self.age)
    print(other.age)
    return self.age < other.age

	def __le__(self, other):#   <=
    pass
p1 = Person(18, 180)
p2 = Person(19, 183)
print(p1 == p2)

#可以通过调换参数的方式定义比较方法,进而简化代码

注意
如果对于反向操作的比较符, 只定义了其中一个方法,但使用的是另外一种比较运算,那么, 解释器会采用调换参数的方式进行调用该方法。
二、也可以通过装饰器自动补全

import functools


@functools.total_ordering
class Person:
    def __lt__(self, other):
        print("lt")
        # pass
        return False

    def __eq__(self, other):
        print("eq")
        pass
  1. 遍历操作
    一、创建对象利用for-in循环遍历,可分为:
    实现__getitem__方法,优先级低
    实例:
class Person:
    def __init__(self):
        self.result = 1

    def __getitem__(self, item):
        self.result += 1
        if self.result >= 6:
            raise StopIteration("停止遍历")

        return self.result
    pass

p = Person()

for i in p:
    print(i)

实现__iter__方法,优先级高
实例:

class Person:
    def __init__(self):
        self.result = 1

    def __iter__(self):
        print("iter")
        self.result = 1
        # return iter([1, 2, 3, 4, 5])
        return self

    def __next__(self):
        self.result += 1
        if self.result >= 6:
            raise StopIteration("停止遍历")
        return self.result

p = Person()

 for i in p:
     print(i)

二、通过返回一个迭代器,__next__方法
如果一个对象拥有__iter__方法,其是可迭代对象;如果一个对象拥有__next__方法,其是迭代器。可迭代对象包含迭代器。
定义可迭代对象,必须实现__iter__方法;
定义迭代器,必须实现__iter____next__方法。
实例:

class Person:
    def __init__(self):
        self.age = 1


    def __getitem__(self, item):
        return 1
def __iter__(self):
    self.age = 1 #使该迭代器可以重复使用
    return self

def __next__(self):
    self.age += 1
    if self.age >= 6:
        raise StopIteration("stop")

    return self.age

next()
p = Person()

for i in p:
    print(i)

import collections   #导入集合模块
print(isinstance(p, collections.Iterator))
#True是迭代器,即输出bool值判断这个实例是否是迭代器
print(isinstance(p, collections.Iterable))#判断是不是可迭代对象
  1. 描述器
    一、概念:可以描述一个属性操作的对象——即类里面有一个属性,属性指向一个特殊的对象,只要这个对象可以实现三个特殊的实例方法(__set____get____delete__)这个对象就是一个描述器。
    二、作用:可以代为管理一个类属性的读写删操作, 在相关方法中, 对数据进行验证处理, 过滤处理等等。
    三、实现:
    方式一、用property:
    实例:
class Person:
    def __init__(self):
        self.__age = 10

    @property
    def age(self):
        return self.__age

    @age.setter
    def age(self, value):
        if value < 0:
            value = 0
        self.__age = value

    @age.deleter
    def age(self):
        print("del age")
        del self.__age
p = Person()#满足对象的三个特殊属性的实例
p.age = 19
del p.age

输出:del age
方式二、利用三个方法直接定义

class Age:
    def __get__(self, instance, owner):
        print("get")

    def __set__(self, instance, value):
        print("set")

    def __delete__(self, instance):
        print("delete")

class Person:
    age = Age()
p = Person()
p.age = 10
print(p.age)
del p.age

四、调用细节:
1、使用实例进行调用时:最多三个方法都会调用。
2、使用类进行调用时:最多只会调用get方法。
3、描述器只在新式类可以可以生效。
4、方法拦截:__getattribute__通过这个生效,使只能实现get方法。(此处不太明白,留待后续细看)
资料描述器 get set
非资料描述器 仅仅实现了 get 方法, 那么他就是一个非资料描述器
资料描述器 > 实例属性 > 非资料描述器

五、由描述器的数据存储问题:
先引入实例:

class Age(object):
    def __get__(self, instance, owner):
        print("get")
        return instance.v

    def __set__(self, instance, value):
        print("set", self, instance, value)
        instance.v = value

    def __delete__(self, instance):
        print("delete")
        del instance.v


class Person(object):
    age = Age()


p = Person()
p.age = 10
p2 = Person()
p2.age = 11

输出结果:
set <main.Age object at 0x000001CDBA867FD0> <main.Person object at 0x000001CDBA867FA0> 10
set <main.Age object at 0x000001CDBA867FD0> <main.Person object at 0x000001CDBA867DC0> 11
由此发现,类属性Age是多个实例对象公用的,因此在set方法里面是对 instance进行操作。

 instance.v = value
  1. 装饰器
    使用类当做装饰器来使用。即使用闭包函数进行。
    实例:
class check:
    def __init__(self, func):
        self.f = func

    def __call__(self, *args, **kwargs):
        print("登录验证")
        self.f()
@check
def fashuoshuo():
    print("发说说")
# fashuoshuo = check(fashuoshuo)

fashuoshuo()

第三章——Python对象的生命周期,以及周期方法(83-94)

监听对象的生命周期

生命周期的概念

第四章——面向对象编程-综合案例(96-109)

第五章——面向对象三大特性(110-151)

封装

概念

将一些属性和相关方法封装在一个对象中。
其中,对外隐藏内部具体实现细节,外界只需要根据"内部提供的接口"去使用就可以。

好处

  1. 使用起来更加方便。
    因为已经把很多相关的功能, 封装成一个整体。
    类似于像外界提供一个工具箱
    针对于不同的场景, 使用不同的工具箱就可以

  2. 保证数据的安全。
    针对于安全级别高的数据, 可以设置成"私有"。
    可以控制数据为只读,外界无法修改。
    也可以拦截数据的写操作,进行数据校验和过滤。

  3. 利于代码维护。
    如果后期, 功能代码需要维护, 则直接修改这个类内部代码即可;
    只要保证接口名称不变; 外界不需要做任何代码修改。

继承

概念

一个类"拥有"另外一个类的"资源"的方式之一,
其中"拥有”指——并不是资源的复制, 变成双份资源,而是资源的使用权。
“资源”——指"非私有的"属性和方法。
目的: 方便资源重用。

分类

单继承

仅仅继承了一个父类。

class Dog(Animal):
	pass
多继承

继承了多个父类

class child(Father, Mather):
	pass

type和object区分

objiect也是一个类,在官方文档中有诸多方法,因此在py3中定义一个类系统自动是新式类,也就是继承了objict的方法。object是父子关系的顶端,所有的数据类型的父类都是它。
type——元类,object也是由type继承而来——objecttype的一个实例。type是类型实例关系的顶端,所有对象都是它的实例的。

class Animal:
	pass
class XXX:
	pass
class Dog(Animal,XXX):
	pass

由此实例画出以下流程图:
Figure2

继承下的影响

资源的继承

除下私有的属性和私有的方法, 其他的基本都能继承。

资源的使用
  1. 继承的几种形态:
    (1)单继承链
    (2)无重叠的多继承链
    (3)有重叠的多继承链
    Figure3

  2. 资源继承的标准的顺序——遵循单调原则
    由上图可知
    对于单继承链:A-B-C

class C:
    # age = "c"
    pass

class B(C):
    # age = "b"
    pass

class A(B):
    # age = "a"
    pass

# A -> B -> C
print A.age

对于无重复的多继承链:A-B-D-C-E

class E:
    age = "e"

class D:
    # age = "d"
    pass

class C(E):
    # age = "c"
    pass

class B(D):
    # age = "b"
    pass

class A(B, C):
    # age = "a"
    pass

print A.age

A -> B -> D -> C -> E

对于有重复的多继承链:A-B-C-D

class D:
    # age = "d"
    pass

class C(D):
    age = "c"
    pass

class B(D):
    # age = "b"
    pass

class A(B, C):
    # age = "a"
    pass

print A.age
A -> B -> D -> C

  1. 资源使用的方案演化*(未明,后续再更)*
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
资源的覆盖
资源的累加

多态

多态的概念

一个类, 所延伸的多种形态,在继承的前提下; 使用不同的子类, 调用父类的同一个方法, 产生不同的功能,调用时的多种形态。

多态在python中的体现

实例:

import abc
class Animal(object, metaclass=abc.ABCMeta):
    @abc.abstractmethod
    def jiao(self):
        pass

    @abc.abstractclassmethod
    def test(cls):
        pass

class Dog(Animal):
    def jiao(self):
        print("汪汪汪")

    @classmethod
    def test(cls):
        print("xxxxx")
    pass

class Cat(Animal):
    def jiao(self):
        print("喵喵喵")


def test(obj):
    obj.jiao()

d = Dog()
d.jiao()
d.test()
  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值