第八章 Python-面向对象编程

2024-06-12 16:20

本文主要是介绍第八章 Python-面向对象编程,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

第八章 面向对象编程

8.1 面向对象概述

  • 面向对象是一种编程的思想,是一种解决问题的思路。

  • 在编程当中,有面向过程的编程思想和面向对象的编程思想。

    • 面向过程:

      • 面向过程主要专注在过程,主要关注在解决问题的步骤,将问题逐步分析去解决,但是代码重复内容较多
        • 函数可以帮助在功能上做一定的整合
      • 龟兔赛跑:
      # 龟兔赛跑
      import timeDISTENCE = 500
      name_t = "turtle"
      speed_t = 100
      t1 = DISTENCE / speed_tname_r = "rabbit"
      speed_r = 10000
      t2 = DISTENCE / speed_r
      
    • 面向对象:

      • 对象本质上是一种容器,编写程序时:变量和函数;即数据和方法。
        • 函数可以针对方法进行进行整合,对象可以对某一类数据和方法的一个封装。
        • 例如:
          • 做饭的数据:食材,调味品 做饭的方法:厨具
            • 可以将做饭的数据跟做饭的方法做一个封装,称为做饭的对象。
          • 洗衣服的数据:脏衣服 洗衣服的方法:洗衣机
            • 可以将洗衣服的数据跟做饭的方法做一个封装,称为洗衣服的对象。

8.2 面向对象基础

8.2.1 类和对象的定义

  • 定义:类是对象的模板,对象是类的实例,类是创建对象用的,对象是实际实现功能的。

    • 定义规范要求:类的名称首字母必须大写,同时采用驼峰体的命名方式。
    • 定义类:
    class MammalAnimal:name = "Turtle"speed = 100def run(self):print("i can run")def jump(self):print("i can jump")
    
  • 类的命名空间

    • 类体代码在创建的时候就会产生,
    class MammalAnimal:name = "Turtle"speed = 100def run(self):print("i can run")def jump(self):print("i can jump")print(MammalAnimal.__dict__)
    

    {‘module’: ‘main’, ‘name’: ‘Turtle’, ‘speed’: 100, ‘run’: <function MammalAnimal.run at 0x0000026AF8AE4D60>, ‘jump’: <function MammalAnimal.jump at 0x0000026AF8AE4C20>, ‘dict’: <attribute ‘dict’ of ‘MammalAnimal’ objects>, ‘weakref’: <attribute ‘weakref’ of ‘MammalAnimal’ objects>, ‘doc’: None}

  • 类的属性访问方式

    • 例如访问类的名称属性
    class MammalAnimal:name = "Turtle"speed = 100def run(self):print("i can run")def jump(self):print("i can jump")print(MammalAnimal.__dict__["name"])
    print(MammalAnimal.name)
    

    Turtle
    Turtle

    • 对象的定义
    class MammalAnimal:name = "Turtle"speed = 100def run(self):print("i can run")def jump(self):print("i can jump")cat = MammalAnimal()
    print(cat.dict)  # 打印对象,显示结果第一行
    cat.__dict__["name"] = "cat"
    cat.__dict__["speed"] = 10
    print(cat.__dict__)  # 打印对象的命名空间,显示结果第二行
    

    {}
    {‘name’: ‘cat’, ‘speed’: 10}

8.2.2 对象的产生过程以及self参数

  • 对象产生的过程

    • 创建一个空对象,类MammalAnimal见上一小节
    cat = MammalAnimal()
    
    • 在对象的命名空间中添加数据

      • 方式一:
      cat.__dict__["name"] = "cat"
      cat.__dict__["speed"] = 10
      
      • 方式二:__init__方法
      class MammalAnimal:def __init__(self):self.name = "Turtle"self.speed = 100def run(self):print("i can run")def jump(self):print("i can jump")obj = MammalAnimal()  # 此处已经将obj当成参数传入到MammalAnimal()中,如果再写一个字符串进去,会显示已经传递了两个位置参数
      print(obj.__dict__)
      

      {‘name’: ‘Turtle’, ‘speed’: 100}

      • 方式三:定制化对象的参数
      class MammalAnimal:def __init__(self, *args):  # 采用可变长位置参数传递对象的属性self.name = args[0]self.speed = args[1]def run(self):print("i can run")def jump(self):print("i can jump")obj = MammalAnimal("cat", 5)
      print(obj.__dict__)
      dog = MammalAnimal("dog", 9)
      print(dog.__dict__)
      

      {‘name’: ‘cat’, ‘speed’: 18}
      {‘name’: ‘dog’, ‘speed’: 9}

    • 将实例化好的对象返回出来

      • 最终对象的命名空间里只包含实例属性,而具体的函数方法,时保存在类的命名空间当中,那么对象调用这些方法的时候,先在自己的命名空间中查找,如果没有,则再到类的命名空间查找。
      class MammalAnimal:fly = ""  # 类属性def __init__(self, *args):self.name = args[0]  # 实例属性self.speed = args[1]def fly_cap(self):MammalAnimal.fly = "yes"  def run(self):  print("i can run")def jump(self):print("i can jump")cat = MammalAnimal("cat", 5)
      dog = MammalAnimal("dog", 9)
      print(cat.__dict__)
      cat.fly_cap()  # 通过对象调用方法
      print(cat.fly)
      print(cat.__dict__)
      MammalAnimal.run(cat)  # 通过类执行cat对象的run方法
      

      {‘name’: ‘cat’, ‘speed’: 5}
      yes
      {‘name’: ‘cat’, ‘speed’: 5}

      i can run

