0

As a toy example below, both of them create the same classes (although one uses Foo.spam() and the other uses Foo.spam to get the value). My question is, what are the criteria to choose one over the other? If the spam needs to be accessed frequently, better to use the second class implementation because of the function overhead? Anything else?

class Foo(object):
    def __init__(self, a):
        self.a = "init"
    @classmethod
    def spam(cls, value=2):
        return value + 1
Foo.spam() # -> 3
Foo.spam(3) #-> 4

class Foo(object):
    spam = 3
    def __init__(self, a):
        self.a = "init"
Foo.spam  #-> 3
Foo.spam = 4
Foo.spam  #-> 4
RNA
  • 146,987
  • 15
  • 52
  • 70
  • Can you provide a clearer use case? Neither example provides a clear enough idea of what you want to achieve, and particularly, the examples have very different behavior regarding future accesses after you pass in the `3`. – user2357112 Jun 09 '14 at 20:05
  • Related: http://stackoverflow.com/questions/2579840/do-you-use-the-get-set-pattern – Robᵩ Jun 09 '14 at 20:07

2 Answers2

3

I don't think either are pythonically correct for what you are trying to accomplish (assign a default value to a class attribute). Why would you not simply do this?

class Foo(object):
    def __init__(self, a = 'init'):
        self.a = a
        self.spam = 2

And then:

>>> a_foo = Foo()
>>> a_foo.spam
2
>>> a_foo.spam = 3
>>> a_foo.spam
3

If you do it via a static class attribute (your second example), you can get very different behavior depending on how you assign/access it:

class Foo(object):
    spam = 2
    def __init__(self, a = 'init'):
        self.a = a

and then:

>>> a_foo1 = Foo()
>>> a_foo2 = Foo()
>>> a_foo1.spam
2
>>> a_foo2.spam
2
>>> Foo.spam = 3
>>> a_foo1.spam
3
>>> a_foo2.spam
3

# But now they'll diverge
>>> a_foo1.spam = 5
>>> a_foo1.spam
5
>>> a_foo2.spam
3
>>> Foo.spam = 2
>>> a_foo1.spam
5
>>> a_foo2.spam
2

If you are trying to make it so that modifying any instance's copy of spam modifies all instance's copies of spam, you'd use a property combined with a static attribute

class Foo(object):
    _spam = 2
    def __init__(self, a = 'init'):
        self.a = a

    @property
    def spam(self):
        return Foo._spam

    @spam.setter
    def spam(self, value)
        Foo._spam = value

>>> a_foo1 = Foo()
>>> a_foo2 = Foo()
>>> a_foo1.spam
2
>>> a_foo2.spam
2
>>> a_foo1.spam = 3
>>> a_foo2.spam
3

Although this kind of singleton-attribute behavior is somewhat dangerous and might be considered an anti-pattern by some, as most users of a class do not expect modifying one instance's attribute to modify all instances' attributes. You definitely need to have a very good reason for doing it this way.

aruisdante
  • 8,875
  • 2
  • 30
  • 37
2

If the method does not do anything but just returns an attribute value, just use the attribute.

However, your example is doubly strange since you are passing in the value you want back. If you just want the number 3, you don't need to use Foo.spam(3) or Foo.spam = 3; just use the number 3.

BrenBarn
  • 242,874
  • 37
  • 412
  • 384