Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/346.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python Don';如果类实例作为初始化参数传递,则不会中断_Python_Class - Fatal编程技术网

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):
           ...