首页 > 编程语言 >Python类

Python类

时间:2024-11-15 13:58:01浏览次数:1  
标签:__ name Python self print age def

五、类

5.1 定义类

  1. 使用 class 关键字定义一个类,类名通常采用首字母大写的驼峰命名法
    class Person:
        pass
    

5.2 构造函数

  1. 基本语法

    class Person:
        def __init__(self, name, age):  # 定义构造函数
            self.name = name            # 初始化 name 属性
            self.age = age              # 初始化 age 属性
    
    
  2. python中,有且仅有一个构造函数。

  3. 构造函数不能有返回值

  4. 构造函数第一个参数必须是self

  5. 可以通过super().__init__()调用父类的构造函数

    • 如果在子类中没有定义__init__方法,会自动调用父类的__init__方法。

    • 但是如果子类定义类__init__方法,不主动调用父类的构造函数,父类的构造函数不会被调用。

      class Animal:
          def __init__(self, name):
              print(f"Animal initialized with name: {name}")
              self.name = name
      
      class Dog(Animal):
          def __init__(self, breed):
              print(f"Dog initialized with breed: {breed}")
              self.breed = breed
      
      # 创建 Dog 对象,不会调用 Animal 的构造函数
      dog = Dog("Labrador")
      
      
      dog = Dog( "Labrador")
      print(dog.name)   # 这里会报错'Dog' object has no attribute 'name'
      
  6. 如果有多重继承,可以指定调用某个父类的构造函数,

    class D(B, C):
        def __init__(self):
            B.__init__(self)  # 调用 B 的构造函数
            C.__init__(self)  # 调用 C 的构造函数
            print("D的构造函数")
    
    
    • 也可以直接super().__init__()调用父类的构造函数,那么,先调用谁呢?
      • 调用顺序是由MRO决定的,怎么查看调用顺序?print(D.__mro__)
  7. __new__方法,是创建一个对象,而上述的__init__()是初始化对象。

    • __new__必须返回一个实例对象,返回的实例对象自动传递给__init__

5.3 属性

  1. 实例属性:在__init__方法中定义,属于某个具体的实例

  2. 类属性:属于类本身,所有实例共享同一属性。

    • 如何理解类属性?

    • 有一个Person

      class Person:
          species = "Human"  # 类属性
          def __init__(self, name, age):
              self.name = name  # 实例属性 name
              self.age = age    # 实例属性 age
      
    • 首先,类属性有点像C++的静态成员变量,

      p = Person("ouyang", 18)
      p2 = Person("ouyang2", 19)
      print(p.species)    # Human
      print(p2.species)   # Human
      Person.species = "People"
      print(p.species)    # People
      print(p2.species)   # People
      
    • 但是,python中,修改了其中一个实例对象的类属性后,并不会影响其他实例对象的类属性,这怎么理解?

      p = Person("ouyang", 18)
      p2 = Person("ouyang2", 19)
      print(p.species)    # Human
      print(p2.species)   # Human
      p2.species = "People"
      print(p.species)    # Human
      print(p2.species)   # People
      
    • 第5行,实际上是p2创建了一个实例属性,同样是species,以后再访问species,会是p2的实例属性,而不再访问类属性。所以,p2修改的是自己的实例属性,自然不会影响到其他的实例对象,同样也不会影响到类属性。

5.4 方法

  1. 实例方法:第一个参数必须是self,并且访问属性时,必须使用self.属性的方式访问。

    • 实例方法只能实例对象访问吗?类能访问吗?答案是可以的,因为python中,「类」是一个特殊的「实例对象」,是python自动帮我们创建好的,如下代码

      class A :
          def __init__(self) -> None:
              self.name = "A"
          def hi(self):
              print("hello")
      
      A.hi(A)   # hello
      
    • 但是,不建议这样使用,因为实例方法可以使用实例属性,但是「类」,没有实例属性,如下

      class A :
          def __init__(self) -> None:
              self.name = "A"
          def hi(self):
              print("hello", self.name)
      
      A.hi(A)  # 报错 AttributeError: type object 'A' has no attribute 'name'
      
  2. 类方法:第一个参数必须是cls,并且需要通过@classmethod装饰器来定义,只能操作类属性

    class Person:
        species = "Human"  # 类属性
        def __init__(self, name, age):
            self.name = name  # 实例属性 name
            self.age = age    # 实例属性 age
        
        @classmethod
        def Person_greet(cls):
            print("hello person")
            cls.species = "People"    # 改变了类属性  会影响到其他实例对象的类属性
    
  3. 静态方法:绑定到类上,通过@staticmethod装饰器来定义,但是不访问属性,可以认为就是类中的普通函数。

    	@staticmethod
        def Person_greet(cls):
            print("hello person")
            cls.species = "People"
    
  4. 类中的普通函数:属于这个类的函数,但是不能访问实例属性,也不能访问类属性,和静态方法的主要区别就是,静态方法能够通过实例对象访问,但是类中的普通函数只能通过类名来访问。

    class Person:
        def Person_greet():
            print("hello person")
    Person.Person_greet()    # hello person
    
  5. 注意,方法名不要以__双下划线开头,这有别的含义。

