开发者

The same method for class and instance

开发者 https://www.devze.com 2023-04-12 12:49 出处:网络
I have class Books and method 开发者_开发知识库select in it. Also there is an instance of that class called book. I want to be able to do both Books.select(where=\'...\') and book.select(where=\'...\'

I have class Books and method 开发者_开发知识库select in it. Also there is an instance of that class called book. I want to be able to do both Books.select(where='...') and book.select(where='...'):

class Books():
    def select(obj, where):
        print(obj, where)

book = Books()
Books.select(where='asdf')
book.select(where='asdf')

The above obviously doesn't work, because select is an instance bound method:

Traceback (most recent call last):
  File "test.py", line 7, in <module>
    Books.select(where='asdf')
TypeError: select() takes exactly 2 arguments (1 given)

A working code:

class Books():
    @staticmethod
    def select(obj, where):
        print(obj, where)

book = Books()
Books.select(Books, where='asdf')
Books.select(book, where='asdf')

And i get:

vic@wic:~/projects/snippets$ python3 test.py 
<class '__main__.Books'> asdf
<__main__.Books object at 0x17fd6d0> asdf

But i have to manually pass the class or its instance as the first argument to the select method - not what i want.

If i make select a class method:

class Books():
    @classmethod
    def select(obj, where):
        print(obj, where)

book = Books()
Books.select(where='asdf')
book.select(where='asdf')

I always get a class as the first argument:

vic@wic:~/projects/snippets$ python3 test.py 
<class '__main__.Books'> asdf
<class '__main__.Books'> asdf

But i want to get an instance in the second case.

So, is there a way to accomplish what i want without manually passing the class/instance as the first argument to a static method?


You could use a descriptor:

class Select(object):
    def __get__(self,obj,objtype):
        x=objtype if obj is None else obj
        def select(where):
            print(x,where)
        return select
class Books(object):
    select=Select()

book = Books()
Books.select(where='asdf')
book.select(where='asdf')

yields

<class '__main__.Books'> asdf
<__main__.Books object at 0xb7696dec> asdf


Solution using a descriptor and a decorator:

class class_or_instance_method():
    def __init__(self, method):
        self.method = method

    def __get__(self, obj, objtype):
        x = obj or objtype
        def wrapped(*args, **kwargs):
            return self.method(x, *args, **kwargs)
        return wrapped        

class Books():
    @class_or_instance_method
    def select(obj, where):
        print(obj, where)


book = Books()
Books.select(where='asdf')
book.select(where='asdf')

Result:

<class '__main__.Books'> asdf
<__main__.Books object at 0x2695890> asdf


Just an example I founded on http://code.activestate.com/recipes/52304-static-methods-aka-class-methods-in-python/

You create a little wrapper:

class Callable:
    def __init__(self, anycallable):
        self.__call__ = anycallable

And then defines your class and a class variable inside it.

class Class2:
    def static2(name):
        print "Hi there",name
    static2 = Callable(static2)

# now, a call such as:
Class2.static2("Peter")
# works just fine, and as-expected
0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号