12

Python (2.6) seems to be derping for no reason, can anyone see a problem with this code?

class DB ():
    def doSomething (self, str):
        print str

class A ():
    __db = DB()

    @staticmethod
    def getDB ():
        return A.__db

    db = property(getDB)


A.db.doSomething("blah")

Fails with the exception:

AttributeError: 'property' object has no attribute 'doSomething'

It was my understanding that a property would automatically run its getter when accessed, so why is it complaining about a property object, and why isn't it finding my clearly available method?

9
  • 2
    What Python version? If using Python 2.x, you'll need to build classes inheriting from object... Commented Dec 13, 2012 at 19:44
  • @JonClements -- Good eye! and it appears that OP is using python2.x because OP uses print str Commented Dec 13, 2012 at 19:45
  • 2.6, classes work fine without inheriting from object. Do i need to do this just for properties to work? Commented Dec 13, 2012 at 19:46
  • 3
    @ben Unless you have a very good reason - all your objects should inherit from object Commented Dec 13, 2012 at 19:46
  • Sorry Jon, i forgot to add the staticmethod decorator in my example. I wont be instantiating this class so inheriting from object will have no effect. Regardless, what are the benefits of inheriting from object? Commented Dec 13, 2012 at 19:51

3 Answers 3

22

In addition to needing to inherit from object, properties only work on instances.

a = A()
a.db.doSomething("blah")

To make a property work on the class, you can define a metaclass. (A class is an instance of a metaclass, so properties defined on the metaclass work on the class, just as properties defined on a class work on an instance of that class.)

Sign up to request clarification or add additional context in comments.

6 Comments

This is a static class, i wont be creating any instances. I assume this also makes inheriting from object pointless?
Easiest solution, assuming you don't need to be able to subclass this "static" class, is to just do A = A() right after the class definition. You then have one instance of the class upon which methods can be called. (It is possible, of course, to create new instances using type(), but this should be warning enough not to do that. Or use a metaclass.)
Thanks. I'd like to keep it static and i don't think it's worth implementing a metaclass just for largely superfluous properties, so i'll just ditch them altogether. Shame since on face value they seemed quite neat, if not very useful.
You don't need properties,though.
If you're using the class simply as a namespace, which seems to be what you mean by "static," it doesn't matter much whether the container is actually a class...
|
1

You aren't using classes correctly. A class is (normally) two things:

  1. A factory for creating a family of related objects
  2. A definition of the common behaviour of those objects

These related objects are the instances of the class. Normal methods are invoked on instances of the class, not on the class itself. If you want methods that can be invoked from the class, without an instance, you need to label the methods with @classmethod (or @staticmethod).

However I don't actually know whether properties work when retrieved from a class object. I can't check right now, but I don't think so. The error you are getting is that A.db is retrieving the property object which defines the property itself, it isn't "evaluating" the property to get A.__db. Property objects have no doSomething attribute. Properties are designed to be created in classes as descriptions of how the instances of those classes work.

If you did intend to be working with an instance of A, then you'll need to create one:

my_a = A()
my_a.db.doSomething("blah")

However, this will also fail. You have not correctly written getDB as any kind of method. Normal methods need an argument to represent the instance it was invoked on (traditionally called self):

def getDB(self):
    ...

Static methods don't, but need a decorator to label them as static:

@staticmethod
def getDB():
    ...

Class methods need both an argument to receive the class they were invoked on, and a decorator:

@classmethod
def getDB(cls):
    ...

7 Comments

It does have a staticmethod decorator. And there are many more ways to use classes than just the two you suggested. You didn't really answer the question here, just stated some obvious facts. I figured the property wasn't being evaluated correctly, which formed the basis of my question...
@It wasn't there when I wrote the answer. You appeared not to know that the property wasn't being evaluated, since you were asking "why isn't it finding my clearly available method?" rather than "why isn't python calling getDB?". It looked very much like the question sprang from some very fundamental misconceptions about classes in python; glad to learn that wasn't the case. :)
Sorry for the confusion. I figured since you answered that much longer after the others you'd seen the edit, sorry about that. Either way your answer may help others that stumble across it so not to worry! I'm still not really sure why an instance of the class is required for properties to be evaluated however?
@Ben For a definitive answer you'd have to ask the original designers. My guess would be that they considered that use case to be tangential, since most properties need an instance and will fail if you try to evaluate them without one. And if you couldn't retrieve the underlying property object from the class there'd be no way to get to it at all, since you can never guarantee that whatever it returns will have a __property__ special attribute (or whatever).
@Ben Slowness is because I'm on my phone.
|
-1

You don't need getters in Python:

class B(object):
    def do_something(self, str):
        print str

class A(object):
    db = B()

A.db.do_something("blah")

(I also PEP8:ed the code)

8 Comments

This is not the same code. db is no longer private. A is no longer static. And you're right, i don't need getters, but i want them.
@Ben: A is still static, it has not been instantiated. B never was private, there is no such thing as "private" objects in Python. All you did was namespace mangling.
True, but it's now less obvious with inheritance and a lack of static methods, but i appreciate this is all just theory. And yes again true, but it's Python's equivalent and i think the difference here is negligible.
@Ben: You don't need getters, but you want them... Have you considered what you want them for? What you expect to achieve by using them? You also do not appear to need a class at all if you are not instantiating nor subclassing it, since you're just using it as a glorified module.
The code in this example is a simple extraction based off my original problem. There is scope for many of my member vars to require additional processing, hence the getters. Whilst this wont apply to all member vars, my classes form modules within an API and i'd like to keep them consistent.
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.