[Tutor] [Re: class/type methods/functions]

spir denis.spir at free.fr
Thu Oct 30 21:07:00 CET 2008


[forwarded, only A.T.Hofkamp got this answer]

A.T.Hofkamp a écrit :
> spir wrote:
>> Q: Is there a way to write /type/ (class) functions, meaning methods 
not bound to an instance, in python?
>
> As Bob Gailer already said, staticmethod seems to do what you want.
Thank you for you answers about static methods. I will explore that 
path. Seems to be what I was looking for.
>
> After reading your mail, I cannot help wondering that something 
crucial seems to be missing in your class structure. (I get the 
impression that you are trying to squeeze object information and object 
meta information together in one class definition.)
>
Yes. This is a consequence of type & instance beeing defined in the same 
class() code section. If I unserstand well, what you call 
meta_information is for me simply type attributes. They will be 
available to any object of this type. Is this a misuse of types/classes? 
See also below for some more precisions.
This syntax that mixes type and object definition applies to all OOP 
languages, no? That's why we need a syntactic rule to distinguish type & 
instance attributes. In python, the way I understand it, the prefix 
'self.' (or any other special name) plays that role. It works for 
properties, i.e. non-method attributes. But the syntax chosen for method 
definition (with self written as argument instead of prefixed) makes it 
impossible: it seems that any method has to be bound to an instance.
> The examples you give are however too fragmented for me, to 
understand the underlying problem you are trying to solve.
>
Unfortunately, I can't paste right now a full & real snippet of the, as 
it is beeing refactored: it would rather be confusing. Here is a kind of 
outline of a typical symbol type:

class Format(Symbol):
   ''' block formats symbol '''
   # import relevant config data for this symbol type
   from_codes = config.formats.from_codes
   to_codes = config.formats.to_codes
   names = config.formats.names
   # open_format to be checked with closing tag (xhtml only)
   open_format = None
   def __init__(self, source, mark, section_level, posV, posH, close = 
False,
                   list_type = None, list_level=0):
       # posV & posH ~ line & element numbers for error output
       # 'mark' can be a wiki code or an xhfml tag
       self.section_level = section_level        # = current title level
       self.indent = section_level * TAB         # for nicer xhtml output
       self.close = close                        # for automatic 
closing (wiki only)
       self.list_level = list_level              # nesting level
       self.list_type = list_type                # bullet or number
       self.error = False                        # flag used for no output
       # read & record symbol data
       if source == WIKI:
           self.from_wiki(mark, posV, posH)
           return
       if source == XHTML:
           self.from_xhtml(mark, posV, posH)
   def from_wiki(self, code, posV, posH):
       ''' Define formats name.
           Record whether it's an opening or closing mark.'''
       [...]
   def from_xhtml(self, tag, posV, posH):
       ''' Define formats code. '''
       [...]
   def into_wiki(self):
       if self.error or self.close:
           return ''
       if self.name == LIST_ITEM:        # case of a list
           code = Format.to_codes[self.list_type]
           code *= self.list_level
       else:
           code = Format.to_codes[self.name]
       if code in header_block_codes:
           code *= self.section_level
       return code + SPACE
   def into_xhtml(self):
       if self.error:
           return ''
       return write_tag(self.name, self.close, DIV, self.section_level)
   def to_table():
       ''' write symbol data into plain text, table-like, format
           (for test or export to DB) '''
       [...]
  
(Note: by the way, native english speakers may tell me if the 
identifiers & comments seem clear -- the original program was in french 
-- but I will probably share it later. One of reasons of the rebuilding.)

So, as you can see, symbols of the Format type will use data held by 
their type. This seems rather an obvious and consistent practice to me. 
Namely, the from_codes, to_codes and names type attributes are available 
to future Format instances. these attributes were imported from an 
config module/object built at startup (from a config file).
The main process for building a sequence of symbols is (simplified):
* A function reads the source file step by step. Actually, it is a 
method of kind of state machine. Let's say the source is an xhtml doc 
(wiki codes vary much and are much less regular and more ambiguous).
* When it steps on a format tag (e.g. <li> for a lit item), it launches 
the creation of a format object, thus an instance of the Format type. 
Clear? Passes to it as argument relevant actual data of the parsing 
process, especially 'mark', that in this case holds the tag.
* The format will "read itself" from the tag, meaning it will record 
that it is an opening tag, a 'list item', and, say, one of the bullet 
kind. That'all for this kind of simple example.
That is more or less the way a representation of the source text is built.
The writing process is more straighforword. A (very) simplified outline 
may be:
for symbol in tortue.symbols:   # I called the state machine'turtle' ;-)
   out_file.write(symbol.into_wiki())  # case of writing into wiki lang
The symbols even take care of line feeds & consistent indentation!
Now, imagine it was a wiki text instead, and the user wishes to output 
it into a wiki language different of the one it was originally coded in. 
At some time between the reading & writing will the config been rebuilt 
and, as a consequence, data held by Symbol types. As this is an action 
of the type, I wish it to be performed by the type. So:
class Format(Symbol):
   ''' block formats symbol '''
   # import relevant config data for this symbol type
   def config():   # should be a type method (static?)
       from_codes = config.formats.from_codes
       to_codes = config.formats.to_codes
       names = config.formats.names


> Have you considered using the factory pattern? (ie make an object 
that represents the type, and another one for the data) In that way you 
can nicely seperate both kinds of information.
>
Definitely! That is the pattern I'm using -- or trying. I didn't know it 
has a name.  Now, isn't this factory<->object pattern precisely what the 
type<->instance relationship is supposed to be?
Now, I admit that in my particuliar case, the types/classes need the 
full potential of real objects:
* config ==> type properties
* config change at runtime ==> type methods
>
> Sincerely,
> Albert
>

If anyone of you wishes to comment/criticize the "exploration" part of 
my previous post, welcome!

Thank you all for your advices.
denis







More information about the Tutor mailing list