【问题标题】:The same method for class and instance类和实例的方法相同
【发布时间】:2011-10-13 07:39:43
【问题描述】:

我有类Books 和方法select。还有一个名为book 的类的实例。我希望能够同时做到Books.select(where='...')book.select(where='...')

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

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

上面显然不行,因为select是实例绑定方法:

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

工作代码:

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

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

我得到:

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

但我必须手动将类或其实例作为第一个参数传递给 select 方法 - 这不是我想要的。

如果我将select 设为类方法:

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

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

我总是得到一个类作为第一个参数:

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

但我想在第二种情况下获得一个实例。

那么,有没有一种方法可以在不手动将类/实例作为第一个参数传递给静态方法的情况下完成我想要的操作?

【问题讨论】:

  • 是的,但你会想自己开枪。
  • :) 感谢您的预测 :) 我认为要走的路是制作自己的装饰器来替换 classmethod
  • 如果你要调用select作为一个静态方法,并且你不打算在方法调用中显式地传递对象,那么当你去打印的时候你会为obj使用什么是吗?
  • 不是装饰器,是描述符。
  • 我不想使用select 作为静态方法——这就是问题所在。如果我使用classmethod 我会丢失实例。如果我不使用classmethodstaticmethod - 我无法从类中调用该方法。

标签: python python-3.x


【解决方案1】:

你可以使用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')

产量

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

【讨论】:

  • 小心obj 是假的,即使它不是None
【解决方案2】:

解决方案使用描述符和装饰器:

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')

结果:

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

【讨论】:

    【解决方案3】:

    只是我在http://code.activestate.com/recipes/52304-static-methods-aka-class-methods-in-python/ 上创建的一个例子

    你创建一个小包装器:

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

    然后在里面定义你的类和一个类变量。

    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
    

    【讨论】:

    • 如果在类上调用,他想将类作为自动参数,如果在实例上调用,则将实例作为自动参数。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-11-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多