Python Don';如果类实例作为初始化参数传递,则不会中断
我试图为一个Python Don';如果类实例作为初始化参数传递,则不会中断,python,class,Python,Class,我试图为一个python类增加灵活性,以便它注意到init参数之一已经是该类的实例。如果你不介意的话,跳过“初始情况”,我是怎么来的 初始情况 我有这门课: class Pet: def __init__(self, animal): self._animal = animal @property def present(self): return "This pet is a " + self._animal
python
类增加灵活性,以便它注意到init参数之一已经是该类的实例。如果你不介意的话,跳过“初始情况”,我是怎么来的
初始情况
我有这门课:
class Pet:
def __init__(self, animal):
self._animal = animal
@property
def present(self):
return "This pet is a " + self._animal
...
还有许多函数接受这个类的实例作为参数(def(pet,…)
)。一切如期进行
然后,我想为这些函数的使用增加一些灵活性:如果调用方传递一个Pet
实例,那么一切都会像以前一样工作。在所有其他情况下,将创建一个Pet
实例。实现这一目标的一种方法是:
def f(pet_or_animal, ...):
if isinstance(pet_or_animal, Pet): #Pet instance was passed
pet = pet_or_animal
else: #animal string was passed
pet = Pet(pet_or_animal)
...
这也可以像预期的那样工作,但是这些行在每个函数中都是重复的。不干,不好
目标
因此,我想从每个函数中提取if
/else
,并将其集成到Pet类本身中。我尝试将其\uuuuu init\uuuu
方法更改为
class PetA: #I've changed the name to facilitate discussion here.
def __init__(self, pet_or_animal):
if isinstance(pet_or_animal, PetA):
self = pet_or_animal
else:
self._animal = pet_or_animal
...
并以
def f(pet_or_animal, ...):
pet = PetA(pet_or_animal)
...
然而,这是行不通的。如果传递了一个Pet实例,则一切正常,但如果调用了字符串,则不会正确创建Pet实例
当前(丑陋的)解决方案
有效的方法是向类中添加一个类方法,如下所示:
class PetB: #I've changed the name to facilitate discussion here.
@classmethod
def init(cls, pet_or_animal):
if isinstance(pet_or_animal, PetB):
return pet_or_animal
else:
return cls(pet_or_animal)
def __init__(self, animal):
self._animal = animal
...
并将功能更改为
def f(pet_or_animal, ...):
pet = PetB.init(pet_or_animal) #ugly
...
问题
- 有人知道如何更改类
以使其具有预期的行为吗?可以肯定的是,以下是快速测试:PetA
- 更一般地说,这是增加这种灵活性的正确方法吗?我考虑过的另一个选择是编写一个单独的函数来进行检查,但这也很难看,而且是另一件需要跟踪的事情。我宁愿把每件事都收拾得干干净净,并把它放在课堂上
- 最后一句话:我意识到有些人可能会发现添加的类方法(
)是一个更优雅的解决方案。我喜欢添加到petB
方法(\uuuu init\uuuu
)的原因是,在我的实际使用中,我已经允许许多不同类型的初始化参数。因此,已经有一个petA
/if
/elif
/elif
/。。。语句,检查创建者使用了哪些可能性。我想再扩展一种情况,即,如果传递了一个初始化实例elif
非常感谢您可以使用函数来获得您想要的相同行为:
def make_pet_if_required(pet_or_animal):
if isinstance(pet_or_animal, PetA):
return pet_or_animal
else:
return Pet(pet_or_animal)
然后:
def f(pet_or_animal, ...):
pet = make_pet_if_required(pet_or_animal)
...
要获得更多的“美观”,您可以尝试将该函数调用转换为装饰程序。我相信您当前的“丑陋”解决方案实际上是正确的方法
这将尽可能地提高灵活性,因为它是混乱的。尽管python允许任意类型和值浮动,但您的用户和您自己都会感谢您将其限制在最外层
我认为它是(不需要以这种方式实现)
等等
如果您不知道您的函数是接受对象还是初始值设定项,则这是一种代码气味。看看您是否可以通过用户输入尽可能提前进行处理,并将其标准化。在这种情况下,灵活性不是一种美德。只要接受一个
Pet
实例,如果调用方还没有实例,就让调用方担心创建这样一个实例。谢谢@chepner这是一个考虑它的有用方法感谢您的回答;我已经读过关于这种编码风格的书(来自…类方法的),但我仍然坚持我灵活的方法。我现在已经按照你的建议重构了代码,我认为这确实使代码更加透明和易于管理。因为这个代码是“只为我”的,我仍然可以在不破坏任何东西的情况下对签名进行更改。太棒了!很高兴它帮了一点忙,当事情进展顺利时总是令人满意的
def f(pet_or_animal, ...):
pet = make_pet_if_required(pet_or_animal)
...
class Pet:
@classmethod
def from_animal(cls, ...):
...
@classmethod
def from_pet(cls, ...):
...
@classmethod
def auto(cls, ...):
if is_pet(...):
return cls.from_pet(...)
def __init__(cls, internal_rep):
...