1 类 1.1 类的定义和使用 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 class Dog : """一次模拟小狗的简单尝试。""" def __init__ (self, name, age ): """初始化属性name和age。""" self.name = name self.age = age self.type = 1 def sit (self ): """模拟小狗收到命令时蹲下。""" print (f"{self.name} is now sitting." ) def roll_over (self ): """模拟小狗收到命令时打滚。""" print (f"{self.name} rolled over!" ) my_dog = Dog('Willie' , 6 ) my_dog.name my_dog.sit() my_dog.roll_over()
创建实例时,有些属性无须通过形参来定义,可在方法__init__() 中为其指定默认值。
1.2 __init__
方法 __init__
方法是类的特殊方法之一,它用于初始化类的实例。
1 2 3 4 5 6 7 8 class Person : def __init__ (self, name="Unknown" , age=0 ): self.name = name self.age = age person1 = Person() person2 = Person("Bob" , 25 )
1 2 3 4 5 6 7 8 9 10 11 12 13 class FileHandler : def __init__ (self, filename, mode ): self.filename = filename self.mode = mode self.file = open (filename, mode) def close (self ): self.file.close() file_handler = FileHandler("example.txt" , "w" ) file_handler.file.write("Hello, World!" ) file_handler.close()
以上示例中在 __init__
方法中进行文件打开。
1.3 类变量 属于类本身这个对象的属性,所有该类的对象都共享类变量。类变量可以通过类名、对象名调用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 from pprint import pprint class Student : student_count = 8 def main (): print (Student.__name__) print (Student.student_count) print (getattr (Student, "student_count" )) print (getattr (Student, "unknown" , "10" )) Student.student_count = 89 setattr (Student, "student_count" , 100 ) print (Student.student_count) Student.newattribute = "hello" print (Student.newattribute) delattr (Student, "newattribute" ) s1 = Student() s2 = Student() Student.student_count = 4 print (s1.student_count) print (s2.student_count) pprint(Student.__dict__) if __name__ == '__main__' : main()
1.4 实例变量与函数 定义实例变量与函数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 class Student : def __init__ (self, name: str ): self.name = name def say_hello (self, msg: str ): print (f"Hello {msg} , {self.name} " ) def main (): s2 = Student("Tom" ) s1.say_hello("1111" ) s2.say_hello("2222" ) s1.gender = 'Male' print (s1.gender) print (s2.gender)
1.5 私有属性与函数 在Python中并没有严格的权限限定符去进行限制,主要通过命名来进行区分。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 class Student : def __init__ (self, name: str ): self.__name = name def __say_hello (self, msg: str ): print (f"Hello {msg} , {self.__name} " ) def main (): s1 = Student("Jack" ) print (s1.__name) print (s1._Student__name) s1._Student__say_hello("1111" ) if __name__ == '__main__' : main()
1.6 __new__
方法 __new__
方法是在对象实例化之前由 Python 解释器调用的,而 __init__
方法则在对象实例化之后调用,用于对象的初始化。
可以在你的类中定义 __new__
方法,通常会接受类本身作为第一个参数(通常命名为 cls
),并返回一个对象实例。这个方法的主要目的是创建对象实例。__new__
方法允许你控制对象的创建过程。
1 2 3 4 5 6 7 8 9 10 class Student : def __new__ (cls, first_name, last_name ): obj = super ().__new__(cls) obj.first_name = first_name obj.last_name = last_name return obj student = Student("Jack" , "Ma" ) print (student.first_name) print (student.last_name)
2 继承 2.1 方法重载 子类通过重写父类的方法,实现方法的重载:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 class Person : color = 1 def __init__ (self ): self.name = "Jack" def say (self ): print ("Hello from person" ) def print_color (self ): print (self.color) class Student (Person ): color = 2 def __init__ (self ): super ().__init__() self.school = "Abc" def say (self ): super ().say() print ("Hello from student" ) def render (person: Person ): person.say()
子类可以重载父类的方法和类属性。
2.2 继承和混入
1 2 3 4 5 6 7 8 9 10 11 class Father (object ): def run (self ): print ("run in father" ) class Son (Father ): def run (self ): super ().run() print ("run in son" ) obj2 = Son() obj2.run()
输出:
1 2 run in father run in son
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 import jsonclass JSONMixin : def to_json (self ): return json.dumps(self.__dict__) class Person : def __init__ (self, name, age ): self.name = name self.age = age class JSONPerson (Person, JSONMixin): pass person = JSONPerson("Alice" , 30 ) json_data = person.to_json() print (json_data)
在上面的示例中,JSONPerson
类继承了 Person
类和 JSONMixin
类。通过混入,JSONPerson
类获得了 to_json
方法,可以将其属性转换为 JSON 字符串。
多继承可以在某些情况下提供灵活性,但要小心避免菱形继承问题(即多个父类共同继承同一个祖先类,可能导致方法冲突)。
混入通常用于将通用功能添加到多个类中,提供代码重用和模块化。混入类通常不应该实例化,而应该与其他类一起使用。
2.3 抽象类 抽象类是一个不能被实例化的类,抽象方法是一个没有具体实现的方法,Python并没有直接支持抽象类,提供了一个模块(abc)来允许定义抽象类。 抽象类的定义:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 from abc import ABC, abstractmethod class Action (ABC ): @abstractmethod def execute (self ): pass class CreateStudentAction (Action ): def execute (self ): print ("Create a new student" ) def execute_action (action: Action ): action.execute() def main (): create_student_action = CreateStudentAction() execute_action(create_student_action) if __name__ == '__main__' : main()
抽象类的主要用途是定义一组接口或方法,以确保派生类提供了必需的实现。一般的使用场景包括:
制定接口规范 :抽象类可以定义一组方法,然后子类需要提供这些方法的具体实现。这对于确保多个类遵循相同的接口规范非常有用。
强制实现 :通过使用抽象类,你可以确保派生类提供了必要的实现,而不会遗漏任何关键方法。
代码结构组织 :抽象类有助于组织代码结构,将通用的接口和方法集中到基类中,减少了代码重复。
多态性 :抽象类可以用于多态性,允许不同的子类实现相同的接口,这有助于更容易地切换或扩展功能。
3.3 多继承
子类继承多个父类,同名方法存在于多个父类,按照继承顺序优先调用第一个继承的父类方法
通过类名指定调用那个父类的方法,需要传self参数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 class Parent1 : def __init__ (self ): pass def render (self ): print ("parent 1" ) def hello (self ): print ("hello parent 1" ) class Parent2 : def __init__ (self ): pass def render (self ): print ("parent 2" ) def hello (self ): print ("hello parent 2" ) class Child (Parent2, Parent1): def __init__ (self ): Parent1.__init__(self) def render (self ): super ().render() def hello (self ): Parent1.hello(self) def main (): child = Child() child.render() child.hello() if __name__ == '__main__' : main()
3 枚举 3.1 枚举的定义 Python提供了一个名为enum
的模块,用于创建和使用枚举。定义枚举类型:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 class Gender (Enum ): MALE = 1 FEMALE = 2 class Student : def __init__ (self, gender: Gender ): self.gender = gender def main (): print (type (Gender.MALE)) print (Gender.MALE.name) print (Gender.MALE.value) for gg in Gender: print (gg) student = Student(Gender.MALE) if student.gender == Gender.MALE: print ("This student is a male" ) else : print ("This student is a female" ) s_gender = "FEMALE" student.gender = Gender[s_gender] print (student.gender) i_gender = 2 print (Gender(i_gender))
枚举类型中存储的格式为key-value,枚举类型可以进行迭代。
定义枚举时,可以使用auto()
让Python自动分配值:
1 2 3 4 5 6 7 8 from enum import Enum, autoclass Color (Enum ): RED = auto() GREEN = auto() BLUE = auto() print (Color.BLUE.value)
3.2 枚举别名和装饰器 如果定义的枚举中有相同的value值,则称为同一个值的枚举别名,底层其实是同一个枚举。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 from enum import Enum class Status (Enum ): SUCCESS = 1 OK = 1 FAIL = 2 WRONG = 2 def main (): for s in Status: print (s.name) print (Status.__members__) print (Status.SUCCESS == Status.OK) print (Status.SUCCESS is Status.OK) if __name__ == '__main__' : main()
输出:
1 2 3 4 5 SUCCESS FAIL {'SUCCESS': <Status.SUCCESS: 1>, 'OK': <Status.SUCCESS: 1>, 'FAIL': <Status.FAIL: 2>, 'WRONG': <Status.FAIL: 2>} True True
通过使用枚举装饰器 @enum.unique
可以禁止定义枚举别名,防止同一个value定义不同的枚举,造成冲突。
1 2 3 4 5 6 7 import enum@enum.unique class Gender (Enum ): MALE = 1 FEMALE = 2
3.3 定制和扩展枚举 通过重写枚举类中的 __str__
、__eq__
等方法,实现不同的功能:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 import enum from enum import Enum @enum.unique class Gender (Enum ): MALE = 1 FEMALE = 2 def __str__ (self ): return f"{self.name} ({self.value} )" def __eq__ (self, other ): if isinstance (other, int ): return self.value == other if isinstance (other, str ): return self.name == other.upper() if isinstance (other, Gender): return self is other return False for g in Gender: print (g) print (Gender.MALE == 1 ) print (Gender.MALE == "FEMALE" )
如果定义比较相关操作,可以使用 total_ordering
装饰器,你只需要定义一个或多个比较操作方法中的一个(例如 __lt__
、__le__
、__eq__
、__ne__
、__gt__
或 __ge__
),然后装饰器将自动为你生成其余的方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 from functools import total_ordering@total_ordering class MyClass : def __init__ (self, value ): self.value = value def __eq__ (self, other ): return self.value == other.value def __lt__ (self, other ): return self.value < other.value obj1 = MyClass(5 ) obj2 = MyClass(10 ) print (obj1 < obj2) print (obj1 == obj2) print (obj1 <= obj2) print (obj1 > obj2) print (obj1 >= obj2)
4 描述符 Python中的描述符(descriptor)是一种强大的编程机制,允许你在对象属性的访问和修改过程中定义自定义行为。描述符是通过实现特定方法的类来实现的,这些方法包括 __get__
、__set__
和 __delete__
。描述符通常用于控制属性的访问和修改,以便实现数据封装和验证。
下面是描述符的主要功能和用法:
__get__
方法 :当你尝试访问属性时,__get__
方法会被调用。这允许你自定义属性的获取行为。通常,__get__
方法返回属性的值。
__set__
方法 :当你尝试为属性分配一个新值时,__set__
方法会被调用。这允许你自定义属性的设置行为。你可以在 __set__
方法中进行验证和限制。
__delete__
方法 :当你尝试删除属性时,__delete__
方法会被调用。这允许你自定义属性的删除行为。通常,__delete__
方法用于清理或处理与属性相关的资源。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 class CustomDescriptor : def __get__ (self, instance, owner ): print ("Getting the value" ) return instance._value def __set__ (self, instance, value ): if value < 0 : raise ValueError("Value cannot be negative" ) print ("Setting the value" ) instance._value = value def __delete__ (self, instance ): print ("Deleting the value" ) del instance._value class MyClass : def __init__ (self, value ): self._value = value descriptor = CustomDescriptor() obj = MyClass(10 ) print (obj.descriptor) obj.descriptor = 20 del obj.descriptor
输出:
1 2 3 4 Getting the value 10 Setting the value Deleting the value
在上面的示例中,CustomDescriptor
类实现了描述符的三个主要方法。MyClass
类中的 descriptor
属性使用了这个自定义描述符。当我们访问、设置和删除这个属性时,对应的 __get__
、__set__
和 __delete__
方法被调用,这使得我们可以自定义属性的行为。
描述符通常用于以下场景:
属性验证和控制 :描述符允许你在属性赋值时进行验证,确保属性值满足特定条件,如范围限制、数据类型等。
属性访问控制 :你可以使用描述符来控制属性的访问权限,例如将属性设置为只读或私有。
属性懒加载 :描述符可以用于延迟加载属性的值,直到首次访问。
属性计算 :你可以使用描述符来计算属性的值,而不是存储它们。