0
点赞
收藏
分享

微信扫一扫

[2]Python面向对象-【9】属性修饰符

属性修饰符(Property Decorators)是 Python 中一个重要的特性,它可以帮助我们控制类的属性的访问方式。常用的几种属性修饰符:

  1. @property: 用于将方法转换为只读属性。
  2. @<name>.setter: 用于将方法转换为可写属性的赋值方法。
  3. @<name>.deleter: 用于将方法转换为可删除属性的方法。
  4. @abstractmethod: 用于定义抽象方法,必须被子类实现。
  5. @staticmethod: 用于定义静态方法,类和实例都可以调用。
  6. @classmethod: 用于定义类方法,只能被类调用,不能被实例调用。
  7. __slots__: 用于限制类实例能添加的属性。

需要注意的是,属性修饰符只能用于类定义中,不能用于普通函数中。同时,在Python中,属性修饰符是可叠加的,也就是说,一个方法可以同时被多个属性修饰符修饰。

@property

@property修饰符将一个方法转换为只读属性。使用@property修饰符的方法可以像访问属性一样被调用,而无需使用函数调用的方式。下面是一个简单的示例:

class Circle:
    def __init__(self, radius):
        self.radius = radius

    @property
    def diameter(self):
        return self.radius * 2

circle = Circle(5)
print(circle.diameter)  # 输出10

在这个示例中,diameter方法被@property修饰符修饰,因此它可以像访问属性一样被调用,而不需要使用diameter()这样的函数调用。

需要注意的是,@property修饰符只能将一个方法转换为只读属性。如果想要将一个方法转换为可写属性的赋值方法,则需要使用@<name>.setter修饰符。

@.setter

@<name>.setter修饰符用于将一个方法转换为可写属性的赋值方法。其中<name>是属性名。需要注意的是,使用@<name>.setter修饰符时,需要先定义一个同名的只读属性,否则会抛出AttributeError异常。

下面是一个示例,演示了如何使用@<name>.setter修饰符将一个只读属性转换为可写属性的赋值方法:

class Circle:
    def __init__(self, radius):
        self._radius = radius

    @property
    def radius(self):
        return self._radius

    @radius.setter
    def radius(self, value):
        self._radius = value

    @property
    def diameter(self):
        return self._radius * 2

circle = Circle(5)
print(circle.diameter)  # 输出10
circle.radius = 10
print(circle.diameter)  # 输出20

在这个示例中,我们定义了一个名为radius的只读属性,并使用@property修饰符将radius方法转换为只读属性。然后,我们定义了一个名为radius的可写属性的赋值方法,并使用@radius.setter修饰符将其与只读属性关联起来。

现在,我们可以像访问属性一样访问radius属性,以读取或修改对象的半径。例如,在上面的示例中,我们先将对象的半径设置为5,然后将其修改为10,并检查其直径是否正确。

@.deleter

@<name>.deleter修饰符用于在类中定义一个属性的删除方法。这个修饰符是用来定义一个方法,当删除一个实例中的属性时,该方法就会被调用。

下面是一个示例,展示了如何使用@<name>.deleter属性修饰符来定义一个类的属性删除方法:

class MyClass:
    def __init__(self):
        self._name = None

    @property
    def name(self):
        return self._name

    @name.setter
    def name(self, value):
        self._name = value

    @name.deleter
    def name(self):
        del self._name

这个示例中,我们定义了一个MyClass类,该类包含一个name属性,并定义了getter、setter和deleter方法。在@name.deleter修饰符中,我们定义了一个方法,该方法在删除name属性时被调用。

使用@<name>.deleter属性修饰符,可以在类定义中轻松地定义一个属性的删除方法。通过这种方式,我们可以控制属性删除时执行的代码,并确保数据的安全性和一致性。

下面是一个示例,展示了如何使用@<name>.deleter属性修饰符来删除一个类的属性:

obj = MyClass()
obj.name = "John"
print(obj.name)  # Output: John

del obj.name
print(obj.name)  # Output: None

在这个示例中,我们首先创建了一个MyClass类的实例,并将name属性设置为John。然后,我们使用del关键字删除了该属性。这时,@name.deleter方法会被调用,并删除_name属性。最后,我们再次打印name属性的值,发现它已经变成了None。