8.2.3 常见成员

  • 属性:变量类型
    • 实例属性:属性前面加了self.则为实例方法
    • 类属性:属性前面没有加self.是类方法
  • 方法:函数类型
    • 绑定方法:
      • 实例方法:函数上存在(self)参数则为实例方法,专门给对象使用
      • 类方法:
    • 非绑定方法:
      • 静态方法:

8.2.4 应用场景

  • 通过对象封装数据

    • 方法一:非对象调用数据
    switch_info = {"CE1": {"ip": "192.168.1.1", "username": "admin", "password": "Huawei@121"},"CE2": {"ip": "192.168.1.2", "username": "admin", "password": "Huawei@122"},"CE3": {"ip": "192.168.1.3", "username": "admin", "password": "Huawei@123"},"CE4": {"ip": "192.168.1.4", "username": "admin", "password": "Huawei@124"}, }
    print(switch_info["CE2"]["ip"])
    

    192.168.1.2

    • 方式二:通过对象调用数据
    class SwitchInfo:def __init__(self, ip, username, password):self.ip = ipself.username = usernameself.password = password
    CE1 = SwitchInfo("192.168.100.1","python","Huawei@123")
    CE2 = SwitchInfo("192.168.100.2","python","Huawei@123")
    CE3 = SwitchInfo("192.168.100.3","python","Huawei@123")
    CE4 = SwitchInfo("192.168.100.4","python","Huawei@123")
    print(CE2.ip)  # 通过对象调用
    

    192.168.100.2

  • 在实例化时可以完成必要操作:

import osclass Files:def __init__(self, path):self.path = pathif not os.path.exists(self.path):os.makedirs(self.path)def open_file(self):pass

8.2.5 数据类型回顾

L1 = list([1, 2, 3, 4, 5])  # list是类;l1是对象;[1,2,3,4,5]是初始化的参数
L1.append(3)  # 将自己作为第一参数加入方法append计算
print(L1)
list.append(L1, 5)  # 直接通过类调用两个参数L1列表,添加值5
print(L1)

[1, 2, 3, 4, 5, 3]
[1, 2, 3, 4, 5, 3, 5]

8.3 三大特性

8.3.1 封装

  • 封装是面向对象编程中最重要的特性
  • 封装体现在两个方面:
    • 封装数据:对象在实例化的过程当中,调用类中的__init__完成初始化,并将初始化好的数据存放在对象的内存空间中,方便之后进行调用。
    • 封装方法:将某一个类的方法封装在类中,做一个整合,方便以后进行调用。

8.3.2 继承

1. 基础
  • 定义:在python中子类可以继承父类当中的类属性和方法(父类当中的类属性和方法依然属于父类,子类只是继承了而已)
    • 父类和子类
    • 基类和派生类
  • 作用:为了方便在原有的类基础上进行扩展,不需要重复造轮子
  • 经典类和形式类:
    • 经典类就是默认没有继承object的类
    • 形式类就是默认继承了object的类
    • 目前来说,在Python 3.0中,我们使用的都是新式类,默认都继承了object
2. 一般继承
class Animal:def __init__(self,name,age):self.name = nameself.age = agedef run(self):print("我会跑")def jump(self):print("我会跳")def swimming(self):print("我会游泳")class Humanbeing(Animal):def swimming(self):  # 父类中存在该方法,此时重写该方法,叫做方法的重写print("我不会游泳")obj = Humanbeing("张三",18)
print(obj.name)
print(obj.age)
obj.run()
obj.swimming()
  • 方法在父类和子类中都存在,会优先调用子类当中的方法,如果说我们想要调用父类当中的方法,需要执行以下操作:

    • 方式一:
    class Humanbeing(Animal):def swimming(self):  Animal.swimming(self)  # 指明父类中的方法
    
    • 方式二:
    class Humanbeing(Animal):def swimming(self):  super(Humanbeing, self).swimming()使用super函数调用父类中的函数swimming()
    
