实现描述符来验证参数

问题描述 投票:0回答:2

所以我的任务是:

*您必须实现具有价格、作者和名称属性的 Book 类。

作者和姓名字段必须是不可变的; 价格字段可能会发生变化,但必须在 0 <= price <= 100 range. If a user tries to change the author or name fields after an initialization or set price is out of range, the ValueError should be raised.

实现描述符 PriceControl 和 NameControl 来验证参数。*

示例:


>>> b = Book("William Faulkner", "The Sound and the Fury", 12)
>>> print(f"Author='{b.author}', Name='{b.name}', Price='{b.price}'")
Author='William Faulkner', Name='The Sound and the Fury', Price='12'

>>> b.price = 55
>>> b.price
55
>>> b.price = -12  # => ValueError: Price must be between 0 and 100.
>>> b.price = 101  # => ValueError: Price must be between 0 and 100.

>>> b.author = "new author"  # => ValueError: Author can not be changed.
>>> b.name = "new name"      # => ValueError: Name can not be changed.

我的决定是:

class PriceControl:
    """
    Descriptor which don't allow to set price
    less than 0 and more than 100 included.
    """
    def __init__(self):
        self.price = 0

    def __get__(self, instance, owner):
        return self.price
    def __set__(self, instance, value):
        if value < 0 or value > 100:
            raise ValueError('Price must be between 0 and 100.')
        self.price = value

class NameControl:
    """
    Descriptor which don't allow to change field value after initialization.
    """
    pass

class Book:
    author = NameControl()
    name = NameControl()
    price = PriceControl()
    def __init__(self, author, name, price):
        self.author = author
        self.name = name
        self.price = price

因此,正如您所看到的,我实现了价格控制的解决方案,但我无法想象如何为作者/名称控制创建描述符。你能帮我吗?


python python-3.x oop methods descriptor
2个回答
0
投票

描述符不提供自动方式来精确地进行“一个”分配;您仍然需要定义一个 setter 来确定分配是否已经发生。 请注意,在这两种情况下,您应该将值附加到作为参数接收的

instance

,而不是描述符本身,否则

Book
的所有实例将共享相同的名称、作者和价格。
# Hard-coded assumption that PriceControl will operate on
# an attribute named _price; see NameControl for a way to
# derive an attribute name from the name of the descriptor itself.
class PriceControl:
    """
    Descriptor which don't allow to set price
    less than 0 and more than 100 included.
    """

    def __get__(self, instance, owner):
        return instance._price

    def __set__(self, instance, value):
        if value < 0 or value > 100:
            raise ValueError('Price must be between 0 and 100.')
        instance._price = value


class NameControl:
   # This method is invoked at class creation time,
   # with the name of the class attribute bound to the
   # descriptor instance passed as the 'name' argument.
   # I.e.,
   #
   #     class Book:
   #         author = NameControl()
   #
   # causes 
   #
   #     Book.author.__set_name__('author')
   #
   # to be called.
   def __set_name__(self, name):
       self.public_name = name
       self.private_name = "_" + name

   def __get__(self, instance, owner):
       return getattr(instance, self.private_name)

   def __set__(self, instance, value):

       # TODO: check if instance already has the private
       # instance attribute set below.

       setattr(instance, self.private_name, value)

(您可能需要修改两个 
__get__

方法以在

__set__
有机会创建底层实例属性之前处理它们的调用。)
    


-1
投票

© www.soinside.com 2019 - 2024. All rights reserved.