A class method which behaves differently when called as an instance method?

后端 未结 5 1261
忘了有多久
忘了有多久 2021-02-01 17:17

I\'m wondering if it\'s possible to make a method which behaves differently when called as a class method than when called as an instance method.

For example, as a skill

相关标签:
5条回答
  • 2021-02-01 17:34

    I think the larger problem is that you are overloading the name 'bar' on class 'Foo', something python doesn't allow. The second definition of 'bar' clobbers the first definition of 'bar'.

    Try to think of unique names for your classmethod and instance method. i.e.

    @classmethod
    def create(cls, baz):
       ...
    
    def rubber_stamp(self):
       ...
    
    0 讨论(0)
  • 2021-02-01 17:40

    @Unknown What's the difference between your's and this:

    class Foo(object):
    
        def _bar(self, baz):
            print "_bar, baz:", baz
    
        def __init__(self, bar):
            self.bar = self._bar
            self.baz = bar
    
        @classmethod
        def bar(cls, baz):
            print "bar, baz:", baz
    
    In [1]: import foo
    
    In [2]: f = foo.Foo(42)
    
    In [3]: f.bar(1)
    _bar, baz: 1
    
    In [4]: foo.Foo.bar(1)
    bar, baz: 1
    
    In [5]: f.__class__.bar(1)
    bar, baz: 1
    
    0 讨论(0)
  • 2021-02-01 17:47

    Questionably useful Python hacks are my forte.

    from types import *
    
    class Foo(object):
        def __init__(self):
            self.bar = methodize(bar, self)
            self.baz = 999
    
        @classmethod
        def bar(cls, baz):
            return 2 * baz
    
    
    def methodize(func, instance):
        return MethodType(func, instance, instance.__class__)
    
    def bar(self):
        return 4*self.baz
    
    
    >>> Foo.bar(5)
    10
    >>> a=Foo()
    >>> a.bar()
    3996
    
    0 讨论(0)
  • 2021-02-01 17:47

    [edited: use attribute to be a more direct answer; see the helpful comment by John Fouhy]

    You can use a descriptor to do what you want:

    class cls_or_inst_method(object):
        def __init__(self, class_method, instance_method):
            self.class_method = class_method
            self.instance_method = instance_method
    
        def __get__(self, obj, objtype):
            if obj is None:
                return self.class_method
            else:
                return lambda: self.instance_method(obj)
    
    def my_class_method(baz):
        return baz + 1
    
    def my_instance_method(self):
        return self.baz * 2
    
    class Foo(object):
        baz = 10
        bar = cls_or_inst_method(my_class_method, my_instance_method)
    

    Using the above:

    >>> print Foo.bar(5)
    6
    >>> my_foo = Foo()
    >>> print my_foo.bar()
    20
    
    0 讨论(0)
  • 2021-02-01 17:48

    You can reassign your identity method in init with short lambda function:

    class Matrix(object):
        def __init__(self):
            self.identity = lambda s=self:s.__class__.identity(s)
    
            #...whatever initialization code you have...
            self.size = 10        
    
        @classmethod
        def identity(self, other):
            #...always do you matrix calculations on 'other', not 'self'...
            return other.size
    
    
    m = Matrix()
    print m.identity()
    print Matrix.identity(m)
    

    If you're not familiar with lambda, it creates an anonymous function. It's rarely necessary, but it can make your code more concise. The lambda line above could be rewritten:

        def identity(self):
            self.__class__.indentity(self)
        self.identity = identity
    
    0 讨论(0)
提交回复
热议问题