5.5 继承

  1. 基本语法class Son(Father):Son类继承了Father类

  2. 重写

    • 子类的方法签名(方法名、参数列表)必须与父类方法一致。
    • 直接调用,会调用子类的,如果想要调用父类的可以使用super().方法名
  3. super()函数

    • 如果有多个父类,super()到底是哪个父?有一个叫做方法解析顺序(MRO),决定了父类方法的调用顺序。可以通过print(类名.mro())来查看

    • 使用super()调用父类的构造函数时,会根据MRO,调用所有父类的构造函数。但是,调用一般方法(假设所有父类都有),只会调用MRO顺序的第一个父类。

    • 假如我不希望使用MRO顺序呢?我希望调用某个父类,看下面例子

      class A:
          def say(self):
              print("A")
      
      class B:
          def say(self):
              print("B")
      
      class C(B):
          def say(self):
              print("C")
      
      class D(A, C) :
          def say(self):
              B.say(self)   # 虽然D只继承了A、C,但是C继承了B,所以可以调用B
              print("D");
      d = D();
      d.say()    # 打印B D、
      

5.6 封装

  1. 在属性前,加前缀_表示「保护权限」,加前缀__表示「私有属性」
    • 保护权限,不是强制性的规则,起到「提醒作用」,也就是说,在类外部仍然可以访问。
    • 私有权限,禁止外部使用,但是可以通过对象名._类名__私有属性名来访问。