总之,@<name>.deleter属性修饰符是Python中用于定义属性删除方法的一种方式。使用它,我们可以轻松地控制属性删除时的操作,并确保数据的安全性和一致性。

@abstractmethod

在Python中,抽象基类是一种特殊类型的类,它不能被实例化,只能被继承,并且它定义了一组抽象方法,子类必须实现这些方法。Python提供了abc模块来支持抽象基类的定义和使用。

@abstractmethod是Python中用于定义抽象方法的装饰器。定义一个抽象方法时,需要使用该装饰器标记方法,以指示该方法是抽象的。如果子类没有实现该方法,将会抛出TypeError异常。

下面是一个示例,展示了如何使用@abstractmethod定义抽象方法并如何实现这些抽象方法:

from abc import ABC, abstractmethod

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

    @abstractmethod
    def perimeter(self):
        pass

class Square(Shape):
    def __init__(self, side):
        self.side = side

    def area(self):
        return self.side ** 2

    def perimeter(self):
        return 4 * self.side

s = Square(5)
print("Area:", s.area())
print("Perimeter:", s.perimeter())

在这个示例中,我们定义了一个抽象基类Shape,它定义了两个抽象方法area和perimeter。然后,我们定义了一个名为Square的具体子类,它实现了area和perimeter方法。我们可以实例化Square类并调用它的方法。

如果我们不在子类中实现area和perimeter方法,会得到以下错误:

TypeError: Can't instantiate abstract class Square with abstract methods area, perimeter

这说明我们必须在子类中实现所有抽象方法,否则无法实例化子类。

需要注意的是,抽象基类本身不能被实例化,只能被用作父类来实现多态性。因此,在定义抽象基类时,应该将其子类视为实现它的具体类型,而不是将其视为实例化它的对象类型。

@staticmethod

Python中的@staticmethod属性修饰符用于定义一个静态方法。静态方法是一个不需要类实例化就可以被类直接调用的方法。它可以用来执行与类相关的操作,但不需要访问类的实例。

1、定义静态方法

定义一个静态方法的方式很简单,只需要在方法的前面加上@staticmethod修饰符即可。例如:

class MyClass:
    @staticmethod
    def my_static_method():
        print("This is a static method.")

在上面的例子中,我们定义了一个名为my_static_method()的静态方法。该方法不需要访问类的实例,因此没有self参数。我们可以通过类名直接调用该方法:

MyClass.my_static_method()

2、调用静态方法

调用静态方法与调用实例方法的语法不同。静态方法是直接通过类名调用的,而实例方法需要通过实例调用。下面是一个演示静态方法如何调用的例子:

class MyClass:
    @staticmethod
    def my_static_method():
        print("This is a static method.")

# 调用静态方法
MyClass.my_static_method()

在这个例子中,我们定义了一个名为my_static_method()的静态方法,并使用MyClass.my_static_method()语法调用它。这将打印出"This is a static method."。

3、静态方法与类方法的区别

静态方法与类方法有相似之处,但也有一些重要的区别。静态方法不需要访问类的实例,而类方法需要访问类的实例。另外,类方法接受一个cls参数,该参数引用类本身,而静态方法不接受任何特殊的参数。

下面是一个演示类方法和静态方法之间区别的例子:

class MyClass:
    @classmethod
    def my_class_method(cls):
        print(f"This is a class method of {cls.__name__}")

    @staticmethod
    def my_static_method():
        print("This is a static method.")

MyClass.my_class_method()  # 输出:This is a class method of MyClass
MyClass.my_static_method()  # 输出:This is a static method.

在这个例子中,我们定义了一个名为my_class_method()的类方法和一个名为my_static_method()的静态方法。我们使用MyClass.my_class_method()和MyClass.my_static_method()语法调用它们。

@classmethod

@classmethod修饰符用于定义类方法,类方法可以通过类或类的实例调用。下面来说一下@classmethod属性修饰符的用法和示例。

1、@classmethod属性修饰符的语法

@classmethod是一个属性修饰符,用于定义类方法。@classmethod属性修饰符应该在函数定义之前,放在方法的第一行。@classmethod属性修饰符的语法如下:

class MyClass:
    @classmethod
    def my_class_method(cls, arg1, arg2, ...):
        # function body

在上面的示例中,@classmethod属性修饰符被应用于my_class_method()方法,该方法被定义为一个类方法。

2、@classmethod属性修饰符的作用

类方法是在类级别上运行的方法,可以通过类或类的实例调用。类方法不需要访问实例变量,也不需要创建实例。在类方法中,第一个参数通常是cls(代表类本身),而不是self(代表实例)。

@classmethod属性修饰符用于将普通的方法转换为类方法。它接受一个cls参数,这个参数是类对象本身,并且可以用于访问类变量和调用其他类方法。当您需要在类级别上运行方法时,使用@classmethod属性修饰符。

3、@classmethod属性修饰符的示例

以下示例演示了如何在Python中使用@classmethod属性修饰符:

class Person:
    total_people = 0

    def __init__(self, name):
        self.name = name
        Person.total_people += 1

    @classmethod
    def show_total_people(cls):
        print("Total people:", cls.total_people)

person1 = Person("Alice")
person2 = Person("Bob")

Person.show_total_people()

在上面的示例中,我们定义了一个Person类,该类包含一个total_people类变量和一个show_total_people()类方法。show_total_people()方法使用@classmethod属性修饰符定义,它接受一个cls参数,用于访问类变量total_people。我们创建了两个Person对象,每个对象都会增加total_people计数器的值。然后,我们使用Person类调用show_total_people()方法,以打印总人数。

输出:

Total people: 2

@classmethod属性修饰符用于定义类方法。类方法在类级别上运行,可以通过类或类的实例调用。使用@classmethod属性修饰符可以将普通方法转换为类方法,它接受一个cls参数,该参数是类对象本身,并且可以用于访问类变量和调用其他类方法。

__slots__

在 Python 中,每个对象都会占用一定的内存空间。当我们需要创建大量对象时,这些对象所占用的内存空间可能会影响程序的性能。为了避免这种情况,Python 中提供了一个特殊的类属性 slots,通过设置这个属性,我们可以限制对象的属性,并且减少对象所占用的内存空间。因为,Python 中的每个对象都包含了一些特殊的属性,例如 __class__、__doc__、__dict__ 等。这些属性占用了对象的一定内存空间,但在某些情况下,我们可能并不需要这些属性。此时,我们可以使用 __slots__ 属性来限制对象的属性,并且减少对象所占用的内存空间。

具体来说,__slots__ 属性可以用来限制实例的属性,只有在指定的属性名中出现的属性才能够被赋值和访问。此外,使用 __slots__ 属性还可以防止我们意外地给实例添加新的属性。

下面是 __slots__ 属性的用法:

class MyClass:
    __slots__ = ['attr1', 'attr2']
    
    def __init__(self, val1, val2):
        self.attr1 = val1
        self.attr2 = val2

在上面的例子中,我们使用了 __slots__ 属性来限制 MyClass 实例的属性,只有 attr1 和 attr2 这两个属性可以被赋值和访问。

在使用 __slots__ 属性时,需要注意以下几点:

  1. __slots__ 属性的值必须是一个字符串列表,每个字符串表示一个属性名。
  2. 如果类继承了其他类,则 __slots__ 属性也必须包含所有继承链中的属性名。
  3. 由于 __slots__ 属性限制了实例的属性,因此不再有 __dict__ 属性,也无法使用 setattr() 和 getattr() 等函数对实例进行动态地属性赋值和访问。
  4. __slots__ 属性的使用应该基于实际需要。如果一个类的实例需要存储的属性数量不是很多,使用 __slots__ 属性可能并不会带来太大的性能提升。
  5. __slots__ 属性不能够限制类的静态属性和方法,因此无法减少类的内存占用。

总结

以上列举了Python中属性修饰符的使用方法和注意事项,这些修饰符可以在 Python 类中使用,以实现更加灵活和高效的对象属性管理。通过掌握这些概念和技术,可以提高代码的可读性、可维护性和可重用性,从而加速应用程序开发的进程。

举报

相关推荐

0 条评论