Python学习笔记-面向对象篇

组合

class Engine:
    """引擎类,提供基本的引擎功能"""
    def __init__(self, power):
        self.power = power
 
    def start(self):
        print(f"引擎启动,功率:{self.power}")
 
class Car:
    """汽车类,使用引擎类的功能"""
    def __init__(self, engine, color):
        self.engine = engine  # 引擎组合
        self.color = color
 
    def start_car(self):
        self.engine.start()  # 使用引擎的start方法
 
# 创建一个Engine实例
engine = Engine(200)
 
# 创建一个Car实例,并使用Engine实例
car = Car(engine, "红色")
 
# 启动汽车,实际上是启动引擎
car.start_car()

绑定

class MyClass:
    def __init__(self, value):
        self.attribute = value
 
obj = MyClass(10)
print(obj.attribute)  # 输出: 10

# 在类定义外部进行绑定通常是指给实例添加新的属性。
class MyClass:
    pass
 
obj = MyClass()
obj.new_attribute = 20
print(obj.new_attribute)  # 输出: 20

MRO:方法解析顺序

class A:
    pass
 
class B(A):
    pass
 
class C(A):
    pass
 
class D(B, C):
    pass

print(D.mro())  # 输出:[<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>]

多态

class Animal:
    def speak(self):
        raise NotImplementedError("子类必须实现该方法")
 
class Dog(Animal):
    def speak(self):
        return "汪汪汪"
 
class Cat(Animal):
    def speak(self):
        return "喵喵喵"
 
def animal_speaks(animal):
    """接受所有Animal类的子类实例,并调用它们的speak方法"""
    print(animal.speak())
 
# 使用示例
dog = Dog()
cat = Cat()
 
animal_speaks(dog)  # 输出: 汪汪汪
animal_speaks(cat)  # 输出: 喵喵喵

鸭子类型

class Duck:
    def quack(self):
        print("Quack")
 
class Person:
    def quack(self):
        print("I am quacking like a duck!")
 
def perform_quack(duck):
    duck.quack()
 
duck = Duck()
perform_quack(duck)  # 输出: Quack
 
person = Person()
perform_quack(person)  # 输出: I am quacking like a duck!

私有变量

class MyClass:
    def __init__(self):
        self.__private_var = 123  # 私有变量
 
    def get_private_var(self):  # 提供一个公共方法来获取私有变量的值
        return self.__private_var
 
    def update_private_var(self, value):  # 提供一个公共方法来更新私有变量的值
        self.__private_var = value
 

obj = MyClass()
# print(obj.__private_var)  # AttributeError
print(obj.get_private_var())  # 输出: 123
obj.update_private_var(456)
print(obj.get_private_var())  # 输出: 456

下划线

# _xx:以单下划线开头,表示这是一个保护成员,只有类对象和子类对象自己能访问到这些变量。以单下划线开头的变量和函数被默认当作是内部函数,使用from module improt *时不会被获取,但是使用import module可以获取
# __xx:双下划线开头,表示为私有成员,只允许类本身访问,子类也不行。在文本上被替换为_class__method 或者 _class__变量名
# __xx__:双下划线开头,双下划线结尾。一种约定,Python内部的名字,用来区别其他用户自定义的命名,以防冲突。是一些 Python 的“魔术”对象,表示这是一个特殊成员
# xx_:以单下划线结尾仅仅是为了区别该名称与关键词

slots属性

# Python中的__slots__是一种优化机制,它限制了类实例能够添加的属性。使用__slots__主要是为了节省内存,尤其是当你有大量实例且具有相同的属性时。继承来自父类的slots属性在子类中不生效。

class Person:
    __slots__ = ['name', 'age']
 
    def __init__(self, name, age):
        self.name = name
        self.age = age
 
# 创建实例
p = Person('Alice', 30)
p.name = 'Bob'  # 允许
p.score = 100   # 会抛出AttributeError,因为没有在__slots__中定义

内省

# dir([object]):返回对象的属性列表。如果没有提供参数,则返回当前范围内的变量、方法和定义的类。
class Person:
    def __init__(self, name):
        self.name = name
 
