【问题标题】:How to use decorator and property to check on class attributes' type and range efficiently?如何使用装饰器和属性有效地检查类属性的类型和范围?
【发布时间】:2025-06-13 00:35:02
【问题描述】:
import math
import random

# === Problem 1

class RectangularRoom(object):
"""
A RectangularRoom represents a rectangular region containing clean or dirty
tiles.

A room has a width and a height and contains (width * height) tiles. Each tile
has some fixed amount of dirt. The tile is considered clean only when the amount
of dirt on this tile is 0.
"""

    def __init__(self, width, height, dirt_amount):
        """
        Initializes a rectangular room with the specified width, height, and 
        dirt_amount on each tile.

        width: an integer > 0
        height: an integer > 0
        dirt_amount: an integer >= 0
        """

        self.width, self.height, self.dirt_amount = width, height, dirt_amount
        tiles = [(w,h) for w in range(width) for h in range(height)]
        self.room = {tile:dirt for tile in tiles for dirt in [dirt_amount]}
        #raise NotImplementedError

    def get_width(self):

        return self._width

    def set_width(self, value):
        if value <= 0 :
            raise ValueError("Must be greater than 0")
        self._width = value

     width = property(get_width,set_width)

    def __str__(self):
        return str((self.room))

到目前为止,这就是我对这个房间对象所做的事情。我正在尝试使高度,dirt_amount 也限制为 int 并且大于零或大于等于零。是否有更简单或更有效的方法来为其他两个属性编写这些约束?

【问题讨论】:

  • 等一下@crystalizeee,这是不是格式错误,或者你没有缩进类下面的函数?
  • 天哪,当我从 IDE 复制粘贴时,它的格式错误。你能忽略这个愚蠢的错误吗?谢谢!

标签: python-3.x decorator


【解决方案1】:
import types
from functools import wraps


def range_check(func):
    code = func.__code__
    allargs = list(code.co_varnames[:code.co_argcount])
    @wraps
    def _decorator(*args, **kargs):
        positionals = allargs[:len(args)]
        for argname, check in func.__annotations__.items():
            if argname in kargs:
                if not check(kargs[argname]):
                    raise TypeError('"%s" check failed' % argname)
            elif argname in positionals:
                pos = positionals.index(argname)
                if not check(args[pos]):
                    raise TypeError('"%s" check failed' % argname)
            else:
                # argument defaulted
                pass
        return func(*args, **kargs)
    return _decorator

def range(ratio):
    return 0 <= ratio and ratio <= 0.5

class Employee:
    def __init__(self, name, age, pay):
        self.name = name
        self.age = age
        self.pay = pay
    @range_check
    def giveRaise(self, ratio: range):
        self.pay *= (1 + ratio)

if __name__ == '__main__':
    alice = Employee('alice', 20, 50000)
    alice.giveRaise(0.1)
    alice.giveRaise(0.6)

这是检查传递给函数的参数的示例代码。
1.在python3中使用__annotations__在函数声明中传递检查函数。
2. 使用 'co_varnames[co_argcount]' 检索参数名称列表。
3. 位置参数总是放在关键字参数之前。

【讨论】:

    最近更新 更多