3. 多层继承
  • 多层继承,父类Animal,子类Intelligence,子类的子类Humanbeing,代码如下:
class Animal:  def __init__(self, name, age):self.name = nameself.age = agedef run(self):print("我会跑")def jump(self):print("我会跳")def swimming(self):print("我会游泳")class Intelligence(Animal):  # def study(self):print("我能学习")def control(self):print("我能控制自己")class Humanbeing(Intelligence):def swimming(self):super(Humanbeing, self).swimming()obj = Humanbeing("张三", 18)
print(obj.name)
print(obj.age)
obj.run()
obj.swimming()
obj.study()

张三
18
我会跑
我会游泳
我能学习

4. 多重继承
class Animal:def __init__(self, name, age):self.name = nameself.age = agedef run(self):print("我会跑")def jump(self):print("我会跳")def swimming(self):print("我会游泳")def control(self):print("我不能控制自己")class Intelligence():def study(self):print("我能学习")def control(self):print("我能控制自己")class Humanbeing(Animal, Intelligence):  # 如果两个父类中都存在相同的方法,则采用最左侧的Animal的方法作为方法使用def swimming(self):super(Humanbeing, self).swimming()obj = Humanbeing("张三", 18)
print(obj.name)
print(obj.age)
obj.run()
obj.swimming()
obj.study()
obj.control()  # 该方法在两个父类中都存在,选择最左侧的类中方法执行

张三
18
我会跑
我会游泳
我能学习
我不能控制自己

  • 继承顺序问题
    • 当使用obj.成员时,首先在obj对象关联的类当中进行查找,没有则向父类中查找
    • 当多重继承时,先继承左边的,在继承右边的。
    • 如果说要打破继承规则,就要进行方法的重写,其中可以直接指定调用类中的方法,也可以使用super表示要调用哪个父类中的方法。
    • 注意:需要关注当前的self是属于哪个类的对象
5. 钻石继承
  • 场景:D继承B,C,B和C都继承A,此时构成一个钻石继承
class A:def f1(self):print("A")def f2(self):print("AA")def f3(self):print("AAA")class B(A):def f1(self):print("B")def f2(self):print("BB")class C(A):def f1(self):print("C")def f3(self): print("CC")class D(B, C):  # 先继承B再继承C方法def f1(self):print("D")obj = D()
obj.f1()
obj.f2()
obj.f3()

D
BB
CC

  • C3算法和MRO列表
    • 关于继承查找的顺序问题,通过C3算法计算得到的,在Python当中 提供了一个叫做mro的方法,通过类.mro可以得到一个mro列表,里面存放的时继承的关系。
class A:def f1(self):print("A")def f2(self):print("AA")def f3(self):print("AAA")class B(A):def f1(self):print("B")def f2(self):print("BB")class C(A):def f1(self):print("C")def f3(self): print("CC")class D(B, C):  # 先继承B再继承C方法def f1(self):print("D")print(D.mro())  # 查看该类的继承顺序

[<class ‘main.D’>, <class ‘main.B’>, <class ‘main.C’>, <class ‘main.A’>, <class ‘object’>]

6. Mixint机制

Mixint是一种规范,一个类继承了多个类,那么通过Minxint机制能够区分出哪个是主类,那个是附加性的。

class Animal:passclass EggMinIn:speak = "我有翅膀"def egg_func(self):print("我会下蛋")class Duck(EggMinIn, Animal):passclass Chicken(EggMinIn, Animal):def Egg(self):print("我会下蛋")speak = "我有翅膀"passclass Cat(Animal):pass

8.3.3 多态

多态其实指的就是一种食物的多种形态;水: 气体:水蒸气;液体:水;固体:冰

