[Tutor] Declaration order of classes... why it is important?
Dave Angel
davea at ieee.org
Wed Aug 26 21:46:28 CEST 2009
Kent Johnson wrote:
> On Wed, Aug 26, 2009 at 12:25 PM, Mac Ryan<quasipedia at gmail.com> wrote:
>
>> Hello everybody,
>>
>> I am using "storm" (https://storm.canonical.com/) to manage my
>> database. In storm, relationships between tables (each table is
>> represented by a class) are expressed like this (line #4):
>>
>> 1 >>> class Employee(Person):
>> 2 ... __storm_table__ =employee"
>> 3 ... company_id =nt()
>> 4 ... company =eference(company_id, Company.id)
>>
>> where Company is another class. Now, what I noticed is that Company must
>> be declared as a class before Employee, or python will throw an
>> exception (Company is not defined).
>>
>> I would be interested in understanding why this is so designed. I
>> expected that the exception would not be thrown at all, as I imagined
>> that the interpreter simply kept track of where classes were declared
>> and would try to evaluate the code only once an actual object would be
>> instantiated (at that point the interpreter would know where to look for
>> each class code).
>>
>
> The body of a class definition is executed when it is encountered. The
> result is a class object (an instance of 'type', usually). Any names
> defined at class scope become attributes of the class. The class name
> becomes a reference to the class object.
>
>
>> BTW, the behaviour I am describing is exactly what happens with function
>> declaration: the following code evaluates as expected, indeed.
>>
>> def fone():
>> ftwo()
>> def ftwo():
>> print "hello"
>> fone()
>>
>
> Yes, functions are different than classes. The body of a function is
> not executed until it is called.
>
> Note that class methods behave like functions (well, they are
> functions) - they are not executed until called. But statements at
> class scope are executed to create the class.
>
>> I would also be interested in knowing if there is a way around this or
>> if I simply have to live with it.
>>
>
> You have to live with it unless you can put the attributes inside a
> method. In this case, I don't think that will work.
>
> Kent
>
>
In Python, you don't declare classes, you define them.
You can forward reference inside a definition (or method), but not
elsewhere. That's because it's a one-pass system, where the lines are
executed in order. In the case of a "def", execution consists of
compiling the body and making a function object. That function object
may forward reference all it likes, as long as it's not called until
those references are available.
So there are two workarounds to get what you'd like. Your problem is
that you want the classes in a certain order, but that the first class
has class attributes that have a forward reference. You can't do that
directly.
1) As Kent suggested, you can put the attribute initialization inside a
"dummy class method," one that will only be executed once, and that you
promise will be executed before any other method of the class. Then
when you have finished defining the dependency (the other class), you
call this dummy method.
Since you don't define all the other stuff, I have to simplify your
case. Give a working fragment, if this is too simplified.
class Employee(object):
__storm_table__ = "employee"
company_id = []
company = Company.id #where Company is a forward reference
class Company:
id = 42
This gives an error trying to define the Employee.company attribute.
So define a classmethod to finish the job, and invoke it later
class Employee(object):
@classmethod
def finish(cls):
cls.__storm_table__ = "employee"
cls.company_id = []
cls.company = Company.id #where Company is a forward
reference
del cls.finish #remove this method so it won't be called a
second time
class Company:
id = 42
Employee.finish() #This finishes initializing the class
help(Employee)
print Employee.company_id
2) Simpler: Simply define the forward referencing class method later
in the file, in the same place you would have invoked finish().
class Employee(object):
__storm_table__ = "employee"
company_id = []
#company = Company.id #Do this later
class Company:
id = 42
Employee.company_id = Company.id
DaveA
More information about the Tutor
mailing list