gpt4 book ai didi

python - const-references 的 Pythonic 等价物是什么?

转载 作者:行者123 更新时间:2023-12-04 10:22:39 25 4
gpt4 key购买 nike

关于缺少 const 的争论很多(至少在 SO 上)。 -正确性和缺乏真实性private Python 中的成员。我正在尝试习惯 Pythonic 的思维方式。

假设我想实现一个油箱。它具有容量,可以重新填充,或者可以消耗掉燃料。所以我会按如下方式实现:

class FuelTank:

def __init__(self, capacity):

if capacity < 0:
raise ValueError("Negative capacity")
self._capacity = capacity

self._level = 0.0

@property
def capacity(self):
return self._capacity

@property
def level(self):
return self._level

def consume(self, amount):

if amount > self.level:
raise ValueError("amount higher than tank level")

self._level -= amount


def refill(self, amount):

if amount + self.level > self.capacity:
raise ValueError("overfilling the tank")

self._level += amount

到目前为止,我已经放置了一些级别的 const -我的代码中的正确性:不为 capacity 实现属性 setter 我通知客户 capacity对象构建后无法更改。 (尽管从技术上讲,这总是可以通过直接访问 _capacity 来实现的。)同样,我告诉客户您可以阅读 level。但请使用 consumerefill改变它的方法。

现在,我实现了 Car有一个 FuelTank :
class Car:
def __init__(self, consumption):
self._consumption = consumption
self._tank = FuelTank(60.0)


@property
def consumption(self):
return self._consumption

def run(self, kms):

required_fuel = kms * self._consumption / 100

if required_fuel > self._tank.level:
raise ValueError("Insufficient fuel to drive %f kilometers" %
kms)

self._tank.consume(required_fuel)

def refill_tank(self, amount):

self._tank.refill(amount)

我再次暗示客户端不应该访问 _tank直接地。他唯一能想到的就是 refill_tank .

过了一段时间,我的客户提示说他需要一种方法来知道油箱里还剩下多少燃料。因此,我决定添加第二种方法,称为 tank_level
    def tank_level(self):
return self._tank.level

怕是 tank_capacity很快就会变得有必要,我开始在 Car 中添加包装器方法访问 FuelTank 的所有方法除了 consume .这显然不是一个可扩展的解决方案。所以,我也可以添加以下 @propertyCar
    @property
def tank(self):
return self._tank

但是现在客户无法理解 consume方法不应该被调用。事实上,这个实现只比制作 tank 稍微安全一点。公共(public)属性:
    def __init__(self, consumption):
self._consumption = consumption
self.tank = FuelTank(60.0)

并节省额外的代码行。

所以,总而言之,我有三个选择:
  • Car 中编写包装方法对于FuelTank 的每种方法Car 的客户允许使用(不可扩展且难以维护)。
  • 保管_tank (名义上)私有(private)并允许客户端将其作为 getter-only 属性访问。这只能保护我免受可能尝试设置 tank 的过度“白痴”客户端的影响。到一个完全不同的对象。但是,否则不如制作tank上市。
  • 制作 tank公开,并询问客户“请不要调用Car.tank.consume

  • 我想知道哪个选项被认为是 Pythonic 世界中的最佳实践?

    在 C++ 中我会写 levelcapacity方法 constTank类并声明 tank作为 Car 的私有(private)成员与 get_tank()返回 const 的方法-引用 tank .这样,我只需要一个包装方法 refill ,并且我授予客户对任何 const 的完全访问权限 Tank 的成员( future 维护成本为零)。就口味而言,我发现这是 Python 缺乏的一个重要特性。

    澄清。

    我知道在 C++ 中可以实现的东西在 Python 中几乎肯定是不可能实现的(由于它们的根本差异)。我主要想弄清楚的是三种替代方案中的哪一种是最 Pythonic 的?选项(2)比选项(3)有什么特别的优势吗?有没有办法使选项(1)可扩展?

    最佳答案

    由于 Python 没有任何标记方法的标准方法 const ,不可能有一种内置的方式来提供一个限制对它们的访问的值(即对象)。然而,有两个习惯用法可以用来提供类似的东西,它们都通过 Python 的动态属性和反射工具变得更容易。

    如果要设计一个类来支持这个用例,你可以拆分 它的接口(interface):仅提供“真实”类型的读取接口(interface),然后提供一个提供写入接口(interface)并将任何未知调用转发给读取器的包装器:

    class ReadFoo:
    def __init__(self): self._bar=1
    @property
    def bar(self): return self._bar
    class Foo:
    def __init__(self): self._foo=ReadFoo()
    def read(self): return self._foo
    def more(self): self._foo._bar+=1
    def __getattr__(self,n): return getattr(self._foo,n)

    class Big:
    def __init__(self): self._foo=Foo()
    @property
    def foo(self): return self._foo.read()

    请注意 Foo继承 来自 ReadFoo ; Python 和 C++ 的另一个区别是 Python 不能表达 Base &b=derived; ,所以我们必须使用一个单独的对象。它也不能从一个构造:客户端不能认为他们应该这样做以获得写访问权限。

    如果类(class)不是为此而设计的,您可以 反向 包装:
    class ReadList:
    def __init__(self,l): self._list=l
    def __getattr__(self,n):
    if n in ("append","extend","pop",…):
    raise AttributeError("method would mutate: "+n)
    return getattr(self._list,n)

    这显然是更多的工作,因为您必须制作 完整黑名单(或白名单,虽然这样更难提供有用的错误消息)。但是,如果类(class)是合作的,您可以将此方法与 一起使用。标签 (例如,函数属性)以避免显式列表并具有两个类。

    关于python - const-references 的 Pythonic 等价物是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60778937/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com