【问题标题】:Python 3: Using OOP to change Class to Integer on Conditional StatementPython 3:在条件语句中使用 OOP 将类更改为整数
【发布时间】:2018-02-28 20:36:00
【问题描述】:

为不正确的术语道歉,我还是新手。

我想创建一个类初始化器,它使用条件来决定所述类的实例是否会折叠成一个简单的整数。

简化的无效示例:

class A(object): 
    def __init__(self,a,b):
        self.a = a
        self.b = b
        if self.b == 0:
            return int(a)
    def __repr__(self):
        return str(a)+":"+str(b)

DoesntBecomeAnInt = A(3,4)
WillBecomeAnInt = A(3,0)
print(DoesntBecomeAnInt,WillBecomeAnInt)

##Desired Output:
##3:4, 3

任何帮助将不胜感激!

【问题讨论】:

    标签: python python-3.x class oop


    【解决方案1】:

    使用数据类

    # A(...) should either raise an exception or 
    # return an instance of A to avoid confusion. 
    # create can do whatever you want it to.
    
    import dataclasses 
    
    @dataclasses.dataclass
    class A:
        print('Initializing')
        a : int
        b : int
                   
        def __repr__(self):
            if self.b == 0:
                return str(int(self.a))
            else:
                return str(self.a) + ":" + str(self.b)
    
        @classmethod
        def create(cls, a, b):
            if b == 0:
                return a
            return cls(a, b)
    
    DoesntBecomeAnInt = A.create(3,4)
    WillBecomeAnInt = A.create(3,0)
    print(f'{DoesntBecomeAnInt}\n{WillBecomeAnInt}')
    
    Initializing
    3:4
    3
    
    [Program finished]
    

    【讨论】:

      【解决方案2】:

      您应该为此使用魔术方法__new____new__ 用作工厂,您可以在其中决定应实例化哪个类。

      class A(object):
          def __new__(self, a):
              return int(a)
      
      A(4)
      > 4
      A(4).__class__
      > <type 'int'>
      

      【讨论】:

      • __new__ 这里也需要b
      • 这很奇怪,让理解调用者的行为变得更加困难。 -1
      【解决方案3】:

      你没有。

      你想要的行为完全出乎意料,而且有些奇怪。调用A() 预计会返回A 的实例。做任何其他事情都是令人困惑和不直观的,这使得阅读和理解任何调用它的代码都很困难。

      另类

      如果你真的需要这种行为,创建一个工厂方法:

      def make_thing(a, b):
          if 0 == b:
              return int(a)
          else:
              return A(a, b)
      

      显然,你需要一个比make_thing 更好的名字,但是没有任何上下文,我无法给你任何建议。

      尽可能避免这个问题

      由于A 不是数字并且通常与int 不兼容,因此将intA 存储在同一个变量中也有些奇怪。

      如果您所做的只是转换为字符串,那么您根本不需要类。类之外的简单方法是更好的选择:

      def a_and_b_to_string(a, b):
          if b == 0:
              return str(int(a))
          else:
              return str(a) + ":" + str(b)
      

      如果你做的不止这些,你的调用代码最终可能会是这样的:

      x = make_thing(input1, input2)
      if isinstance(x, A):
          result = x.some_method_from_a() # Or some other calculation requiring an A
      else:
          result = 5 * x # Or some other calculation requiring an `int`
      

      这有点愚蠢:您编写一个方法来选择数据类型,然后必须为每个可能的结果编写专门的代码。您没有从这里返回单独类型的函数中获得任何好处。我可以想到两个更简单的选择:

      1. 只需将检查移至调用代码即可:

        if input2 == 0:
            temp = A(input1, input2)
            result = temp.some_method_from_a() # Or some other calculation requiring an A
        else:
            result = 5 * int(input1) # Or some other calculation requiring an int
        

        如果你走这条路,你还应该修改A.__init__,如果b == 0,则抛出ValueError,因为这对于A来说是无效的状态。

      2. 修改A,使其无论b是否为0都能正常工作:

        class A(object):
            def __init__(self,a,b):
                self.a = a
                self.b = b
        
            def some_method_from_a():
                if self.b == 0:
                    # Some calculation involving only a
                    return int(self.a) * 5
                else:
                    # Some other more complex calculation involving both a and b
                    return self.a * self.b * 6
        
            def __repr__(self):
                if self.b == 0:
                    return str(int(self.a))
                else:
                    return str(self.a) + ":" + str(self.b)
        

        然后

        x = A(a, b)
        result = x.some_method_from_a()
        

      但是,在不知道您实际使用它的情况下很难提供建议。

      【讨论】:

        【解决方案4】:
        class A:
            def __new__(cls, a, b):
                if b == 0:
                    return a
                return super().__new__(cls)
            def __init__(self, a, b):
                print('Initilizing')
                self.a = a
                self.b = b
            def __repr__(self):
                return str(self.a)+":"+str(self.b)
        

        __new__ 是用于控制新对象创建的方法(因此得名)。在这里,我们检查b__new__ 中是否为零,并返回适当类型的实例。

        在行动:

        >>> DoesntBecomeAnInt = A(3,4)
        Initilizing
        >>> WillBecomeAnInt = A(3,0)
        >>> print(DoesntBecomeAnInt,WillBecomeAnInt)
        3:4 3
        

        【讨论】:

        • 这是完美的。谢谢!
        • 这很奇怪,让理解调用者的行为变得更加困难。 -1
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2021-08-27
        • 1970-01-01
        • 2021-12-09
        • 2012-09-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多