17

I want to have a class that I can create subclasses of that has a print function that only prints on a particular condition.

Here's basically what I'm trying to do:

class ClassWithPrintFunctionAndReallyBadName:
    ...
    def print(self, *args):
        if self.condition:
            print(*args)

This works already except for the fact that there are arguments that have to be explicitly stated with the default print function, such as end (example: print('Hello, world!', end='')). How can I make my new class's print function accept arguments such as end='' and pass them to the default print?

Neithan
  • 395
  • 1
  • 4
  • 9

5 Answers5

34

The standard way to pass on all arguments is as @JohnColeman suggested in a comment:

class ClassWithPrintFunctionAndReallyBadName:
    ...
    def print(self, *args, **kwargs):
        if self.condition:
            print(*args, **kwargs)

As parameters, *args receives a tuple of the non-keyword (positional) arguments, and **kwargs is a dictionary of the keyword arguments.

When calling a function with * and **, the former tuple is expanded as if the parameters were passed separately and the latter dictionary is expanded as if they were keyword parameters.

mkrieger1
  • 19,194
  • 5
  • 54
  • 65
Mark Tolonen
  • 166,664
  • 26
  • 169
  • 251
12

I know it looks a bit ugly but works perfectly, if you are using a lot of keyword arguments and only want to build a facade for another method:

def print(self, print_message, end='\n', sep=' ', flush=False, file=None):
    if self.condition:
        print(**{key: value for key, value in locals().items() if key != 'self'})

Although it's a lot of boilerplate, it avoids any duplication of parameter statements.

You might also look into using a decorator to make the conditional part more pythonic. But beware that the decorator checks the condition once prior to the class instantiation.

Andrew Dennison
  • 1,069
  • 11
  • 9
CheradenineZK
  • 149
  • 1
  • 6
  • 3
    `key in self` has false positivies on `s`, `se`, `elf`, etc. variable names, should be just `key != 'self'` in the filter section of dict comprehension – DimG Jul 21 '21 at 06:16
  • Yes, you are right. I overlooked this. Probably had a tuple with more input there, when writing the code in production. – CheradenineZK Jul 21 '21 at 08:23
4

Just duplicate the named arguments for the method signature.

def print(self, *args, end='\n', sep=' ', flush=False, file=None):
    if self.condition:
        print(*args, end=end, sep=sep, flush=flush, file=file)
TigerhawkT3
  • 48,464
  • 6
  • 60
  • 97
  • If someone would tell me what's wrong with this answer to make it deserve a downvote, I would love to fix the issues. – TigerhawkT3 Feb 28 '17 at 03:36
  • Your answer is fine for the problem at hand. It is hard to figure out downvotes at times. – John Coleman Feb 28 '17 at 03:37
  • struck by the random disliker :< I feel like if you dislike something you must make a comment if there are none, otherwise it's as unhelpful as 'my code doesn't work' questions – A. L Feb 28 '17 at 03:44
  • 2
    @TigerhawkT3, compared to the args and kargs solution your anwser is not generalizable. So it is better to show it to the users after those ones. That may be the reason of downvotes. – pembeci Dec 18 '18 at 13:41
2
class List(list):
    def append_twice(self, *args, **kwargs):
        self.append(*args, **kwargs)
        self.append(*args, **kwargs)
l = List()
l.append_twice("Hello")
print(l) # ['Hello', 'Hello']
Steely Wing
  • 16,239
  • 8
  • 58
  • 54
1

Add at the end like this

def print(self, *args, end=''):

If the arguments are dynamic or too many:

 def print(self, *args, **kwargs):
Rami
  • 79
  • 1
  • 7