class Animal:def speak(self):print("我是动物,我会叫")class Humanbeing(Animal):def speak(self):super().speak()print("我是人,我的叫声是啊啊啊")class Dog(Animal):def speak(self):super().speak()print("我是狗,我的叫声是汪汪汪")class Duck(Animal):def speak(self):super().speak()print("我是鸭子,我的叫声是嘎嘎嘎")obj = Dog()
obj.speak()
  • 定义了一个叫做Animal的类,Humanbeing,Dog,duck类,人、狗、鸭子继承了动物类,那么此时动物类里面定义了一个speak方法,就意味着他的所有子类都拥有了speak这个方法。

  • 这么讲的含义是什么呢,就是说假设我们有一个类,他存在某些特征,那么之后我们在遇到一些类,只要他属于挪个类,那么他就不需要思考,就能直接使用这些特征。

  • 此时的Animal,起到的作用,就是即便下面的子类当中没有定义这个方法,但是由于他们属于Animal这个类,因此也可以直接调用Speak方法。

  • 但是在python当中,其实并不推崇这个约束方式,而是按照规范来创建类,假如定义一个类需要具备某些特征,那么我们就应该自主的吧这个特征加到定义的类里面。比如在这个例子当中,不是应为继承了Animal才有speak这个方法,而是以为属于Animal的子类,而Animal拥有speak的方法,所以也要在自己的类中定义speak方法。

  • 鸭子类型:

    • 如果已知鸟走起路来像鸭子,叫起来像鸭子,游泳像鸭子,那么他就是鸭子。
  • 拓展:

import abcclass Animal(metaclass=abc.ABCMeta):@abc.abstractmethoddef speak(self):print("I am an Animal")class HumanBeing(Animal):def speak(self):passclass Dog(Animal):def speak(self):passclass Duck(Animal):def speak(self):passobj = HumanBeing()
obj1 = Dog()

8.4 隐藏属性

8.4.1 定义

class Foo:def __init__(self, name, age):self.__name = name  # 变量名前加上__,则该变量为隐藏属性,无法被对象调用。self.age = ageobj = Foo('张三', 21)
print(obj._Foo__name)  # 隐藏后的属性如果一定要调用,采用该方式调用

通过对象.属性的方式来获取属性值,而如果定义类的时候属性名之前加上__,那么此时该属性成为隐藏属性,通过之前的方式调用则会失败,必须通过对象._类名__属性名的方式可以调用,但是不建议该隐藏后又再次被调用。

8.4.2 作用

  • 开发者决定用户能够访问哪些属性,用什么样的方式能访问属性。影藏属性在类的内部可以直接调用,通过变形后的属性名类.__属性名
class Foo:def __init__(self, name, age):self.__name = name  # 变量名前加上__,则该变量为隐藏属性,无法被对象调用。self.age = agedef get_name(self):# print("看什么看,不准查看")# returnprint(self.__name)def set_name(self, val):if val == str(val):self.__name = valprint(self.__name)else:print("更改的类型必须是字符串")def del_name(self):del self.__nameobj = Foo("张三", 18)
obj.set_name(123)

更改的类型必须是字符串

8.5 成员相关补充

  • 变量:
    • 实例变量:实例中定义
    • 类变量:类中定义
  • 方法:
    • 绑定方法:绑定给对象使用
      • 类方法:
      • 对象方法
    • 非绑定方法
      • 静态方法:

8.5.1 类方法

  • 类的最大方法使用来创建对象,因此类方法的使用场景比较局限性,存在一个场景需要通过类来调用而不需要通过对象,就可以使用类方法。
import config  # 引入另一个文件中的代码,代码如下:# Switch_info = {"CE1": {"IP": "192.168.1.1", "username": "admin", "password": "Huawei@123"},
#                "CE2": {"IP": "192.168.1.2", "username": "admin", "password": "Huawei@123"},
#                "CE3": {"IP": "192.168.1.3", "username": "admin", "password": "Huawei@123"},
#                "CE4": {"IP": "192.168.1.4", "username": "admin", "password": "Huawei@123"}, }class SwitchMonitor:def __init__(self, ip, username, password):self.ip = ipself.username = usernameself.password = passwordprint(self.ip, self.username, self.password)@classmethod  # 加了该命令后,不在将对象当成第一个参数传函数中,而是将类当成第一个参数传递进来def config_info(cls, arg):  # cls相当于类名,是一个类return cls(SwitchMonitor(config.Switch_info[arg]["IP"], config.Switch_info[arg]["username"],config.Switch_info[arg]["password"]))obj = SwitchMonitor.config_info("CE1")

192.168.1.1 admin Huawei@123

8.5.2 静态方法

class Foo:def __init__(self, x):self.x = xdef f1(self):print(self.x ** 2)def f2(self):print(self.x ** 3)obj = Foo(10)
obj.f1()
obj.f2()

8.5.2 property

  • 使用装饰器:
class Foo:def __init__(self, x):self.x = xdef f1(self):print(self.x ** 2)@property   # 装饰器实现的功能,即可以通过调用属性的方式调用方法。def f2(self):print(self.x ** 3)obj = Foo(10)
obj.f2  # 调用属性的方法,如果是调用方法则obj.f2()
  • 配合匿名属性使用
