Hello,

I was lately implementing a kind of "pure symbol" type. What I call pure 
symbols is these kinds of constants that refer to pure "idea", so that they 
have no real obvious value. We usually _arbitrarily_ give them as value an int, 
a string, a boolean, an empty object:
   BLACK, WHITE = False, True
   GUARD_FLAG = object()
   N,S,W,E = 1,2,3,4
   READ,WRITE = 'r','w'
   ...

Such symbols, especially the ones we give boolean values, often match the use 
of C preprocessor flags:
   #define GUARD_FLAG
   ...
   #ifdef GUARD_FLAG ...
When there is a set of symbols, they match Pascal enumerations:
   var
      direction: (N, S, W, E);
They are often used as func parameters.
   f = open("foo.txt", WRITE)
The latter case is so common that numerous (built-in or third-party) libraries 
define a whole load of "pure symbol" constant values to be used as func 
arguments:
   pattern = re.compile(format, re.MULTILINE)

This is very heavy, indeed. But alternatives I can imagine are worse:
* Use literal (unnamed) values: illegible.
* Use unprefixed names: pollutes global namespace.
I cannot find any good solution for this issue. This is my first question.

These pure symbol are, I guess, a very close notion to the one of "nominals" 
(see http://en.wikipedia.org/wiki/Nominal_number). And in fact pascal enums are 
nominal types. So, I wrote this for isolated symbols:
class Nominal(object):
    count = 0
    def __init__(self, value=None):
        self.type = self.__class__
        self.type.count += 1
        # no need to restrict user-provided value, if any, to natural integer
        self.value = value if value is not None else self.type.count
    def __str__(self):
        typeName = self.type.__name__
        return "%s:(%s)" %(typeName,self.value)
x,y,z = Nominal(),Nominal(),Nominal()
print x,y,z     # Nominal:(1) Nominal:(2) Nominal:(3)

The type here can only be Nominal; and the value is not really needed, indeed, 
but it can be useful in some cases. Especially, this type can be the base of 
derived Nominal types, i.e. pascal-like enums. Like in Pascal, making the 
instances comparable can be very handy:
    def __lt__(self, other):
        assert(isinstance(other, Nominal))
        return self.value < other.value
class CardSuite(Nominal): pass
club,diamond,heart,spade = CardSuite(),CardSuite(),CardSuite(),CardSuite()
print club,diamond,heart,spade  # CardSuite:(4) CardSuite:(5) CardSuite:(6) 
CardSuite:(7)
print(diamond < heart)          # True

An issue is that a subtupe should start with count==0. I could not find any way 
to do that, so I ended up writing a subtype factory. But this goes against the 
language, for the user cannot use anymore the dedicated idiom "class 
CardSuite(Nominal)". Also, the type's name has to be *stupidly* passed as 
argument. So, the content of the method itself clearly shows how artificial 
this solution is:
    @classmethod
    def subtype(cls, name):
        class DummyName(cls): pass
        DummyName.count = 0
        DummyName.__name__ = name
        return X
CardSuite = Nominal.subtype("CardSuite")
club,diamond,heart,spade = CardSuite(),CardSuite(),CardSuite(),CardSuite()
print club,diamond,heart,spade  # CardSuite:(1) CardSuite:(2) CardSuite:(3) 
CardSuite:(4)
print(diamond < heart)          # True

Actually, what I need is a kind of __subtype__ magic method that acts for 
subtyping the same way __init__ does for instanciation. Then, I could write:
    @staticmethod
    def __subtype__(subtype):
        subtype.count = 0
(Note that here I do not need a classmethod, as staticmethod is enough.)

So, do you see any other solution? (I have probably overlooked some)
And, what do you think of __subtype__?

Denis
________________________________

la vita e estrany

http://spir.wikidot.com/
_______________________________________________
Tutor maillist  -  [email protected]
To unsubscribe or change subscription options:
http://mail.python.org/mailman/listinfo/tutor

Reply via email to