p = Person('Alice')
print(dir(p))  # 输出对象p的属性列表

# type(object):返回对象的类型。
print(type(42))  # 输出:<class 'int'>

# hasattr(object, name):检查对象是否有指定的属性。
class Person:
    def __init__(self, name):
        self.name = name
 
p = Person('Alice')
print(hasattr(p, 'name'))  # 输出:True

# getattr(object, name[, default]):返回对象指定的属性值,如果属性不存在,则返回默认值。
class Person:
    def __init__(self, name):
        self.name = name
 
p = Person('Alice')
print(getattr(p, 'name', 'default'))  # 输出:'Alice'
print(getattr(p, 'age', 'default'))  # 输出:'default'

# setattr(object, name, value):设置对象指定的属性值。
class Person:
    def __init__(self, name):
        self.name = name
 
p = Person('Alice')
setattr(p, 'name', 'Bob')
print(p.name)  # 输出:'Bob'

# delattr(object, name):删除对象指定的属性。
class Person:
    def __init__(self, name):
        self.name = name
 
p = Person('Alice')
delattr(p, 'name')
print(p.name)  # 抛出AttributeError

# isinstance(object, classinfo):检查对象是否是指定类的实例。
class Person:
    pass
 
p = Person()
print(isinstance(p, Person))  # 输出:True

# issubclass(class, classinfo):检查类是否是指定的基类的子类。
class Person:
    pass
 
class Student(Person):
    pass
 
print(issubclass(Student, Person))  # 输出:True


# 模块对象主要的元数据如下表:
元数据	含义说明
__name__	模块名
__doc__	    模块的文档注释
__file__	源文件名(包含路径)
__dict__	包含了模块里可用的属性名-属性的字典;也就是可以使用模块名.属性名访问的对象。

# 函数对象主要的元数据如下表:
元数据	含义说明
__name__	函数名
__doc__	函数的文档注释
__module__	函数所在的模块名,如果是入口模块会被重置为__main__
__defaults__	默认位置参数的值元组。
__kwdefaults__	按名的默认参数的值元组
__code__	代码对象,函数的主代码
__class__	指向函数对象类型

# 类的元数据如下表:
元数据	含义说明
__name__	类名
__doc__	类的文档注释
__module__	类所在的模块名,注意如果是入口模块,显示的是__main__模块
__bases__	父类元组
__dict__	类对象的所有属性信息用字典的方式表示

# 实例(也就是类的对象)元数据如下表:
元数据	含义说明
__doc__	类的文档注释
__class__	指向类对象
__dict__	对象的属性,包括私有属性,注意私有属性的命名方式

# 对象方法是特殊的函数,它有函数的全部元数据,也有自己特有的元数据如下表:
元数据	含义说明
__name__	函数名
__doc__	函数的文档注释
__module__	函数所在的模块名,如果是入口模块会被重置为__main__
__defaults__	默认位置参数的值元组。
__kwdefaults__	按名的默认参数的值元组
__code__	代码对象,函数的主代码
__class__	指向函数对象类型
__self__	方法特有的属性:指向实例对象
__func__	方法特有的属性:指向函数对象自己

混入类

class LoggerMixin:
    def log(self, message):
        print(f"[LOG]: {message}")

class DataProcessor(LoggerMixin):
    def process_data(self, data):
        self.log("Starting data processing")
        # 数据处理逻辑
        processed_data = data * 2  # 简单的数据处理示例
        self.log("Data processing completed")
        return processed_data

class AnotherClass(LoggerMixin):
    def perform_action(self):
        self.log("Performing an action in AnotherClass")

# 使用混入类的DataProcessor
processor = DataProcessor()
result = processor.process_data(10)
print(f"Processed Data: {result}")

# 使用混入类的AnotherClass
another_instance = AnotherClass()
another_instance.perform_action()

魔术方法

魔术方法:对象的创建、初始化和销毁过程