5.7 特殊方法

  1. __str__(self)

    • 当使用print,或者str函数作用于该对象时,获取该对象的字符串形式

    • 例子

      class Person:
          _species = "Human"  # 类属性
          def __init__(self, name, age):
              self.__name = name  # 实例属性 name
              self.age = age    # 实例属性 age
              
          def __str__(self) :
              return f"Person(name={self.__name}, age={self.age})"
      
      p = Person("ouyang", 18)
      print(p)   # Person(name=ouyang, age=18)
      
    • 还有个类似的__repr__:在调试和交互模式下显示对象的更精确或有用的描述。实现 __repr__ 方法可以使对象在输出时显示定制的信息,而不是直接使用对象的内存地址。

  2. __len__(self)

    • 当调用len(实例对象)时,会调用__len__方法,如果没有实现,则会抛出异常
  3. __getitem__(self, key)

    • 使对象能够像访问「字典」一样,通过key,得到相应的value
  4. __setitem__(self, key, value)

    • 使对象能够像访问「字典一样」,通过key,设置value

    •   class Person:
            _species = "Human"  # 类属性
            def __init__(self, name, age):
                self.__name = name  # 实例属性 name
                self.age = age    # 实例属性 age
                
            def __getitem__(self, key):
                if key == "name":
                    return self.__name
                else:
                    return self.age
            def __setitem__(self, key, val):
                if key == "name":
                    self.__name = val
                else :
                    self.age = val
        
        p = Person("ouyang", 18)
        p["name"] = "ouyang2"
        print(p["name"])    # ouyang2
      
  5. __del__(self)

    • 析构器,对象销毁前的清理操作,但是并不建议依赖__del__进行内存管理,手动调用del obj并不会立刻触发__del__,而是垃圾回收机制决定何时释放内存。
    • 可以使用上下文管理器替换__del__,更清晰和安全
  6. 上下文管理器

    • __enter__:在进入with语句代码块时调用,负责设置或分配资源,并且可以返回资源对象

    • __exit__:在离开 with 语句代码块时调用,负责清理或释放资源。无论代码块是否正常结束或出现异常,__exit__ 都会执行。

    • 例子

      class FileHandler:
          def __init__(self, filename, mode):
              self.file = open(filename, mode)
      
          def __enter__(self):
              return self.file  # 返回文件对象供 with 语句内使用
      
          def __exit__(self, exc_type, exc_value, traceback):
              self.file.close()  # 确保在 with 代码块后关闭文件
      
      # 使用自定义上下文管理器
      with FileHandler("example.txt", "w") as file:
          file.write("Hello, World!")
      
  7. __iter__(self)

    • 当一个对象实现了 __iter__ 方法,它就可以被 Python 的内置函数 iter() 调用,并且可以用于 for 循环、生成列表、使用 list() 等构造函数。
    • 返回值: __iter__ 方法必须返回一个迭代器对象,也就是一个实现了 __next__ 方法的对象。
  8. __next__(self)

    • 通常__iter____next__搭配使用。

    • __next__ 方法是实际提供数据的地方。每次调用 __next__ 时,返回当前值,并将迭代器的状态更新为下一个值。它在没有更多数据可返回时抛出 StopIteration 异常,表示迭代结束。

    • 在使用 for 循环时,Python 首先会调用 __iter__ 方法获取一个迭代器对象,然后反复调用 __next__ 来逐步获取值。

    • 例子

      class Counter:
          def __init__(self, start, end):
              self.current = start
              self.end = end
      
          def __iter__(self):
              return self  # 返回自身作为迭代器
      
          def __next__(self):
              if self.current >= self.end:
                  raise StopIteration  # 无更多值时停止迭代
              self.current += 1
              return self.current - 1
      
      # 使用 Counter 迭代器
      counter = Counter(1, 4)
      for num in counter:
          print(num)  # 输出 1, 2, 3
      
  9. __add__(self, other)

    • 自定义类的加法
  10. __sub__(self, other)

    • 自定义类的减法

    • 类似的还有__mul__乘法、__truediv__除法

    • 例子

      class Vector:
          def __init__(self, x, y):
              self.x = x
              self.y = y
      
          def __add__(self, other):
              return Vector(self.x + other.x, self.y + other.y)
      
          def __sub__(self, other):
              return Vector(self.x - other.x, self.y - other.y)
      
          def __mul__(self, other):
              return Vector(self.x * other, self.y * other)
      
          def __truediv__(self, other):
              return Vector(self.x / other, self.y / other)
      	# 打印时
          def __repr__(self):
              return f"Vector({self.x}, {self.y})"
      
      v1 = Vector(3, 4)
      print(v1 + v1)  # Vector(6, 8)
      print(v1 - v1)  # Vector(0, 0)
      print(v1 * 3)   # Vector(9, 12)
      print(v1 / 2)   # Vector(1.5, 2.0)
      
  11. __eq__(self, other)

    • 自定义类的==操作,返回一个布尔值
  12. __lt__(self, other)

    • 自定义类的<操作,返回一个布尔值

    • 类似的还有__le__小于等于、__gt__大于、__ge__:大于等于、__ne__:不等于

    • 例子

      class Person:
          def __init__(self, name, age):
              self.name = name
              self.age = age
      
          def __eq__(self, other):
              return self.age == other.age
      
          def __lt__(self, other):
              return self.age < other.age
      
          def __le__(self, other):
              return self.age <= other.age
      
          def __gt__(self, other):
              return self.age > other.age
      
          def __ge__(self, other):
              return self.age >= other.age
      
          def __ne__(self, other):
              return self.age != other.age
      
      p1 = Person("Alice", 30)
      p2 = Person("Bob", 25)
      print(p1 > p2)   # 输出: True
      print(p1 != p2)  # 输出: True
      
      
  13. __call__(self, ...)

    • 允许类的实例像函数一样被调用(C++中的仿函数)。

    • 语法

      class MyClass:
          def __call__(self, *args, **kwargs):
              pass
      
    • 例子

      class Greeter:
          def __init__(self, greeting):
              self.greeting = greeting
      
          def __call__(self, name):
              return f"{self.greeting}, {name}!"
      
      # 创建 Greeter 类的实例
      greet = Greeter("Hello")
      
      # 使用像调用函数一样调用实例
      print(greet("Alice"))  # 输出: Hello, Alice!
      

5.8 多态

  1. 先看一个例子

    class Dog:
        def speak(self):
            print("Dog barks")
    
    class Cat:
        def speak(self):
            print("Cat meows")
    
    class Human:
        def speak(self):
            print("Human talks")
    
    # 使用不同类型的对象,只要它们都有相同的方法,Python就能调用
    def make_sound(animal):
        animal.speak()
    
    make_sound(Dog())    # Dog barks
    make_sound(Cat())    # Cat meows
    make_sound(Human())  # Human talks
    
    • 有一个函数make_sound(),能够接收所有,包含speak()方法的类,然后调用speak()方法。
    • 总感觉不伦不类的,因为对比C++,父类指针指向子类对象,但是因为python一个变量,类型是能够变的,所以这里的animal,本来就可以接收任何数据类型,所以,python的多态,没有C++那么多限制,比如,子类必须要「实现父类的所有抽象方法」。
    • 所以,python多态总觉得「不是真正的多态。。。」

