我正努力坚持谷歌的风格指南,从一开始就努力保持一致性。
我目前正在创建一个模块,在这个模块中我有一个类。我想为不同的标准用例提供一些合理的默认值。但是,我想让用户具有覆盖任何默认设置的灵活性。我目前正在做的是提供一个模块作用域的“常量”字典,其中包含默认值(对于不同的用例),在我的类中,构造函数中的参数优先于默认值。
最后,我想确保我们以参数的有效值结束。
我就是这么做的:
MY_DEFAULTS = {"use_case_1": {"x": 1, "y": 2},
"use_case_2": {"x": 4, "y": 3}}
class MyClass:
def __init__(self, use_case = None, x = None, y = None):
self.x = x
self.y = y
if use_case:
if not self.x:
self.x = MY_DEFAULTS[use_case]["x"]
if not self.y:
self.y = MY_DEFAULTS[use_case]["y"]
assert self.x, "no valid values for 'x' provided"
assert self.y, "no valid values for 'y' provided"
def __str__(self):
return "(%s, %s)" % (self.x, self.y)
print(MyClass()) # AssertionError: no valid values for 'x' provided
print(MyClass("use_case_1")) # (1, 2)
print(MyClass("use_case_2", y = 10) # (4, 10)问题
assert似乎也不是最好的选择,它只是一个调试语句,而不是一个验证检查。我在玩弄@property装饰器,在这里我会引发一个异常,以防参数无效,但是对于当前的模式,我希望允许x和y在短时间内不是truthy来正确实现优先级(也就是说,我只想在构造函数的末尾检查truthiness。有什么线索吗?发布于 2020-03-18 14:10:32
通常,如果有多种方法合理地构造对象类型,则可以为备用构造提供S (dict.fromkeys就是一个很好的例子)。请注意,如果用例是有限的,并且是静态定义的,则此方法更适用。
class MyClass:
def __init__(self, x, y):
self.x = x
self.y = y
@classmethod
def make_use_case1(cls, x=1, y=2):
return cls(x,y)
@classmethod
def make_use_case2(cls, x=4, y=3):
return cls(x,y)
def __str__(self):
return "(%s, %s)" % (self.x, self.y) 如果用例中唯一的变化是默认参数,那么每次重写位置参数列表都需要大量开销。相反,我们可以编写一个classmethod来接受用例,并且可选的重写仅作为关键字。
class MyClass:
DEFAULTS_PER_USE_CASE = {
"use_case_1": {"x": 1, "y": 2},
"use_case_2": {"x": 4, "y": 3}
}
@classmethod
def make_from_use_case(cls, usecase, **overrides):
args = {**cls.DEFAULTS_PER_USE_CASE[usecase], **overrides}
return cls(**args)
def __init__(self, x,y):
self.x = x
self.y = y
def __str__(self):
return "(%s, %s)" % (self.x, self.y)
x = MyClass.make_from_use_case("use_case_1", x=5)
print(x)如果您希望从位置上通过这些参数,这将更加困难,但我想这将适合您的需要。
发布于 2020-03-18 14:08:22
Python是一种非常灵活的语言。如果您的代码运行,技术上没有错误的处理方法。然而,如果你想成为"Pythonic",这里有一些提示给你。首先,您不应该使用AssertionError来验证参数的存在或值。如果一个参数没有被传递并且应该在那里,那么您应该引发一个TypeError。如果传递的值不可接受,则应引发ValueError。断言主要用于测试。
当您想要验证参数a中是否存在一个值时,最好执行a is not None,而不是not a。当not a和None、0或其他Falsy值对您同样无效时,您可以执行该操作。但是,当目的是检查值的存在时,0和None并不相同。
关于您的类,我认为一个更好的方法是在类initalization上展开字典的值。如果从函数签名中删除use_case,并按如下方式调用类:
MyClass(**MY_DEFAULTS["use_case_1"])Python将打开嵌套字典的值,并将它们作为关键字参数传递给您的__init__方法。如果不希望这些值是可选的,则删除默认值,如果提供的参数与函数签名不匹配,Python将为您引发一个TypeError。
如果您仍然希望您的参数不是Falsy,也许您应该为参数的可能值提供一个更具体的范围。如果x的类型是int,并且不需要0值,那么应该将x与0进行比较
def __init__(x, y):
if x == 0 or y == 0:
raise ValueError("x or y cannot be 0")发布于 2020-03-18 14:14:36
保留原来的接口,可以使用kwargs读取参数。如果缺少一些,则只在用例匹配的情况下设置默认值。
MY_DEFAULTS = {"use_case_1": {"x": 1, "y": 2},
"use_case_2": {"x": 4, "y": 3}}
class MyClass:
def __init__(self, use_case = None, **kwargs):
for k,v in kwargs.items():
setattr(self,k,v)
if use_case:
for k,v in MY_DEFAULTS[use_case].items():
if k not in kwargs:
setattr(self,k,v)
unassigned = {'x','y'}
unassigned.difference_update(self.__dict__)
if unassigned:
raise TypeError("missing params: {}".format(unassigned))
def __str__(self):
return "(%s, %s)" % (self.x, self.y)
print(MyClass("use_case_1")) # (1, 2)
print(MyClass("use_case_2", y = 10)) # (4, 10)
print(MyClass())执行此操作:
(1, 2)
(4, 10)
Traceback (most recent call last):
File "<string>", line 566, in run_nodebug
File "C:\Users\T0024260\Documents\module1.py", line 22, in <module>
print(MyClass())
File "C:\Users\T0024260\Documents\module1.py", line 15, in __init__
raise TypeError("missing params: {}".format(unassigned))
TypeError: missing params: {'y', 'x'}随着我的类的默认值越来越多,代码变得非常重复,我能做些什么来简化它呢?
此解决方案允许具有许多参数。
https://stackoverflow.com/questions/60741112
复制相似问题