0

I have a class db defined like so:

class db:

    def __init_(self, idx, host, port, db_name, user, password):
        self.idx = idx
        ...

    def Connect(self):
        conn = db_engine.connect(host=self.host, ...)

    @staticmethod
    def Connect(idx):
        if idx == 1:
            d = db(1, "localhost", 80, ...)
            conn = d.Connect()
        return conn

So, as you can see, my class has two methods. Most importantly it has a static method Connect which internally tries to call a non-static method Connect. However, when I try to use my program, I get an error message:

d.Connect()

TypeError: Connect() missing 1 required positional argument ...

It seems like the static method tries to call itself, however I want to make it call another non-static method. So, what am I doing wrong?

Community
  • 1
  • 1
Jacobian
  • 10,122
  • 29
  • 128
  • 221

1 Answers1

3

You redefined the Count method. Python doesn't support overloading; you cannot define both a regular method and a static method. You only have the staticmethod version because it was defined last, it replaced the non-static version altogether.

If you need a method that alters its behaviour based on wether or not it is bound (static vs. a regular method) you have two options; either test the type of the self argument (it'll be an integer or an instance of the db class), or you'll have to build a custom descriptor object that can alter how your method is called based on the context; on an instance or on the class.

Testing the type of self looks like this:

class db:
    def __init_(self, idx, host, port, db_name, user, password):
        self.idx = idx
        # ...

    def Connect(self_or_idx):
        if isinstance(self_or_idx, db):
            self = self_or_idx
            conn = db_engine.connect(host=self.host, ...)
            # ...
        else:
            idx = self_or_idx
            if idx == 1:
                d = db(1, "localhost", 80, ...)
                conn = d.Connect()
            return conn

If using a custom descriptor, you could build one that supports two different functions like the property object does:

class static_or_instance_method(object):
    def __init__(self, instancemethod=None, staticmethod=None):
        self.method = instancemethod
        self.static = staticmethod

    def staticmethod(self, staticmethod):
        return type(self)(self.method, staticmethod)

    def instancemethod(self, instancemethod):
        return type(self)(instancemethod, self.static)

    def __get__(self, instance, cls=None):
        if instance is None:
            return self.static
        return self.method.__get__(instance, cls)

then use it like this:

class db:
    def __init_(self, idx, host, port, db_name, user, password):
        self.idx = idx
        # ...

    @static_or_instance_method
    def Connect(self):
        conn = db_engine.connect(host=self.host, ...)
        # ...

    @Connect.staticmethod
    def Connect(idx):
        if idx == 1:
            d = db(1, "localhost", 80, ...)
            conn = d.Connect()
        return conn

Quick demo of the descriptor:

>>> class Foo:
...     @static_or_instance_method
...     def bar(self):
...         return 'Bound method of {}'.format(self)
...     @bar.staticmethod
...     def bar(arg):
...         return 'Static method, receiving argument {}'.format(arg)
... 
>>> Foo().bar()
'Bound method of <__main__.Foo object at 0x10b6cf588>'
>>> Foo.bar('spam')
'Static method, receiving argument spam'
Community
  • 1
  • 1
Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
  • BTW. There is a small error. In `else` block `d` should be returned, not `conn` – Jacobian Oct 08 '15 at 20:38
  • @Jacobian: I based this directly on your own `staticmethod` code in your question. Besides, for the problem at hand (how to handle calling the method on the class or on an instance) it hardly matters what exactly is returned here. :-) – Martijn Pieters Oct 08 '15 at 21:11