5.9 抽象类

  1. 抽象类是一种特殊的类,用来定义一组方法,子类必须实现这些方法。抽象类本身不能被实例化。它通过定义抽象方法来强制子类去实现某些方法。抽象类有两个主要特性:

    • 抽象方法:这是没有实现的函数,它只有声明没有方法体。子类必须实现全部抽象方法,否则子类也会被视为抽象类,不能实例化。
    • 不能实例化:你不能直接创建一个抽象类的对象,必须通过继承它的子类来创建实例。
  2. 使用@abstractmethod装饰器来标记一个方法为抽象方法

  3. 例子

    from abc import ABC, abstractmethod
    
    class Animal(ABC):  # Animal 是一个抽象类
        @abstractmethod
        def make_sound(self):
            pass  # 这个方法在抽象类中没有实现
    
    class Dog(Animal):  # Dog 是 Animal 的子类
        def make_sound(self):
            return "Woof"
    
    class Cat(Animal):  # Cat 是 Animal 的子类
        def make_sound(self):
            return "Meow"
    
    # 实例化
    dog = Dog()
    print(dog.make_sound())  # 输出: Woof
    
    cat = Cat()
    print(cat.make_sound())  # 输出: Meow
    
    

标签:__,name,Python,self,print,age,def
From: https://www.cnblogs.com/ouyangxx/p/18547844

相关文章

  • Python开发环境搭建(PyCharm+Anaconda+Git+Gitee)
    一、Anaconda介绍1.1为什么选择Anaconda?Anaconda是一个开源的Python发行版本,主要用于数据科学和机器学习,它包含了Python、conda以及众多工具和库,让我们可以轻松的构建和管理python虚拟环境,方便的进行python项目开发。下面是选择Anaconda的理由:安装简单方便便捷的Python虚拟......
  • 【第二章】Python基础之内建常用数据类型与数值型
    内建常用数据类型分类数值型  int、float、complex、bool序列sequence  字符串str、字节序列bytes、bytearray  列表list、元组tuple键值对  集合set、字典dict数值型int、float、complex、bool都是class,1、5.0、2+3j都是对象即实例int:   ......
  • python编写的扫雷游戏
    使用python语言编写的命令行方式的交互的《扫雷》游戏:importnumpyasnpimportrandomfromtypingimportListH=36W=64defbelong_to(h,w,H=H,W=W):near=[]foriinrange(h-2,h+3):forjinrange(w-2,w+3):ifi>=0andj......
  • Python-django-flask游戏虚拟物品道具商城管理系统
    文章目录项目介绍系统开发技术路线具体实现截图开发技术django项目代码结构参考解析论文大纲目录参考核心代码部分展示源码/演示视频获取方式项目介绍游戏虚拟物品管理系统的主要使用者分为管理员和用户,实现功能包括管理员:首页、个人中心、用户管理、游戏虚拟物品......
  • 李沐《动手学深度学习》kaggle树叶分类(ResNet18无预训练)python代码实现
    前言    在尝试这个树叶分类之前,作者仅仅看完了ResNet残差网络一章,并没有看后面关于数据增强的部分,这导致在第一次使用最原始的ResNet18直接跑完训练数据之后的效果十分的差,提交kaggle后的准确仅有20%左右。本文最后依然使用未经预训练的手写ResNet18网络,但做了一定的......
  • Python小白学习教程从入门到入坑------第三十二课 生成器(语法进阶)
    目录一、生成器generator1.1生成器表达式1.1.1表达式一1.1.2表达式二二、可迭代对象、迭代器、生成器三者之间的关系2.1定义与特性2.2关系与区别一、生成器generator在Python中,生成器(Generators)是一种用于迭代对象的特殊类型函数。它们允许你生成一个序列......
  • Python小白学习教程从入门到入坑------第三十一课 迭代器(语法进阶)
    目录一、可迭代对象Iterable1.1可迭代对象的条件1.2for循环工作原理1.3isinstance()二、迭代器 Iterator2.1 __iter__() 和 __next__()2.2 可迭代对象&迭代器2.2.1定义与特性2.2.2 关系与转换2.2.3应用场景三、迭代器协议(了解即可)四、自定义迭代器类......
  • Python从0到100(七十二):Python OpenCV-OpenCV实现手势音量控制(文末送书)
    前言:零基础学Python:Python从0到100最新最全教程。想做这件事情很久了,这次我更新了自己所写过的所有博客,汇集成了Python从0到100,共一百节课,帮助大家一个月时间里从零基础到学习Python基础语法、Python爬虫、Web开发、计算机视觉、机器学习、神经网络以及人工智能相关知......
  • python自动化之selenium 封装
    fromseleniumimportwebdriverfromtimeimportsleepclasscms(object):definit(self):passdefdl(self):self.dx=webdriver.Chrome()self.dx.get("http://cms.duoceshi.cn/manage/login.do")self.dx.find_element_by_name("userAccount&qu......
  • python从旧库中导出csv并导入新库
    在线的游戏,迁移数据库,数据比较大,游戏不能停很久,先使用sqldump导入不变的表,再使用python导出可变的表到csv文件,导入到新库.找出各表中csv中最大的id,然后停服, 然后根据各表的id,从id位置开始再导出新增数据,再导入到新库.export.py"""导出msql表格"""impo......