class Foo:def __init__(self, x):self.__x = xdef get_x(self):print(self.__x)def set_x(self,val):self.__x = valdef del_x(self):del self.__xobj = Foo(10)
obj.get_x()
obj.set_x(22)
obj.get_x()

装饰器配合property

class Foo:def __init__(self, x):self.__x = x@propertydef x(self):print(self.__x)@x.setterdef x(self, val):self.__x = valprint(self.__x)@x.deleterdef x(self):del self.__xobj = Foo(10)
obj.x = 20  # 像对对象属性一样的进行赋值,格式为x = val,则会自动匹配x.setter这个装饰器进行执行
del obj.x  # 删除参数只要前面加了del,则匹配x.deleter删除参数
obj.x  # 参数已经被删除,执行该语句报错

8.6 反射

8.6.1 反射的基本原理

  • 动态语言

    • 定义变量时候,不需要指明变量的类型,那么就可以称为动态语言,动态语言在程序执行时,才会知道数据的类型。
  • 反射的定义:

    • 反射是指在程序执行过程中,能够动态的获取对象的属性以及方法,执行之前不知道对象中具体有哪些内容。需要有一种灵活或者自由的方式能够判断属性是否存在,以及怎样获取对象的属性以及方法。
    • 在Python当中的体现就是能够通过字符串来获取属性和方法。
  • 作用:

    • 实例一:获取类的属性
      • name这个属性是否存在与这个对象,如果不存在会报错。
      • 需要一个更便捷的方式来获取对象中的属性和方法的信息。
      • 以及判断如果属性存在如何调用以及如果属性不存在怎么处理。
    class Foo:def __init__(self, name, age):self.name = nameself.age = agedef run(self):passobj = Foo("张三", 21)
    print(obj.__dict__)  # 查询对象的属性,返回字典
    print(dir(obj))  # 查询对象的属性和方法
    print(obj.name)  # 执行该属性,如果该属性不存在则会报错。
    
    • 反射的方法
      • 相比于通过对象.属性的形式,或者对象.方法的形式来进行调用,也可以通过反射功能,采用字符串的类型事项相应多功能
  • 反射的方法:

    • hasattr:判断一个属性是否在对象中存在
    lass Foo:def __init__(self, name, age):self.name = nameself.age = agedef run(self):passobj = Foo("张三", 21)
    res = hasattr(obj, "name")  # obj是对象,"name"属性对应的字符串,判断,返回结果是True或者False
    print(res)
    
    • gettattr:判断属性是否存在,如果存在返回一个值,不存在返回另一个值
    class Foo:def __init__(self, name, age):self.name = nameself.age = agedef run(self):passobj = Foo("张三", 21)
    res = getattr(obj, "name",None)  # obj是对象,"name"属性对应的字符串,存在则返回name值,不存在则返回None
    print(res)
    
    • setattr:为属性赋值
    class Foo:def __init__(self, name, age):self.name = nameself.age = agedef run(self):passobj = Foo("张三", 21)
    setattr(obj, "name", "李四")
    print(getattr(obj, "name"))
    

    李四

    • delattr删除属性
    class Foo:def __init__(self, name, age):self.name = nameself.age = agedef run(self):passobj = Foo("张三", 21)
    delattr(obj, "name")
    res = getattr(obj, "name", "None")
    print(res)
    
    • 应用实例
    class Foo:def __init__(self, name, age):self.name = nameself.age = agedef run(self):print("123")def choose_function(self):option = input("please input a function's name:")  # 输入run,结果返回到res,res()就是run()。if hasattr(self, option):res = getattr(obj, option)res()else:print("Invalid function")obj = Foo("张三", 21)
    obj.choose_function()
    

8.6.2 import_module+反射

  • import_module:可以以导入字符串的形式导入一个模块
from importlib import import_moduler = import_module('random')
res = r.randint(1, 10)
print(res)
  • 注意:通过import_mudule最多只能导入到模块的级别,不能单独导入模块下的类。
from importlib import import_moduler = import_module('telnetlib')
r1 = import_module('telnetlib.Telnet')  # 错误方式

8.7 内置方法

8.7.1 内置方法

  • 满足一定情况自动执行的方法,不需要手动调用,也叫做魔法方法

8.7.2 使用内置方法

1. __init__
  • 在对象执行实例化操作是后,自动触发执行__init__的方法
2. __dict__
  • 在生成命名空间的时候,会自动触发__dict__的方法。
3. __str__
  • 在执行print(对象)的时候会自动触发__str__,必须为该方法顶一个字符串的返回值,否则会报错。
