面向对象编程的特点

  • 封装是将数据和操作数据的方法封装在一个类中,对外隐藏内部的实现细节,只提供一些公共的方法来访问和修改数据。这样可以提高代码的安全性和可维护性,避免外部直接访问和修改内部数据,导致程序出现错误。

  • 继承允许一个类(子类)继承另一个类(父类)的属性和方法,从而实现代码的复用和扩展。子类可以继承父类的所有公共属性和方法,并可以根据需要添加自己的属性和方法,或者重写父类的方法

  • 多态是指同一个方法可以根据调用对象的不同而表现出不同的行为。在 Python 中,多态是通过方法重写和方法重载来实现的。方法重写是指子类重写父类的方法,方法重载是指在同一个类中定义多个同名方法,但参数列表不同。

  • 抽象类是一种不能被实例化的类,它只能作为其他类的父类,用于定义一些抽象方法,这些方法没有具体的实现,需要在子类中实现

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    from abc import ABC, abstractmethod

    class Shape(ABC):
    @abstractmethod
    def area(self):
    pass

    @abstractmethod
    def perimeter(self):
    pass

Python类的基础知识

类的定义

1
2
3
4
5
6
7
8
9
10
11
12
13
14
>>> class Student(object):
... 'student class'
... def __init__(self, name, age):
... self.name = name
... self.age = age
... def get_name(self):
... return self.name
... def get_age(self):
... return self.age
...
>>> sen = Student('sen', 18)
>>> sen.get_name()
'sen'
>>> sen.get_age()

子类的定义:

1
2
3
4
5
6
7
8
9
10
>>> class BoyStudent(Student):
... def __init__(self, name, age):
... super().__init__(name, age)
... self.sex = 'male'
... def get_sex(self):
... return self.sex
...
>>> sen = BoyStudent('sen', 18)
>>> sen.get_sex()
'male'

类的特殊属性

1
2
3
4
5
6
7
8
9
10
11
12
13
>>> BoyStudent.__doc__
>>> BoyStudent.__name__
'BoyStudent'
>>> BoyStudent.__bases__
(<class '__main__.Student'>,)
>>> BoyStudent.__dict__
mappingproxy({'__module__': '__main__', '__init__': <function BoyStudent.__init__ at 0x104681800>, 'get_sex': <function BoyStudent.get_sex at 0x104681620>, '__doc__': None})
>>> BoyStudent.__module__
'__main__'
>>> BoyStudent.__class__
<class 'type'>
>>> sen.__class__
<class '__main__.BoyStudent'>

静态方法

在 Python 中,静态方法是一种不依赖于类实例和类本身的方法。它可以通过类名直接调用,而不需要创建类的实例。使用 @staticmethod 装饰器来定义静态方法。例如:

1
2
3
4
5
6
class MyClass:
version = '1.0' # 静态属性
@staticmethod
def static_method():
print("这是一个静态方法。")
MyClass.static_method() #调用静态方法

类方法

使用 @classmethod 装饰器定义,并且第一个参数通常命名为 cls,代表类本身。

类方法:

可以访问类变量,通过 cls 参数可以访问和修改类的属性。不能直接访问实例变量,因为没有实例对象的引用。

静态方法:

不能访问类变量和实例变量,它完全独立于类和实例的状态。通常用于与类或实例没有直接关系的通用功能。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class MyClass:
class_variable = 0

def __init__(self, instance_variable):
self.instance_variable = instance_variable

@classmethod
def class_method(cls):
print(f"Class variable: {cls.class_variable}")

@staticmethod
def static_method():
print("This is a static method.")
MyClass.class_method()
MyClass.static_method()

obj = MyClass(10)
obj.class_method()
obj.static_method()

其他要点

  • 组合类似于js中类的聚合,新类直接将旧类的实例包含在自己的属性中,从而达到访问旧类中属性和方法的目的
  • Python的多重继承在查找属性和方法是广度优先搜索的

类相关的内建函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
>>> issubclass(BoyStudent, Student)
True
>>> isinstance(sen, BoyStudent)
True
>>> hasattr(BoyStudent, 'name')
False
>>> hasattr(sen, 'name')
True
>>> dir(Student)
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getstate__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'get_age', 'get_name']
>>> hasattr(Student, 'get_name')
True
>>> getattr(sen, 'name')
'sen'
>>> setattr(sen, 'name', 'sen001')
>>> getattr(sen, 'name')
'sen001'
>>> delattr(sen, 'name')
>>> getattr(sen, 'name')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'BoyStudent' object has no attribute 'name'
>>> vars(sen)
{'age': 18, 'sex': 'male'}

类的特殊属性和方法

slots

  • 当定义了 slots 时,Python 不会为每个实例创建一个 dict 属性字典来存储实例的属性。这可以显著减少内存使用,特别是在创建大量实例的情况下。
  • slots 可以明确地指定一个实例可以拥有的属性列表
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
>>> class BoyStudent(Student):
... 'boy student'
... __slots__ = ['name', 'age', 'sex']
... def __init__(self, name, age):
... super().__init__(name, age)
... self.sex = 'male'
... def get_sex(self):
... return self.sex
...
>>> sen = BoyStudent('sen', 18)
>>> sen.phone = 123 # 没有限制住,因为父类中没有__slot__,所以父类中存在__dict__
>>> vars(sen) # 新的属性存进了父类的__dict__
{'phone': 123}

>>> class Student(object):
... def __init__(self, name, age):
... self.name = name
... self.age = age
... __slots__ = ['name', 'age']
...
>>> sen = Student('sen', 18)
>>> sen.phone = 123
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'Student' object has no attribute 'phone'
AttributeError: 'Student' object has no attribute 'phone'
>>> vars(sen)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: vars() argument must have __dict__ attribute

描述符方法 get set delete

在 Python 中,描述符是一种实现了特定协议(__get____set____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
26
27
28
29
class IntegerValidator:
def __set_name__(self, owner, name):
self.name = name
def __set__(self, instance, value):
if not isinstance(value, int):
raise ValueError(f'{self.name} must be an integer.')
instance.__dict__[self.name] = value
def __get__(self, instance, owner):
if instance is None:
return self
return instance.__dict__.get(self.name)
def __delete__(self, instance):
print(f"Deleting {self.name} from {instance}")
del instance.__dict__[self.name]

class Student:
age = IntegerValidator()

>>> s = Student()
>>> s.age = '28'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 6, in __set__
ValueError: age must be an integer.
>>> s.age = 28
>>> s.age
28
>>> del s.age
Deleting age from <__main__.Student object at 0x1007714f0>