Python


一.面向对象

1.写代码的时候,什么时候用面向对象
  • 代码量大,功能多的时候
  • 处理比较复杂的角色之间的关系(面试可以这么说)
    • qq 好友 陌生人 群 组
    • 复杂的电商程序
    • 公司/学校的人事管理/功能的系统
  • 面向对象的好处
    • 代码的清晰度更高了
    • 可读性,无论是开发者,还是调用者,都能明确的分辨出每个角色拥有的方法和属性
    • 增强了代码的可扩展性
    • 增加复用性
    • 更加规范
2.对象
  • Python当中一切皆对象, 基础数据类型 都是对象
  • 类型和自定义类的关系–>类型和类是一个东西
    • type(obj) obj 是一个对象,那么它的type就是它的类型
  • 创建一个对象
    • 类名() 实例化一个对象
    • new() 创造了一个对象的空间,一些简单的初始化
  • 创建一个类
    • class 类名 —>语法级别的 Python解释器读到这句话的时候,就会创建类
    • type是所有类的元类, object是所有类的父类
    • 类也是被创建出来的,type创建类, type(cls) = type
      • class A(metaclass = ABCMeta) ABCMeta创建了这个A类,那么ABCMeta就是A的元类
      • 那么 type 就是这个类的 元类
  • type(obj) 的结果就是这个对象所属的类
  • type(类) 的结果及时创建这个类的元类, 大多数情况下就是type,除非你指定metaclass
class Saler:
    def __init__(self, name, sex, ident):
        self.name = name
        self.sex = sex
        self.ident = ident

    def sale(self):
        print('%s卖东西' % self.name)

    def add_goods(self):
        pass


alex = Saler('alex', None, 'looser')
print(type(alex))
print(type(Saler))  # Saler类 --> Saler类型 类型的类型 = 类型
3. 类 class 类名
  • 类是什么时候被加载的, 以及类名是什么时候生效的

    • 静态属性/静态字段/静态变量
    • 动态属性/方法
    class Person:
        role = 'china'
        print(role)
    
        def func(self):
            pass
    
    a = Person()
    print(Person.func)  # <function Person.func at 0x000001999CEBF1F8>
    print(a.func)  # <bound method Person.func of <__main__.Person object at 0x000001999CEE1C48>>
    内存地址是不一样的,如下

1604742664127

4.对象
  • 类创造对象的过程就是实例化的过程 : 构造new, 初始化 init
  • 可以通过指针找到类的空间中的内容
  • 对象本身内部存储了一些只属于对象的属性
5.组合
  • 什么有什么的关系 (比如: 学生和课程的关系)
  • 一个类的对象作为一个类的属性(组合的定义)
6.继承
class Foo:
    def __init__(self):
        self.func()

    def func(self): print('Foo.func')


class Son(Foo):
    def func(self): print('Son.func')


s = Son()
结果是 : Son.func
  • 什么是什么的关系 (dog 和 Animal 的关系) 节省代码

  • 子类 和 父类

  • 单继承 和 多继承

    • 单继承

      • 如果子类的对象调用某个方法
        • 子类有: 调用子类的
          • 子类有单想调用父类的:
            • super : 不用自己传self super(子类,self).方法名(除了self之外的参数)
            • 父类名: 父类名.方法名(self,…)
        • 子类没有,找父类
      • 注意 在任意类中调用的方法,都要仔细分辨以下这个self到底是谁的对象
    • 多继承

    • 新式类: 广度优先 - c3算法

      • mro方法查看继承顺序
      • py3 中默认继承object, 所以py3 中都是新式类
        • super().func() 遵循mro算法, 在类的内部不用传子类名和self
      • py2 中需要主动继承object
        • super(子类名,self).func() 必须传子类名和self
        • 经典类: 深度优先
      • py2 不继承object, 默认都是经典类
      • 没有mro算法
class A:
    def func(self):
        print('A')


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


class C(A):
    def func(self):
        super(C, self).func()  # 这里super(C, self) 是默认的,可以不传,在python3中
        print('C')


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