class Animal:def __init__(self, name, age):self.name = nameself.age = agedef run(self):passdef jump(self):passdef __str__(self):return "这是一个动物的对象"  # 该函数调用一个字符串,否则会报错,在打印对象的时候会调用obj = Animal('Bob', 18)
print(obj)
4. __del__
  • 当执行删除对象的操作时,会自动的触发__del__执行

  • 默认在程序执行完成之后,会回收程序代码资源,等于说这个时候会将对象回收,也就意味着触发了方法__del__的执行。

class Animal:def __init__(self, name, age):self.name = nameself.age = agedef run(self):passdef jump(self):passdef __str__(self):return "这是一个动物的对象"  # 该函数调用一个字符串,否则会报错,在打印对象的时候会调用def __del__(self):print("程序终止了")obj = Animal('Bob', 18)  
  • 但是对于系统的资源是不会被回收,如果执行代码的过程中打开了一个文件,那么可以在__del__的方法下关闭一个文件,防止文件一直占用系统资源。
class Animal:def __init__(self, name, age):self.name = nameself.age = ageself.f = open("config.py", "r")  # 打开文件print("文件打开完毕")def run(self):passdef jump(self):passdef __str__(self):return def __del__(self):self.f.close()print("文件关闭了")  # 关闭文件obj = Animal('Bob', 18)
5. __new__
  • 创建对象的时候会用到的魔法方法

  • 创建对象的过程:

    • 创建一个空对象,通过__new__方法创建出来的。
    • 通过__init__方法初始化对象,需要注意,一定要有一个空对象才会触发__init__
    • 返回一个初始化好的对象
    obj = Animal('Bob', 18)  # 值传递给__init__方法
    
  • 创造空对象是自动触发__new__方法,并且返回好一个创建好的空对象

    • 对象
    class Animal:def __init__(self, name, age):self.name = nameself.age = ageprint("haha")def run(self):passdef jump(self):passdef __str__(self):return "这是一个动物的对象"  # 该函数调用一个字符串,否则会报错,在打印对象的时候会调用def __new__(cls, *args, **kwargs):return super().__new__(cls)obj = Animal('Bob', 18)  # 实例化对象
    print(obj)  # 显示结果为空
    print(dir(Animal))
6. __call__
  • 在执行对象()的操作时,会自动触发__call__方法的执行,并且可以将__call__return的结果当成返回值。
  • Animal()触发的应该是Animal父类中的call方法,可以推断Animal()触发的应该是Animal父类中的__call__方法,也就说明了,我们在做对象实例的时候,默认触发的就是Animal父类中的__call__方法。
  • 创建对象的过程:
    • 触发Animal父类当中的call方法的执行。
    • 创建一个空对象。
    • 通过__init__方法初始化对象。
    • 返回一个初始化好的对象。
class Animal:def __init__(self, name, age):self.name = nameself.age = ageprint("haha")def run(self):passdef jump(self):passdef __str__(self):return "这是一个动物的对象"  # 该函数调用一个字符串,否则会报错,在打印对象的时候会调用def __new__(cls, *args, **kwargs):return super().__new__(cls)def __call__(self, *args, **kwargs):return 123obj = Animal('Bob', 18)
res = obj()
print(res)
7. __getitem____setitem____delitem__
class Animal:def __init__(self, name, age):self.name = nameself.age = ageprint("看到我这句,表示打印了__init__中的属性")def run(self):passdef jump(self):passdef __str__(self):return "这是一个动物的对象"  # 该函数调用一个字符串,否则会报错,在打印对象的时候会调用def __new__(cls, *args, **kwargs):return super().__new__(cls)def __call__(self, *args, **kwargs):return 123def __getitem__(self, item):print(item)passdef __setitem__(self, key, value):print(key)print(value)def __delitem__(self, key):print(key)passobj = Animal('Bob', 18)  # Animal()触发的应该是Animal类中的call方法。
obj["gender"] = "male"  # 该语句自动执行setitem的方法
obj["name"]  # 自动触发geitem方法的执行
del obj["age"]  # 自动触发delitem执行
8. __add__
class Animal:def __init__(self, name, age):self.name = nameself.age = agedef run(self):passdef jump(self):passdef __str__(self):return "这是一个动物的对象"  # 该函数返回一个字符串,否则会报错,在打印对象的时候会调用def __new__(cls, *args, **kwargs):return super().__new__(cls)def __call__(self, *args, **kwargs):return 123def __add__(self, other):print(other)obj1 = Animal('Bob', 18)  # Animal()触发的应该是Animal类中的call方法。
obj2 = Animal('Alice', 19)
obj3 = obj1 + 3  # 触发__add__方法
print(obj3)
9. __enter____exit__
  • 打开文件时采用的方法(回顾):

    • 方法一:open
    f = open("config.py", "r")  # 打开后,需要手工关闭。
    print(f.read())
    f.close()
    
    • 方法二:With xxx as 语句
    with open("config.py", "r") as f:  # 打开后当退出with语句块的时候,关闭文件。print(f.read())
    
  • __enter____exit__方法

    • 首先使用with对象 as语句会自动线触发__enter__方法,然后获得一个返回值,赋值给f,接着执行with 对象as下对应的代码块,执行完毕之后触发__exit__方法。
    • 使用该方法文件的过程类似
