1

Imagine I have an initializer with optional parameter

def __init__(self, seed = ...):

Now if parameter is not specified I want to provide a default value. But the seed is hard to calculate, so I have a class method that suggests the seed based on some class variables

MyClass.seedFrom(...)

Now how can I call it from that place? If I use self:

def __init__(self, seed = self.__class__.seedFrom(255)):

I definitely don't know what is self at that point. If I use the class name directly (which I hate to do):

def __init__(self, seed = MyClass.seedFrom(255)):

it complains that

name 'MyClass' is not defined

I'm also interested to learn the pythonic way of doing this. And I hope that pythonic way is not hardcoding stuff and making it nil by default and checking it later…

Uko
  • 13,134
  • 6
  • 58
  • 106
  • Yup, it's making it nil by default and checking it later. – Stanislav Shabalin Jan 25 '16 at 18:37
  • 1
    That's absolutely the Pythonic way. Default parameter values are only evaluated once, and at method definition time the class name doesn't exist. You could also consider making the classmethod an alternate constructor. – jonrsharpe Jan 25 '16 at 18:37
  • "I hope that pythonic way is not ... making it nil by default and checking it later" - Do you want the default `seed` to be fixed, or do you want to pick a new one each time? If you want a new one each time, you're stuck with that option. – user2357112 Jan 25 '16 at 18:38
  • 1
    On the other hand, if you want it fixed, define `seedFrom` first and use a default `seed=seedFrom(255)`, with no `self` or `MyClass`. – user2357112 Jan 25 '16 at 18:39
  • I've reopened the question, since I think it's worth considering the case where it is desirable to call `seedFrom` only once, when `__init__` is defined. – chepner Jan 25 '16 at 18:41
  • @chepner, you can close it again, the seed should be idealy dynamic (though in my case it can actually work like user2357112 said) – Uko Jan 25 '16 at 18:44

2 Answers2

2

In case you only need to call seedFrom once, you can do so when __init__ is defined.

class MyClass:

    # Defining seedFrom as a function outside
    # the class is also an option. Defining it
    # as a class method is not, since you still
    # have the problem of not having a class to
    # pass as the first argument when it is time
    # to declare __init__
    @staticmethod
    def seedFrom():
        ...

    def __init__(self, seed=seedFrom()):
        ...
chepner
  • 497,756
  • 71
  • 530
  • 681
  • Good answer. Should note, the staticmethod definition doesn't even take a class parameter (as opposed to classmethod definitions). [per https://docs.python.org/2/library/functions.html#staticmethod ] – F1Rumors Jan 25 '16 at 19:08
  • 1
    My fault. I started defining it as a class method before I realized that would't work, and forgot to remove `cls` from the argument list. – chepner Jan 25 '16 at 19:37
  • Yes, standalone function will work, but what about encapsulation? ;) – Uko Jan 25 '16 at 22:02
0

If you must do this in the init and want the seed method to be on the class, then you can make it a class method, eg as follows:

class SomeClass(object):

    defaultSeed = 255

    @classmethod
    def seedFrom(cls, seed):
        pass # some seed

    def __init__(self, seed=None):
        self.seedFrom(seed if seed is not None else self.defaultSeed)
        # etc
chepner
  • 497,756
  • 71
  • 530
  • 681
F1Rumors
  • 920
  • 9
  • 13
  • @chepner your edit, whilst not incorrect, is not necessarily the intent either. Any 'falsy' seed would have lead to default seeding, whilst now only not supplying a seed or explicitly using None would have that effect. – F1Rumors Jan 25 '16 at 19:02