4
class IntTuple(tuple):
    def __new__(cls, iterable):
        generator = (x for x in iterable if isinstance(x, int) and x > 0)
        return super().__new__(cls, generator)

Pycharm suggests me to remove the generator which is in the return. Why?

It said: This inspection reports discrepancies between declared parameters and actual arguments, as well as incorrect arguments (e.g. duplicate named arguments) and incorrect argument order. Decorators are analyzed, too.

But its output was what I expected.

Example:

t = IntTuple([1, -1, "abc", 2, [1, 2], 3])

print(t)

output: (1, 2, 3)

I'm new to Python, so I think this may lack of standardization.

How should I improve it?

Olivier Melançon
  • 21,584
  • 4
  • 41
  • 73
AurevoirXavier
  • 2,543
  • 2
  • 17
  • 25

2 Answers2

5

This is not specific to tuple, calling most builtin type's special method leads PyCharm to get confused with type signatures.

str.__new__(str, 'foo') # This will confuse PyCharm even though it is correct

PyCharm resolves tuple.__new__ as being inherited from builtins.object.__new__. This is not the real method used to create a tuple, but it fails to find the correct one (which is not in a .py file since it is written in C).

tuple.__new__

This is most likely a bug and, unfortunately, this is not something you can fix through settings, except by disabling Incorrect call arguments inspection which I do not recommend.

The bottom line is that PyCharm inspection sometimes gives false positives due to having to inspect a dynamically typed language. This is not a surprise and you will sometimes have to ignore inspection errors it raises.

A word on your code

On another note, I want to point out that you might want to cover the case where you create an empty IntTuple in the same way it can be done with tuple.

tuple() # ()

For this you could have a default iterable.

class IntTuple(tuple):
    def __new__(cls, iterable=()):
        generator = (x for x in iterable if isinstance(x, int) and x > 0)
        return super().__new__(cls, generator)

IntTuple() # ()
Olivier Melançon
  • 21,584
  • 4
  • 41
  • 73
  • I'm using other JetBrains product. I think this maybe a bug, but I'm new to python so I can't confirm that it's or not. And I really appreciate your tips. I almost forget to handle the empty tuple. – AurevoirXavier Mar 25 '18 at 05:32
  • 1
    Issue about `str` is [known](https://youtrack.jetbrains.com/issue/PY-26747) – user2235698 Mar 26 '18 at 16:20
-2

It is saying this because tuple's __new__ method accepts parameters __new__(*args, **kwargs).

You probably found documentation that you could construct a tuple instance using tuple(iterable) to pre-fill the tuple with initial values. This iterable is an argument to the __init__ method of the tuple class, not the __new__ method.

I think what you meant to use was __init__ instead of __new__. In Python, the __new__ method is used mostly for metaprogramming. The __init__ method can be seen as the constructor like you would use it in other languages. The __new__ method is used to create an instance of the class, so you'd need to construct an object and return that. You could use __new__ to implement the singleton pattern for instance, by always returning the same static object. The __init__ method just initialises the instance after it's been created, like a normal constructor does.

So you'd be using something like:

class IntTuple(tuple):
    def __init__(self, iterable):
        generator = (x for x in iterable if isinstance(x, int) and x > 0)
        super().__init__(self, generator)
Ghostkeeper
  • 2,830
  • 1
  • 15
  • 27
  • 2
    That does not work, tuple has no `__init__` method so you call `object.__init__` and that takes no argument. In that case, `__new__` is exactly what should be called. – Olivier Melançon Mar 24 '18 at 14:46
  • Please read about subclassing immutable objects: https://stackoverflow.com/a/1565448/5378816 – VPfB Mar 24 '18 at 14:52