# __new__、__init__、__del__
class Person:
    def __new__(cls, *args, **kwargs):
        print("Creating a new instance...")
        instance = super().__new__(cls)
        return instance
    
    def __init__(self, name, age):
        print("Initializing Person object...")
        self.name = name
        self.age = age
    
    def __del__(self):
        print(f"Deleting {self.name}...")

p = Person("Alice", 30)
print(f"Created {p.name}, age {p.age}")
del p

魔术方法:对象字符串描述

# __repr__、__str__
# 如果只定义了 __str__ 方法,而没有定义 __repr__ 方法,则在 repr(p) 中会调用 str(p) 的结果
class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y
    
    def __repr__(self):
        return f"Point({self.x}, {self.y})"  # 完整、详细的表示形式
    
    def __str__(self):
        return f"({self.x}, {self.y})"       # 简洁、友好的表示形式

p = Point(3, 4)
print(repr(p))  # 输出: Point(3, 4)
print(str(p))   # 输出: (3, 4)

魔术方法:对象的比较运算

# __lt__、__gt__、__eq__、__ne__、__le__、__ge__
class MyNumber:
    def __init__(self, value):
        self.value = value
 
    def __lt__(self, other):
        return self.value < other.value
 
    def __gt__(self, other):
        return self.value > other.value
 
    def __eq__(self, other):
        return self.value == other.value
 
    def __ne__(self, other):
        return self.value != other.value
 
    def __le__(self, other):
        return self.value <= other.value
 
    def __ge__(self, other):
        return self.value >= other.value

a = MyNumber(10)
b = MyNumber(20)
print(a < b)  # 输出: True
print(a > b)  # 输出: False
print(a == b) # 输出: False
print(a != b) # 输出: True
print(a <= b) # 输出: True
print(a >= b) # 输出: False

魔术方法:对象其他常见运算

# __add__、__len__、__contains__、__bool__
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 __len__(self):
        return abs(self.x) + abs(self.y)
    
    def __contains__(self, item):
        return item == self.x or item == self.y
    
    def __bool__(self):
        return self.x != 0 or self.y != 0

v1 = Vector(3, 4)
v2 = Vector(1, 2)

v3 = v1 + v2
print(v3)  # 输出: Vector(4, 6)

print(len(v3))  # 输出: 10

print(3 in v3)  # 输出: True
print(5 in v3)  # 输出: False

print(bool(v1))  # 输出: True
print(bool(Vector(0, 0)))  # 输出: False

魔术方法:对象的属性管理

# __getattr__、__setattr__、__delattr__
class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age
    
    def __getattr__(self, name):
        print(f"Getting attribute '{name}'")
        raise AttributeError(f"'Person' object has no attribute '{name}'")
    
    def __setattr__(self, name, value):
        print(f"Setting attribute '{name}' to '{value}'")
        super().__setattr__(name, value)
    
    def __delattr__(self, name):
        print(f"Deleting attribute '{name}'")
        super().__delattr__(name)

p = Person("Alice", 30)
print(p.age)  # 输出: 30
p.age = 31  # 输出: Setting attribute 'age' to '31'
del p.age  # 输出: Deleting attribute 'age'
print(p.address)  # 输出: Getting attribute 'address',抛出 AttributeError

魔术方法:对象的索引管理

# __getitem__、__setitem__、__delitem__
class MySequence:
    def __init__(self, *args):
        self.data = list(args)
    
    def __repr__(self):
        return repr(self.data)
    
    def __getitem__(self, index):
        return self.data[index]
    
    def __setitem__(self, index, value):
        self.data[index] = value
    
    def __delitem__(self, index):
        del self.data[index]
    
    def __len__(self):
        return len(self.data)
    
    def append(self, value):
        self.data.append(value)
    
    def insert(self, index, value):
        self.data.insert(index, value)
    
    def pop(self, index=-1):
        return self.data.pop(index)

seq = MySequence(1, 2, 3, 4, 5)
print(seq[2])  # 输出: 3
seq[1] = 10
print(seq)  # 输出: [1, 10, 3, 4, 5]
del seq[3]
print(seq)  # 输出: [1, 10, 3, 5]
seq.append(6)
print(seq)  # 输出: [1, 10, 3, 5, 6]
print(len(seq))  # 输出: 5

