2

Here is an example which creates a point as p=Point(x, y). Assume that I have some array ppp=(x, y) where x and y are numbers and I want to make it of class Point but in the way: p=Point(ppp). I can do either one or another way but not both simultaneously. Is it possible to have both ways?

tshepang
  • 12,111
  • 21
  • 91
  • 136
  • The proposed solution does not work for me. I have: `def __init__(self, x, y = None, z = None): if y is not None and z is not None: self.x, self.y, self.z = x, y, z elif y is not None or z is not None: raise TypeError('Instance may have only 1 or 3 arguments, got 2') else: self.x, self.y, self.z = x` Then I make: `ppp = Point(p)`, where `p = [0.0, 0.0, 0.0]`, and I got: `__new__() takes exactly 4 arguments (2 given)`. It does not matter what are the numbers inside. –  Aug 10 '12 at 12:41
  • The solution of Karol Nowak works. –  Aug 10 '12 at 12:42

5 Answers5

3

There are two different ways to acquire the result, the first is to analyse arguments that you pass to __init__ and in dependence of their quantity and type - choose a decision what are you using to instantiate class.

class Point(object):

    x = 0
    y = 0

    def __init__(self, x, y=None):
       if y is None:
           self.x, self.y = x, x
       else:
           self.x, self.y = x, y

The other decision is to use classmethods as instantiators:

class Point(object):

    x = 0
    y = 0

    @classmethod
    def from_coords(cls, x, y):
       inst = cls()
       inst.x = x
       inst.y = y
       return inst

    @classmethod
    def from_string(cls, x):
       inst = cls()
       inst.x, inst.y = x, x
       return inst

p1 = Point.from_string('1.2 4.6')
p2 = Point.from_coords(1.2, 4.6)
Rostyslav Dzinko
  • 39,424
  • 5
  • 49
  • 62
  • Thank you for your answer. I understand what you mean, and I considered this way. But I did not want to create too many methods, and then call them every time I need to make a Point. The first way is better for me. –  Aug 10 '12 at 10:58
  • The second method is much cleaner. Branching to determine type identity just feels wrong. –  Sep 20 '12 at 18:47
2

If you know that you have a tuple/list while creating the instance, you can do: p = Point(*ppp), where ppp is the tuple.

Karol Nowak
  • 662
  • 3
  • 8
  • 1
    It should: >>> class Point(object): ... def __init__(self, x, y): ... self.x = x ... self.y = y ... >>> coords = [1, 2] >>> p = Point(*coords) >>> p <__main__.Point object at 0x7ff4a6ec> >>> p.x, p.y (1, 2) – Karol Nowak Aug 10 '12 at 12:08
  • 1
    It means "unpack the list/tuple into multiple arguments". And if you have a `dict` `d`, you can use `**d` to unpack it into keyword arguments. – Karol Nowak Aug 10 '12 at 19:04
  • What is the difference between `init__` and `__init__`? If I use `__init__` the code does not work. –  Aug 15 '12 at 09:02
  • @AlexPi: The inital `__` was interpreted as bold markup by the markdown formatting code. The commenter did put them in but did not escape them. `init__` doesn't mean anything. – Martijn Pieters Nov 13 '12 at 11:38
0
class Point:
    def __init__(self, x, y=None):
        if isinstance(x, tuple):
            self.x, self.y = x
         else:
            self.x = x
            self.y = y
Chris Ortner
  • 806
  • 6
  • 11
  • does it work only if the array is tuple? What if I have a list? The second answer is probably better. –  Aug 10 '12 at 10:55
0

Yes:

class Point(object):
    def __init__(self, x, y=None):
        if y is not None:
            self.x, self.y = x, y
        else:
            self.x, self.y = x

    def __str__(self):
        return "{}, {}".format(self.x, self.y)

print Point(1,2)
# 1, 2
print Point((1,2))
# 1, 2
-1

I would guess that your looking for a way to overload your constructor, as is common in statically typed languages such as C++ and Java.

This is not possible in Python. What you can do is provide different keyword argument combinations, something like:

class Point(object):
  def __init__(self, x=None, y=None, r=None, t=None):
    if x is not None and y is not None:
      self.x = x
      self.y = y
    elif r is not None and t is not None:
      # set cartesian coordinates from polar ones

Which you would then use as:

p1 = Point(x=1, y=2)
p2 = Point(r=1, t=3.14)
Nicola Musatti
  • 17,834
  • 2
  • 46
  • 55