class Foo:def __init__(self, name):self.name = namedef __enter__(self):return 5passdef __exit__(self, exc_type, exc_val, exc_tb):print("-------")obj = Foo("张三")
with obj as f:print(f)print(123)
10. __inter____next__
  • 生成器定义:
    • 对象中存在__iter____next__方法
    • __iter__方法返回自身(对象)
    • 通过__next__提取,如果没有数据可以提取,那么抛出一个StopIteration的错误
  • 示例一:创建一个生成器函数
class Foo:def __init__(self):self.counter = 0def __iter__(self):return selfdef __next__(self):self.counter += 1if self.counter == 5:raise StopIterationelse:return self.counterobj = Foo()
print(next(obj))
print(next(obj))
print(next(obj))
print(next(obj))
  • 示例二:自定义一个range方法:
class Foo:def __init__(self, num):self.counter = -1self.num = numdef __iter__(self):return selfdef __next__(self):self.counter += 1if self.counter == self.num:raise StopIterationelse:return self.counterobj = Foo(5)
print(next(obj))
print(next(obj))
print(next(obj))
print(next(obj))
  • 生成器对象
    • 是由generator类实例化而来的,本质上生成器需要满足的条件跟迭代器一样。
  • 可迭代对象,需要满足两个条件。
    • 内部拥有__iter__方法
    • 通过__iter__方法返回一个迭代器对象
  • 示例:只要是可迭代的对象都能使用for循环进行遍历,而只有迭代器对象和生成器对象才能使用next方法来提取数据。
class Foo:def __init__(self, num):self.counter = -1self.num = numdef __iter__(self):return selfdef __next__(self):self.counter += 1if self.counter == self.num:raise StopIterationelse:return self.counterclass Xoo:def __iter__(self):return Foo(100)obj = Xoo()
for i in obj:print(i)

8.8元 类

8.8.1 元类定义

  • 元类就是类所属的类,python中一切皆对象,那么Animal这个类本质上也是对象,Animal这个对象是由哪个类实例化得到的呢。
class Animal:def __init__(self, name, age):self.name = nameself.age = agedef run(self):print("我会跑")def jump(self):print("我会跳")obj = Animal("cat", 8)
print(type(obj))  # 显示结果obj类的父类是Animal
print(type(Animal))  # 显示结果Animal的父类是type,时一个元类。

<class ‘main.Animal’>
<class ‘type’>

8.8.2 自定义类

cls_name = "Animal"
cls_base = (object,)
cls_content = """
class Animal:def __init__(self, name, age):self.name = nameself.age = agedef run(self):print("我会跑")def jump(self):print("我会跳")
"""
cls_namespace = {}
exec(cls_content, {}, cls_namespace)
Animal = type(cls_name, cls_base, cls_namespace)  # 通过元类创造对象Animal,第一个参数是字符串,第二个参数是元组类型,第三个参数是字典类型
obj = Animal("张三", 18)
print(obj.__dict__)

8.8.3 自定义元类来对类的定义进行约束

class MyMeta(type):def __init__(self, a1, a2, a3):  # a1代表类名,a2代表继承的父类,a3代表命名空间。if a1.isupper():self.a1 = a1else:print("类名必须全大写")class Animal(object, metaclass=MyMeta):  # 将该类的父类设置为MyMeta类def __init__(self, name, age):self.name = nameself.age = agedef run(self):print("我会跑")def jump(self):print("我会跳")obj = Animal("cat", 8)
print(obj)

8.8.4 在看__new____call__

class MyMeta(type):def __call__(self, *args, **kwargs):print(args, kwargs)obj = self.__new__(self)  # 创建空对象,对于MyMeta而言,self是Animal,调用Animal中的__new__方法,如果Animal中不存在__new__方法,则查找父类中的__new__方法。self.__init__(obj, *args, **kwargs)  # 初始化参数return obj  # 返回初始化好的对象class Animal(object, metaclass=MyMeta):  # 将该类的父类设置为MyMeta类def __init__(self, name, age):self.name = nameself.age = agedef run(self):print("我会跑")def jump(self):print("我会跳")def __new__(cls, *args, **kwargs):  # 因此Animal中该方法也可以删除,删除后,将调用父类中的__new__函数,父类中没有,将调用到元类。return super().__new__(cls)obj = Animal("cat", 8)  # 相当于执行父类中的__call__类型,进而调用
print(obj)

