3

Can I use self parameters in my method definition in python?

class Test:

    def __init__(self, path):
        self.path = pathlib.Path(path)

    def lol(self, destination=self.path):
        x = do_stuff(destination)
        return x

I can make def lol(self, destination) and use it this way test_obj.lol(test_obj.path). But is there a way to set default destination arg to self.path? The other way posted below(based on this answers), but can I refactor it somehow and make it more elegant? Maybe there is new solution in python3.+ versions.

def lol(self, destination=None):
    if destination in None:
        destination = self.path
    x = do_stuff(destination)
    return x
Alex
  • 1,221
  • 2
  • 26
  • 42
  • 1
    It's possible to dynamically add an instance method inside the class' `__init__`. There you have access to the instance variables. – a_guest Oct 17 '18 at 11:29
  • @a_guest, but can I use method defined in `__init__` from outside? – Alex Oct 17 '18 at 11:32
  • `def lol(self, destination=self.path):` this declaration already has the default you are looking for. Just pass whatever you want to, to destination if you want it to take any other value. – jar Oct 17 '18 at 11:33
  • 1
    @Alex In addition you need to set it as an instance attribute via `self.lol = lol`. Then you can access it normally. I'll post an example later. – a_guest Oct 17 '18 at 11:34
  • @raj `self.path` does not refer to the parameter `self`. It's not a valid default parameter unless there already exists an object called "self". – molbdnilo Oct 17 '18 at 11:40
  • @a_guest, nice solution, thanks! Maybe add an answer with whole class code. – Alex Oct 17 '18 at 11:45
  • @molbdnilo that is quite true. However I apologize that i am failing to see what you are. He is already instantiating that class, right? In that case shouldn't it be okay? – jar Oct 17 '18 at 11:47
  • 1
    The parameter is evaluated when the function is defined, not when it is called or when the object is created. There is no object called "self" when the function is defined, unless you do something weird like have a global variable of a different type that also has a `path` property. – molbdnilo Oct 17 '18 at 11:49
  • @Alex Since the question has been closed I provided some examples as an [answer to the duplicate question](https://stackoverflow.com/a/52855749/3767239). Let me know what you think. Honestly I would go with `None` as default parameter together with an explicit check at the beginning of the function. That way is perfectly clean and very explicit about your intentions while being concise as well. As shown, some "hacks" are possible, but unless really required, they are an overkill since they obscure the actual intentions and make the code much harder to read / understand / maintain (imho). – a_guest Oct 17 '18 at 13:17
  • @a_guest, great! Thank you! – Alex Oct 17 '18 at 14:18

2 Answers2

2

How I'd refactor the code:

def func_test(self, destination=None):
    return do_stuff(destination or self.path)

The above is the cleanest and riskiest. - a best case scenario where you know the value, and that or fits in perfectly. - otherwise careless to use it.

Otherwise I would opt for:

def func_test(self, destination=None):
    return do_stuff(destination if destination is not None else self.path)

In regards to passing self.property to a function argument; simply no.

Julian Camilleri
  • 2,975
  • 1
  • 25
  • 34
  • 3
    This does not explicitly check for `None`. It will fallback at any false value. This is definitely different than the OP. In addition it is not answering the question (which is about instance variables as default arguments for instance methods). – a_guest Oct 17 '18 at 11:35
  • 3
    Don't use `or` carelessly. What if I pass `destination=''`? – Aran-Fey Oct 17 '18 at 11:42
  • So this will work if `destination` != `False`/`None`/`empty_value`, right? – Alex Oct 17 '18 at 11:50
  • @Alex `or` as noted by others, is quite careless, unless you're absolutely sure about the data type coming in. - `or` will fallback at any false value (meaning '', False, None etc.) - if that's what you need, this is perfect for you. - But as @Aran-Fey said, be attentive of where you use it. :) – Julian Camilleri Oct 17 '18 at 13:11
2

No. This leads to problems, since self.Path will probably change over runtime. But the default arguments are all evaluated at creation time. Therefore destination will always be a static value which might be different to self.Path at any point.

EDIT:

see Why are default arguments evaluated at definition time in Python?

DiCaprio
  • 823
  • 1
  • 7
  • 24