d = D()
d.func()
结果是A C B D 执行顺序遵循mro算法 mro执行顺序: dbca

b = B()
b.func()

1604742755894

7.抽象类和接口
  • 不能被实例化
  • 规范子类当中必须实现某个方法
  • 有原生的实现抽象类的方法,但是没有原生实现接口类的方法
  • 抽象类: 抽象类中的方法是可以实现的 只能单继承
  • 接口类: 可以多继承 但是这个类中的所有方法都不应该被实现
    • java中
      • java 只支持类的单继承 抽象类 父类的方法可以实现
      • 接口 interface 支持多继承的规范 . 接口中的所有方法 只能写pass
8.多态
  • 在python中处处存在
  • 定义: 一种类型的多种形态, 多个子类去继承父类, 那么每一个子类都是这个父类的一种形态
class Animal:pass
class Tiger(Animal):pass
class Frog(Animal):pass
  • 鸭子类型: 规范全凭自觉
9.封装
  • 私有的
    • 广义的封装: 把方法和属性都封装在一个类里,定义一个规范来描述一类事物
    • 狭义的封装: 私有化 只能在类的内部访问
    • __静态变量, 私有方法 , 私有的对象属性, 私有的类方法 , 私有的静态方法
    • 在内存中的存储形式: _类名__名字
    • 为什么在类的内部可以使用双下划线访问 : 在类的内部使用, 你就知道在哪个类中
    • 在子类中可以访问父类私有变量吗? 不行
    • 私有 : 不能在类的外部使用也不能被继承
10.property
  • 是装饰器函数, 内置函数, 帮助你将类中的方法伪装成属性 , 也叫特性
  • 调用方法的时候不需要主动加括号
  • 让程序的逻辑性更合理
  • @方法名.setter 装饰器, 修改被property装饰的属性的时候会调用被这个装饰器装饰的方法,除了self之外还有一个参数, 被修改的值
  • @ 方法名.deleter 装饰器,当要删除被property装饰的属性的时候会调用被这个装饰器装饰的方法
  • 只用property
class Circle:
    def __init__(self, r):
        self.r = r

    @property
    def area(self):
        return 3.14*self.r**2  # 这个方法计算结果本身就是一个属性,但是这个属性会随着这个类/对象的一个基础变量的变化而变化


c = Circle(5)
print(c.area)
c = Circle(1)
print(c.area)
  • 其他语言 property+私有的 合用 , 这时候更多的也会用到setter 和 deleter
class A:
    def __init__(self, name):
        self.__name = name

    @property
    def name(self):
        return self.__name

    @name.setter
    def name(self, new_name):
        if type(new_name) is str:
            self.__name = new_name

    @name.deleter
    def name(self):
        del self.__name


a = A(123)
print(a.name)

1604742788101

11.classmethod
  • 类方法的装饰器 内置函数
  • 使用类名调用, 默认传类名作为第一个参数
  • 不用对象命名空间中的内容, 而用到了类命名空间中的变量(静态属性) 或者类方法或静态方法
class Goods:

    __discount = 0.8
    def __init__(self, price):
        self.__price = price

    @property
    def price(self):
        return self.__price * Goods.__discount

    @classmethod
    def change_discout(cls, num):
        cls.__discount = num

## 商场的程序
apple = Goods(5)
banana = Goods(10)
print(apple.price, banana.price)
Goods.change_discout(1)  # 类名调用类方法 这里是改变__discount的值
print(apple.price, banana.price)
12.staticmethod
  • 静态方法的装饰器 内置函数
  • 如果一个类里面的方法, 既不需要用到self中的资源, 也不用cls 中的资源
  • 相当于一个普通函数
  • 但是你由于某种原因, 还是要把这个方法放在类中,这是时候,就将这个方法变成一个静态方法
  • 某种原因
    • 你完全想用面向对象编程, 所有的函数都必须写在类中
    • 某个功能确确实实是这个类的方法, 但是确确实实没有用到这个类有关系的资源
  • 比如 : 学生 管理员 课程 和 班级