这篇关于第八章 Python-面向对象编程的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1054723

相关文章

Python 字符串占位

在Python中,可以使用字符串的格式化方法来实现字符串的占位。常见的方法有百分号操作符 % 以及 str.format() 方法 百分号操作符 % name = "张三"age = 20message = "我叫%s,今年%d岁。" % (name, age)print(message) # 我叫张三,今年20岁。 str.format() 方法 name = "张三"age

一道经典Python程序样例带你飞速掌握Python的字典和列表

Python中的列表(list)和字典(dict)是两种常用的数据结构,它们在数据组织和存储方面有很大的不同。 列表(List) 列表是Python中的一种有序集合,可以随时添加和删除其中的元素。列表中的元素可以是任何数据类型,包括数字、字符串、其他列表等。列表使用方括号[]表示,元素之间用逗号,分隔。 定义和使用 # 定义一个列表 fruits = ['apple', 'banana

Python应用开发——30天学习Streamlit Python包进行APP的构建(9)

st.area_chart 显示区域图。 这是围绕 st.altair_chart 的语法糖。主要区别在于该命令使用数据自身的列和指数来计算图表的 Altair 规格。因此,在许多 "只需绘制此图 "的情况下,该命令更易于使用,但可定制性较差。 如果 st.area_chart 无法正确猜测数据规格,请尝试使用 st.altair_chart 指定所需的图表。 Function signa

python实现最简单循环神经网络(RNNs)

Recurrent Neural Networks(RNNs) 的模型: 上图中红色部分是输入向量。文本、单词、数据都是输入,在网络里都以向量的形式进行表示。 绿色部分是隐藏向量。是加工处理过程。 蓝色部分是输出向量。 python代码表示如下: rnn = RNN()y = rnn.step(x) # x为输入向量,y为输出向量 RNNs神经网络由神经元组成, python

python 喷泉码

因为要完成毕业设计,毕业设计做的是数据分发与传输的东西。在网络中数据容易丢失,所以我用fountain code做所发送数据包的数据恢复。fountain code属于有限域编码的一部分,有很广泛的应用。 我们日常生活中使用的二维码,就用到foutain code做数据恢复。你遮住二维码的四分之一,用手机的相机也照样能识别。你遮住的四分之一就相当于丢失的数据包。 为了实现并理解foutain

python 点滴学

1 python 里面tuple是无法改变的 tuple = (1,),计算tuple里面只有一个元素,也要加上逗号 2  1 毕业论文改 2 leetcode第一题做出来

Python爬虫-贝壳新房

前言 本文是该专栏的第32篇,后面会持续分享python爬虫干货知识,记得关注。 本文以某房网为例,如下图所示,采集对应城市的新房房源数据。具体实现思路和详细逻辑,笔者将在正文结合完整代码进行详细介绍。接下来,跟着笔者直接往下看正文详细内容。(附带完整代码) 正文 地址:aHR0cHM6Ly93aC5mYW5nLmtlLmNvbS9sb3VwYW4v 目标:采集对应城市的

python 在pycharm下能导入外面的模块,到terminal下就不能导入

项目结构如下,在ic2ctw.py 中导入util,在pycharm下不报错,但是到terminal下运行报错  File "deal_data/ic2ctw.py", line 3, in <module>     import util 解决方案: 暂时方案:在终端下:export PYTHONPATH=/Users/fujingling/PycharmProjects/PSENe

将一维机械振动信号构造为训练集和测试集(Python)

从如下链接中下载轴承数据集。 https://www.sciencedirect.com/science/article/pii/S2352340918314124 import numpy as npimport scipy.io as sioimport matplotlib.pyplot as pltimport statistics as statsimport pandas

Python利用qq邮箱发送通知邮件(已封装成model)

因为经常喜欢写一些脚本、爬虫之类的东西,有需要通知的时候,总是苦于没有太好的通知方式,虽然邮件相对于微信、短信来说,接收性差了一些,但毕竟免费,而且支持html直接渲染,所以,折腾了一个可以直接使用的sendemail模块。这里主要应用的是QQ发邮件,微信关注QQ邮箱后,也可以实时的接收到消息,肾好! 好了,废话不多说,直接上代码。 # encoding: utf-8import lo