0

Sometimes in __init__ I already have the instance that self is supposed to become, and I simply want to set it to that.
The simplest case is that the argument used to initialize a Foo is itself a Foo.
(Foo(Foo(x)) == Foo(x) just like set({1, 2}) == {1, 2}.)
In the example this is case_trivial. But there is also case_variadic.

Currently I have to set each attribute on its own. Is there a way to do that in one line?

from variadic_foo_operations import foo_addition, foo_multiplication


class Foo(object):

    def __init__(self, arg=None, addends=None, factors=None):

        case_arg = arg is not None
        case_normal = case_arg and type(arg) == int
        case_trivial = case_arg and type(arg) == Foo

        case_add = addends is not None
        case_multiply = factors is not None
        case_variadic = case_add or case_multiply

        if case_normal:
            self.bar = arg
            self.double_bar = 2 * arg
        elif case_trivial:
            the_foo_i_want = arg
        elif case_variadic:
            operation = foo_addition if case_add else foo_multiplication
            operands = addends if case_add else factors
            current_foo = Foo(0) if case_add else Foo(1)  # neutral element
            for operand_foo in operands:
                current_foo = operation(current_foo, operand_foo)
            the_foo_i_want = current_foo

        if case_trivial or case_variadic:
            # What I would like:
            self = the_foo_i_want
            # What I have to do instead:
            self.bar = the_foo_i_want.bar
            self.double_bar = the_foo_i_want.double_bar
jonrsharpe
  • 115,751
  • 26
  • 228
  • 437
Watchduck
  • 1,076
  • 1
  • 9
  • 29
  • 1
    No, by the time `__init__` gets called Python has already created the new instance - `self` is just a method parameter at that point, assigning to it doesn't have any impact outside the method. Maybe you want to override `__new__` instead? – jonrsharpe Jul 19 '20 at 14:55
  • It sounds like you want a copy constructor, but Python doesn't provide anything similar out of the box. As a note, I think this method does too much disparate work. I'd suggest leaving just initialisation in your `__init__` and introducing auxiliary functions that implement the calculation. So you'd have something like `def new_foo_add(addends): ...; return Foo(bar=..., ...)`. Also, `type(arg) == Foo` is going to break if you ever inherit from Foo. – Norrius Jul 19 '20 at 15:07
  • @Norrius If `addends` is one one of the ways to initialize `Foo`, then `__init__` is the place where I have it. How would you get it to that auxiliary function? – Watchduck Jul 19 '20 at 19:16

1 Answers1

0

Found the answer here: How to copy all properties of an object to another object

self.__dict__ = the_foo_i_want.__dict__.copy()
Watchduck
  • 1,076
  • 1
  • 9
  • 29