class Person:
    @staticmethod
    def login():  # 动词 动作  属于某一个对象 用不到类的资源
        pass


class Student(Person):pass
class Manager(Person):pass
class Course:pass
class Classes:pass
13.object.new() 重点
14.反射(重点)
  • 从某个指定的命名空间中, 用字符串数据类型的变量名来获取变量的值
  • 类名反射 静态属性 类方法 静态方法
  • 对象反射 对象属性 方法
  • 模块 模块中的方法
  • 自己模块中
    • import sys
    • mymodule = sys.modules[‘main‘]
    • getattr(mymodule,’变量名’)
  • hasattr/getattr/setattr/delattr
  • 参数
    • (命名空间,’变量名’)
    • setattr(命名空间,’变量名’,新的值)
  • 变量名, 你只能拿到一个字符串的版本
    • 可以从文件里拿
    • 交互拿 : input/ 网络传输(二进制–> bytes类型–>str)
14.进阶
  • 内置方法/魔术方法/双下方法
  • _ _名字__ 不是被直接调用的
  • 间接调用: 内置函数/面向对象中的特殊语法/python提供的语法糖 (语法糖,就是给程序员提供了更实用的编码方式,有利于更好的编码风格,更易读)
x = 5
y = 6
print(x.add__(y))
print(x + y)  # 语法糖,和上面实现的功能是一样的
  • _ str__ : str(obj) . 要求必须实现 _ _ str__ ,要求这个方法的返回值必须是字符串str类型

    • 应用场景 : print %s str
  • _ _call__ : 相当于对象() 用类写装饰器

  • _ len__ : len(obj) , 要求必须实现了 _ len__ , 要求这个方法的返回值必须是数字int类型

  • _ _new__: 在实例化的过程中, 最先执行的方法,在执行init之前, 用来创造一个对象, 是一个构造方法

    • 经典的单利类
  • _ _init__ : 在实例化过程中,在new执行之后, 自动触发的一个初始化方法

  • _ _ add__: 加法

class MyType:
    def __init__(self, s):
        self.s = s

    def __add__(self, other):
        return self.s.count('*') + other.s.count('*')


obj1 = MyType('asdf*****')
obj2 = MyType('xfg****')
print(obj1 + obj2)
print(obj1.__add__(obj2))
  • _ repr__ : 是 _ str__的备胎, 如果有 _ _str _ 方法,那么 print, %s, str 都先会执行 _ str _ 方法,并且使用_ _str__的返回值
    • 如果没有_ _ str __ ,那么print %s str 都会执行repr
    • 应用场景 repr(obj) %r
  • 在子类中使用_ _ str _ ,先找子类的 _ _ str _ _. 没有的话向上找,只要父类不是object,就执行父类的 _ _ str _ _方法
  • 但是如果除了object之外的父类都没有 _ _ str _ _ 方法, 就执行子类的 _ _ repr _ _,如果子类也没有,还要向上找继续找父类中的 _ _ repr __ 方法
class A:
    def __init__(self, name):
        self.name = name

    def __str__(self):
        return '**%s**' % self.name

    def __repr__(self):
        return self.name


class B(A):
    def __init__(self, name):
        self.name = name

    def __repr__(self):
        return '***'

b = B('alex')
print(b)
print(str(b), repr(b))

Author: 二哈君
Reprint policy: All articles in this blog are used except for special statements CC BY 4.0 reprint polocy. If reproduced, please indicate source 二哈君 !
 Previous
python模块 python模块
一.模块初识 模块的分类 内置模块 安装python解释器的时候跟着装上的那些方法 第三方模块 没在安装怕python解释器的时候安装的那些功能 自定义功能 自己写的功能是一个通用的功能,可以当作是一个模块 模块的定义 有的
2020-11-11 二哈君
Next 
Python Python
一.面向对象的初始​ 1.类 : 具有相同属性和技能的一类事物 ​ 2.对象 : 具体类的表现, 具体的实实在在的一个实例 ​ class Person: ''' 类体:两部分: 变量部分
2020-10-13 二哈君
  TOC