魔术方法:with语句上下文管理器

# __enter__、__exit__
class DatabaseConnection:
    def __enter__(self):
        print("数据库连接已打开")
        # 这里可以添加打开数据库的代码
        return self
    
    def __exit__(self, exc_type, exc_value, traceback):
        print("数据库连接已关闭")
        # 这里可以添加关闭数据库的代码
        if exc_type is None:
            return False

with DatabaseConnection() as db:
    print(f"正在使用数据库: {db}")

魔术方法:对象的迭代

# __iter__、__next__
class Person:
    def __init__(self, name, age, city):
        self.attributes = {'name': name, 'age': age, 'city': city}
        self.keys = iter(self.attributes)
    
    def __iter__(self):
        return self
    
    def __next__(self):
        key = next(self.keys)
        return key, self.attributes[key]

person = Person('Alice', 30, 'New York')
for attr, value in person:
    print(f'{attr}: {value}')

魔术方法:允许对象像函数一样被调用

# __call__
class Counter:
    def __init__(self):
        self.count = 0
    
    def __call__(self):
        self.count += 1
        return self.count

counter = Counter()
print(counter())  # 输出: 1
print(counter())  # 输出: 2
print(counter())  # 输出: 3

contextmanager上下文管理器

from contextlib import contextmanager

class DatabaseConnection:
    def __init__(self):
        self.connected = False

    def connect(self):
        self.connected = True
        print("Database connected")

    def disconnect(self):
        self.connected = False
        print("Database disconnected")

@contextmanager
def manage_db_connection():
    db = DatabaseConnection()
    db.connect()
    try:
        yield db
    finally:
        db.disconnect()

with manage_db_connection() as db:
    print(f'Using database: {db.connected}')

property定义属性

class C:
    def __init__(self):
        self._x = None
 
    @property
    def x(self):
        """I'm the 'x' property."""
        return self._x
 
    @x.setter
    def x(self, value):
        self._x = value
 
    @x.deleter
    def x(self):
        del self._x
 
# 使用例子
c = C()
c.x = 10
print(c.x)  # 输出: 10
del c.x
try:
    print(c.x)
except AttributeError as e:
    print(e)  # 输出: 'C' object has no attribute '_x'

类方法和静态方法

class MyClass:
    '''
    类方法接收类作为它的第一个参数,通常以cls作为前缀。静态方法则不接受任何特殊参数,可以看作是全局函数。     这两种方法都可以通过类直接调用,无需创建类的实例。
    '''
    @classmethod
    def class_method(cls):
        print(f"This is a class method. Class: {cls.__name__}")
 
    @staticmethod
    def static_method():
        print("This is a static method.")
 
MyClass.class_method()  # 不需要实例化
MyClass.static_method()  # 同样不需要实例化

描述符协议

class MyDescriptor:
    def __init__(self, name):
        self.name = name
 
    def __get__(self, instance, owner):
        print(f"Getting {self.name}")
        return instance.__dict__[self.name]
 
    def __set__(self, instance, value):
        print(f"Setting {self.name}")
        instance.__dict__[self.name] = value
 
    def __delete__(self, instance):
        print(f"Deleting {self.name}")
        instance.__dict__.pop(self.name)
 
class MyClass:
    x = MyDescriptor('x')

obj = MyClass()
obj.x = 10  # 触发 __set__,输出 :Setting x
print(obj.x)  # 触发 __get__,输出 :Getting x   10
del obj.x  # 触发 __delete__,输出 :Deleting x

类装饰器

def decorator(cls):
    """
    # 定义了一个装饰器函数 decorator,它接受一个类作为参数,并返回一个新的被装饰过的子类。
    # 当这个装饰器被应用到 MyClass 类上时,它会创建一个新的继承自 MyClass 的内部类 DecoratedClass,     # 并且在其 __init__ 方法中打印一条消息。
    # 这展示了如何在不修改原始类定义的情况下,给类添加额外的初始化行为。
    """
    class DecoratedClass(cls):
        def __init__(self, *args, **kwargs):
            super().__init__(*args, **kwargs)
            print("类已被装饰器装饰。")
    return DecoratedClass
 
