2

I have read this question but it isn't clear to me. I defined my class like this:

from sqlite3 import Connection, Cursor, Row, connect

class myclass(object):
    def __init__(self,number):
        co = connect('C:\\mydatabase.sqlite')
        co.row_factory = Row
        with connection:            
            cu = connection.cursor()
            sql = '''SELECT * FROM mytable WHERE Number= {n} LIMIT 1'''.format(n = number)
            cu.execute(sql)
            for i in cu:
                self.classattribute1 = i['Field1']
                self.classattribute2 = i['Field2']
                etc.

Now this works fine until I want to add a third attribute to my class like:

self.classattribute3 = self.classattribute1 + self.classattribute2
AttributeError: 'myclass' object has no attribute 'classattribute1'

This won't work if the SELECT statement didn't return anything, if the number isn't in the database.

Now what I would like to do when I call an instance of myclass like:

myclassinstance1 = myclass(100)

I would like to write something like:

if cu.fetchone() == None:
    #code to exit the method __init__ and to delete my class instance here

I don't know how to exit and delete the instance I called from inside myclass. I need to delete theses instances because I don't want to use empty class instances.

Thanks for reading.

Community
  • 1
  • 1

1 Answers1

2

Just create a factory function that will either return a new instance or None if if couldn't be loaded:

class MyClass(object):
    def __init__(self, attribute1, attribute2, ...):
        self.attribute1 = attribute1
        self.attribute2 = attribute2
        # ...

    @staticmethod
    def load_from_db(number):
        # set up and query database
        record = cursor.fetchone()
        if record == None:
            return None
        else:
            return MyClass(record['Field1'], record['Field2'], ...)

Then load MyClass object from a database with:

my_obj = MyClass.load_from_db(number)

You can't delete an object in Python (from __init__ or anywhere), you can only delete a single reference to an object from a scope that contains this reference. (E.g. a scope calling MyClass(), like the load_from_db() function in the code above.)

millimoose
  • 39,073
  • 9
  • 82
  • 134
  • **if record == None: return None** how could i delete the class instance i called in the first place in this case? I need to be prevented from using an empty instance outside my class –  Oct 28 '12 at 21:05
  • @kingpin I expanded my example. You're calling a static function, the instance doesn't exist until the line `return MyClass(...)`. The idea is to check whether you can create the instance *before* you do so, not in the middle. – millimoose Oct 28 '12 at 21:07
  • 1
    `@staticmethod` is bad in this case, since `@classmethod` is for *exactly* these situations. Plus you don't have to keep up with class name changes. – rantanplan Oct 28 '12 at 21:20
  • @rantanplan What exactly would `@classmethod` help here? It's basically the same as `@staticmethod` except you get the class the method is called on as a parameter, which I don't need for the sake of this example. Obviously this code could be refactored into a highly generic and robust database layer of some sort, but that's outside the scope of the answer. – millimoose Oct 28 '12 at 21:36
  • Because you would do `return cls()` instead of hardcoding the class name. Python has a built-in construct for these cases. Simple as that. – rantanplan Oct 28 '12 at 21:45
  • @rantanplan There's no reason to assume that subclasses of `MyClass` even exist, or that they can be instantiated with the same constructor call; not knowing these further constraints the choice of `@staticmethod` vs. `@classmethod` is a complete and utter wash. I wanted to illustrate the construct of a factory method, and either decorator is appropriate for this, so I went with the one that seemed (by a hair) more straightforward. – millimoose Oct 28 '12 at 21:54
  • @millimoose this answer looks good but i can't make it work: should load_form_db have (self) argument? And when i go to the **else: # fetch attributes from record** how can i define self arguments for the class? should i do **return** MyClass(number,selfarg1,selfarg2, etc.)? If its the case i will do the data fetching within the _init_ method? –  Oct 28 '12 at 21:56
  • @kingpin It's a static method, so it shouldn't. A static method is basically a regular, non-OO function, except it's in the namespace of a class. The `...` I use means "fill in the attributes that your class has". The idea is that `__init__()` knows *nothing* about databases, and gets fed the data loaded from a database "from the outside". You do the data fetching in `load_from_db` where that comment is. – millimoose Oct 28 '12 at 21:59
  • There is no reason to assume that it won't get subclassed. Actually it is frightfully wrong to assume such a thing. Your answer is spot on and I'm giving you a +1 just to make it clear. I just made an observation on the pattern you chose to illustrate. `classmethod` is the one and only python way here, however we look at it. – rantanplan Oct 28 '12 at 22:01
  • @kingpin I updated my code example, hopefully that makes it clearer. – millimoose Oct 28 '12 at 22:04
  • 1
    @rantanplan I generally assume that a class may not be subclassed unless it's explicitly designed to allow it and documented to be so. (As per the Open-Closed Principle.) – millimoose Oct 28 '12 at 22:07
  • I was about to respond that "this seems like a Java programmer talking" and then I saw your posting history :) Believe me I wish python was so rigid and "safe" as Java. And we didn't get even get to the monkepatchi-ness horror. – rantanplan Oct 28 '12 at 22:14
  • @rantanplan Well, a die-hard Java programmer would be complaining about the fact there isn't a compiler to enforce these sorts of constraints at runtime. I merely happen to believe the SOLID principles are generally sound and should be (budget permitting ;) followed regardless of language. Besides, the OCP is basically Python's "explicit is better than implicit", applied to class hierarchy design. – millimoose Oct 28 '12 at 22:22
  • I knew almost nothing of Java until 2 months ago where I was task to develop an android app. It took me 2 weeks(I learned only the stuff I needed) to develop it and it was a success. The reason? Well `eclipse` wouldn't let me make a mistake! In python? Yeah I can pass anything I want to a function, but I have to assess for multiple type inputs. I can make no assumptions about subclassing, because anything is subclassable unless explicitly said otherwise. Then we have monkey-patching. Then you quit :P – rantanplan Oct 28 '12 at 22:31