@decorator  # 等同于 MyClass = decorator(MyClass)
class MyClass:
    def __init__(self):
        print("类初始化。")

my_object = MyClass()

__init_subclass__函数

class A:
    def __init_subclass__(cls, **kwargs):
        super().__init_subclass__(**kwargs)
        # 这里可以添加更多的初始化子类的代码
        print(f"初始化了子类: {cls.__name__}")
 
# 使用 A 作为基类创建子类时,会自动调用 __init_subclass__ 方法
class B(A):
    pass
 
# 输出: 初始化了子类: B

元类

# 给所有的子类对象增加一个作者的属性
class MetaClass(type):  
    def __new__(mcls, name, bases, attrs):  
        # 在这里,我们给类添加一个author属性  
        attrs["author"]= "John Doe"
        return type.__new__(mcls, name, bases, attrs)  
  
class AuthorizedClass(metaclass=MetaClass):  
    pass  
  
class SubClass(AuthorizedClass):  
    pass  

s = SubClass()
print(s.author)  # 输出: John Doe
#############################################

class MetaClass(type):  
    def __init__(cls, name, bases, attrs):  
        # 在这里,我们给类添加一个author属性  
        cls.author= "John Doe"
        return type.__init__(cls, name, bases, attrs)  
  
class AuthorizedClass(metaclass=MetaClass):  
    pass  
  
class SubClass(AuthorizedClass):  
    pass  

s = SubClass()
print(s.author)

# 规范类名
class MetaClass(type):  
    def __init__(cls, name, bases, attrs):  
        if not name.istitle():
            raise TypeError("类名称不符合规范")
        return type.__init__(cls, name, bases, attrs)  
  
 
class Subclass(metaclass=MetaClass):    # 正常创建
    pass
class SubClass(metaclass=MetaClass):    # 发生异常
    pass

# 只支持关键字传参
class MetaClass(type):  
    def __call__(cls, *args, **kwargs):  
        if args:
            raise TypeError("只支持关键字参数")
        return type.__call__(cls, *args, **kwargs)  
 
class SubClass(metaclass=MetaClass):  
    def __init__(self, name):
        self.name = name

s = SubClass(name="John")   # 正常创建
s = SubClass("John")   # 发生异常

# 类禁止被实例化
class MetaClass(type):  
    def __call__(cls, *args, **kwargs):  
        raise TypeError("该类不允许直接实例化对象")

class SubClass(metaclass=MetaClass):
    pass
c = SubClass()   # 发生异常

# 只允许实例化一个对象
class MetaClass(type):  
    def __init__(cls, name, bases, attrs):  
        cls.__instance = None
        return type.__init__(cls, name, bases, attrs)
    def __call__(cls, *args, **kwargs):  
        if cls.__instance is None:
            cls.__instance = type.__call__(cls, *args, **kwargs)
            return cls.__instance
        else:
            return cls.__instance

class SubClass(metaclass=MetaClass):
    pass
c1 = SubClass()
c2 = SubClass()
c1 is c2    # 输出:True
print(dir(SubClass))

抽象基类

import abc
 
class AbstractClass(metaclass=abc.ABCMeta):
    @abc.abstractmethod
    def abstract_method(self):
        pass
 
    @abc.abstractmethod
    def another_abstract_method(self):
        pass
 
# 下面的代码将会抛出错误,因为ConcreteClass没有实现所有的抽象方法
# concrete_instance = AbstractClass()
 
class ConcreteClass(AbstractClass):
    def abstract_method(self):
        print('实现了abstract_method方法')
 
    def another_abstract_method(self):
        print('实现了another_abstract_method方法')
 
# 这样就可以正常创建实例了
concrete_instance = ConcreteClass()
posted @ 2024-06-23 14:39  wanghongwei-dev  阅读(10)  评论(0编辑  收藏  举报