IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Python Discussion :

Tester si une chaîne peut être un nombre d'un type particulier


Sujet :

Python

  1. #1
    Membre chevronné

    Profil pro
    Account Manager
    Inscrit en
    Décembre 2006
    Messages
    2 301
    Détails du profil
    Informations personnelles :
    Localisation : France, Savoie (Rhône Alpes)

    Informations professionnelles :
    Activité : Account Manager

    Informations forums :
    Inscription : Décembre 2006
    Messages : 2 301
    Points : 1 752
    Points
    1 752
    Par défaut Tester si une chaîne peut être un nombre d'un type particulier
    Voici mon petit code :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    # -*- coding: utf-8 -*-
    #!/usr/bin/env python
     
    import re
    from fractions import Fraction
     
    # The following pattern commes from the book "Dive into Python".
    # It will be use to test if a text is a valid roman number.
    PATTERN_ROMAN_NUMERAL = re.compile("""
        ^                   # beginning of string
        M{0,4}              # thousands - 0 to 4 M's
        (CM|CD|D?C{0,3})    # hundreds - 900 (CM), 400 (CD), 0-300 (0 to 3 C's),
                            #            or 500-800 (D, followed by 0 to 3 C's)
        (XC|XL|L?X{0,3})    # tens - 90 (XC), 40 (XL), 0-30 (0 to 3 X's),
                            #        or 50-80 (L, followed by 0 to 3 X's)
        (IX|IV|V?I{0,3})    # ones - 9 (IX), 4 (IV), 0-3 (0 to 3 I's),
                            #        or 5-8 (V, followed by 0 to 3 I's)
        $                    # end of string
        """ ,re.VERBOSE)
     
    def isUpperRoman(stringToTest):
        return bool(PATTERN_ROMAN_NUMERAL.search(stringToTest))
     
    def isInteger(stringToTest):
        try:
    # We cannot use  isinstance(stringToTest, int) ...
            int(stringToTest)
            return True
        except:
            return False
     
    def isRational(stringToTest):
        try:
            Fraction(stringToTest)
            return True
        except:
            return False
     
     
    ###############
    ###############
    ##           ##
    ## FOR TESTS ##
    ##           ##
    ###############
    ###############
     
    if __name__ == '__main__':
        tests = []
     
        tests.append("isUpperRoman('I')")
        tests.append("isUpperRoman('4')")
     
        tests.append("isInteger('I')")
        tests.append("isInteger('4')")
     
        tests.append("isRational('I')")
        tests.append("isRational('4')")
        tests.append("isRational('4/5')")
        tests.append("isRational('123.667')")
     
        for oneTest in tests:
            print oneTest
            print '\t',
            exec "print " + oneTest
    Les méthodes sont typiquement celles de canards boîteux dont raffolent Python.

    Ma question est de savoir s'il est possible de faire autrement. Simple curiosité.

  2. #2
    Expert éminent
    Avatar de fred1599
    Homme Profil pro
    Lead Dev Python
    Inscrit en
    Juillet 2006
    Messages
    3 823
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Meurthe et Moselle (Lorraine)

    Informations professionnelles :
    Activité : Lead Dev Python
    Secteur : Arts - Culture

    Informations forums :
    Inscription : Juillet 2006
    Messages : 3 823
    Points : 7 119
    Points
    7 119
    Par défaut
    Tu peux utiliser le module types ou id()

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    >>> id(45)
    152270160
    >>> id(int("45"))
    152270160
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    >>> type(45) is types.IntType
    True
    Celui qui trouve sans chercher est celui qui a longtemps cherché sans trouver.(Bachelard)
    La connaissance s'acquiert par l'expérience, tout le reste n'est que de l'information.(Einstein)

  3. #3
    Expert éminent
    Avatar de tyrtamos
    Homme Profil pro
    Retraité
    Inscrit en
    Décembre 2007
    Messages
    4 462
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2007
    Messages : 4 462
    Points : 9 249
    Points
    9 249
    Billets dans le blog
    6
    Par défaut
    Bonjour,

    Tant que les nombres à tester sont formatés comme dans Python, on peut faire comme tu le proposes. Mais s'il s'agit, par exemple, de tester des nombres réels saisis avec une virgule au lieu d'un point décimal, ou des grands nombres ayant des séparateurs de milliers (espaces ou virgules à l'américaine), on peut recourir aux expressions régulières. J'ai essayé des solutions comme ça ici:

    http://python.jpvweb.com/mesrecettes...ivers_expr_reg.

    Tyrtamos
    Un expert est une personne qui a fait toutes les erreurs qui peuvent être faites, dans un domaine étroit... (Niels Bohr)
    Mes recettes python: http://www.jpvweb.com

  4. #4
    Membre régulier
    Profil pro
    Inscrit en
    Octobre 2009
    Messages
    70
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2009
    Messages : 70
    Points : 88
    Points
    88
    Par défaut
    Note que pour savoir si c'est un entier tu peux faire :

    machin = "123"
    machin.isdigit()

  5. #5
    Membre chevronné

    Profil pro
    Account Manager
    Inscrit en
    Décembre 2006
    Messages
    2 301
    Détails du profil
    Informations personnelles :
    Localisation : France, Savoie (Rhône Alpes)

    Informations professionnelles :
    Activité : Account Manager

    Informations forums :
    Inscription : Décembre 2006
    Messages : 2 301
    Points : 1 752
    Points
    1 752
    Par défaut
    Citation Envoyé par fred1599 Voir le message
    Tu peux utiliser le module types ou id()

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    >>> id(45)
    152270160
    >>> id(int("45"))
    152270160
    L'inconvénient de cette méthode par rapport à la mienne est qu'elle appelle les deux fonctions id et int au lieu de seulement int.

    Citation Envoyé par tyrtamos Voir le message
    Tant que les nombres à tester sont formatés comme dans Python, on peut faire comme tu le proposes.
    Oui effectivement. Si les nombres ne sont pas formatés la solution qui me vient à l'esprit est de passer par sympy qui se charge de faire les calculs et les simplifications exactes dans toutes les situations possibles.

    Citation Envoyé par tyrtamos Voir le message
    Mais s'il s'agit, par exemple, de tester des nombres réels saisis avec une virgule au lieu d'un point décimal, ou des grands nombres ayant des séparateurs de milliers (espaces ou virgules à l'américaine), on peut recourir aux expressions régulières.
    Merci.

    Citation Envoyé par peufeu Voir le message
    Note que pour savoir si c'est un entier tu peux faire :

    machin = "123"
    machin.isdigit()
    Merci

  6. #6
    Expert éminent
    Avatar de fred1599
    Homme Profil pro
    Lead Dev Python
    Inscrit en
    Juillet 2006
    Messages
    3 823
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Meurthe et Moselle (Lorraine)

    Informations professionnelles :
    Activité : Lead Dev Python
    Secteur : Arts - Culture

    Informations forums :
    Inscription : Juillet 2006
    Messages : 3 823
    Points : 7 119
    Points
    7 119
    Par défaut
    On peut aussi utiliser assert

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    assert(isinstance(nombre, int))
    Celui qui trouve sans chercher est celui qui a longtemps cherché sans trouver.(Bachelard)
    La connaissance s'acquiert par l'expérience, tout le reste n'est que de l'information.(Einstein)

  7. #7
    Membre chevronné

    Profil pro
    Account Manager
    Inscrit en
    Décembre 2006
    Messages
    2 301
    Détails du profil
    Informations personnelles :
    Localisation : France, Savoie (Rhône Alpes)

    Informations professionnelles :
    Activité : Account Manager

    Informations forums :
    Inscription : Décembre 2006
    Messages : 2 301
    Points : 1 752
    Points
    1 752
    Par défaut
    Pas dans mon cas car la variable à tester est stockée sous forme de chaîne puisqu'elle provient d'un fichier texte.

  8. #8
    Membre extrêmement actif
    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    1 418
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 1 418
    Points : 1 658
    Points
    1 658
    Par défaut
    Pourquoi parles tu de canards boiteux ? Le code que tu présentes est quand même malin.

    Mais tous ces append() , ça fait un peu malin vilain. Et si tu veux introduire les valeurs à tester par un raw_input(), tu vas être obligé de réécrire ce code. Pour clarifier ce code en restant dans son esprit, j’écrirais donc

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    if __name__ == '__main__':
     
        tests = ["isUpperRoman('I')",
                 "isUpperRoman('4')",
                 "isInteger('I')",
                 "isInteger('4')",
                 "isRational('I')",
                 "isRational('4')",
                 "isRational('4/5')",
                 "isRational('123.667')"]
     
        tests = [ 'print "%s\\n\t\" + repr(%s)' % (u,u) for u in tests ]
        exec '\n'.join(tests)


    Je suppose que tu utilises cet exec que tu affectionnes dans le cadre de ton programme démonstratif.
    Sinon, je préfère la simplicité suivante:
    - fonction isdigit() citée par peufeu, qui suffit bien en effet
    - je garde ta fonction isRational() , ne voyant pas par quoi la remplacer
    - un regroupement des fonctions en triplet, et un dictionnaire à clés triplets remplaçant haut la main de devoir écrire chaque fonction pour chaque string testée

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    # -*- coding: utf-8 -*-
    #!/usr/bin/env python
     
    import re
    from fractions import Fraction
     
    # The following pattern commes from the book "Dive into Python".
    # It will be use to test if a text is a valid roman number.
    PATTERN_ROMAN_NUMERAL = re.compile('''
        ^                   # beginning of string
        M{0,4}              # thousands - 0 to 4 M's
        (CM|CD|D?C{0,3})    # hundreds - 900 (CM), 400 (CD), 0-300 (0 to 3 C's),
                            #            or 500-800 (D, followed by 0 to 3 C's)
        (XC|XL|L?X{0,3})    # tens - 90 (XC), 40 (XL), 0-30 (0 to 3 X's),
                            #        or 50-80 (L, followed by 0 to 3 X's)
        (IX|IV|V?I{0,3})    # ones - 9 (IX), 4 (IV), 0-3 (0 to 3 I's),
                            #        or 5-8 (V, followed by 0 to 3 I's)
        $                    # end of string
        ''' ,re.VERBOSE)
     
     
    def isRational(stringToTest):
        try:
            Fraction(stringToTest)
            return True
        except:
            return False
     
    dico = dict(zip(((True,False,False),(False,True, True),(False,False,True),(False,False,False)),\
                    ('  est un nombre romain','  est un entier','  est un rationnel',\
                     "  n'est ni un nombre romain, ni un entier, ni un rationnel")))
     
     
    ###############
    ###############
    ##           ##
    ## FOR TESTS ##
    ##           ##
    ###############
    ###############
     
    if __name__ == '__main__':
     
        li = ['XVI','435','4/5','123.667','bigoudi']
     
        for u in li:
            print u + dico[bool(PATTERN_ROMAN_NUMERAL.match(u)),u.isdigit(),isRational(u)]


    ------------------------

    Au delà de ces questions de conception, je crois qu’il serait bon aussi de s’interroger sur les limites de validité de l’utilisation de Fraction pour discriminer les rationnels.

    Le code suivant calcule n et d tels que n/d = section , pour des sections de '1235.1847395274539645108453672985463' de plus en plus grandes
    et il calcule d * section pour voir si il retrouve n.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    from fractions import Fraction             
     
    ch = '1235.1847395274539645108453672985463'
    for j in xrange(1,len(ch)):
        n,_,d = repr(Fraction(ch[:j]))[9:-1].partition(', ')
        print '\nn = '+n+'\nd = '+d
        print 'ch[:'+str(j)+'] : '+str(ch[:j])\
              +'\n      d * '+ch[:j]+' = '+str(float(d)*float(ch[:j])),float(d)*float(ch[:j])== float(n)
    .........
    ............. etxrait

    n = 3859952311
    d = 3125000
    ch[:13] : 1235.18473952
    d * 1235.18473952 = 3859952311.0 True

    n = 1235184739527
    d = 1000000000
    ch[:14] : 1235.184739527
    d * 1235.184739527 = 1.23518473953e+12 True

    n = 6175923697637
    d = 5000000000
    ch[:15] : 1235.1847395274
    d * 1235.1847395274 = 6.17592369764e+12 True

    n = 24703694790549
    d = 20000000000
    ch[:16] : 1235.18473952745
    d * 1235.18473952745 = 2.47036947905e+13 False

    n = 1235184739527453
    d = 1000000000000
    ch[:17] : 1235.184739527453
    d * 1235.184739527453 = 1.23518473953e+15 True

    n = 12351847395274539
    d = 10000000000000
    ch[:18] : 1235.1847395274539
    d * 1235.1847395274539 = 1.23518473953e+16 False

    n = 30879618488186349
    d = 25000000000000
    ch[:19] : 1235.18473952745396
    d * 1235.18473952745396 = 3.08796184882e+16 True

    n = 308796184881863491
    d = 250000000000000
    ch[:20] : 1235.184739527453964
    d * 1235.184739527453964 = 3.08796184882e+17 True

    n = 2470369479054907929
    d = 2000000000000000
    ch[:21] : 1235.1847395274539645
    d * 1235.1847395274539645 = 2.47036947905e+18 True

    n = 123518473952745396451
    d = 100000000000000000
    ch[:22] : 1235.18473952745396451
    d * 1235.18473952745396451 = 1.23518473953e+20 False
    ................
    ..................
    À partir d’une certaine section du nombre '1235.1847395274539645108453672985463', il trouve des False, alors qu’il a réussi à trouver n et d.

    Je n’ai pas regardé tout ça en détail mais, dans ces conditions, que signifie que Fraction(x) soit possible donc donne isRational(stringToTest) égal à True ?

    Peux tu donner un exemple de nombre pour lequel Fraction(’nombre’) produit une erreur ?





    ------------------------------

    Enfin je trouve ce post un peu bizarre.
    - Il y a deux fautes d'orthographie dans
    # The following pattern commes from the book "Dive into Python".
    # It will be use to test if a text is a valid roman number.
    - Souvent tu mets l'adresse de référence du code ou de la discussion
    Là il n’y en a pas.
    - Je n'ai pas trouvé de code utilisant ces méthodes de canard boiteux dans les livres Dive into Python consultables sur internet, auusi bien pour Python 2 que celui pour Python 3.
    - Une googlerie sur 'PATTERN_ROMAN_NUMERAL' ne donne aucun résultat sauf ton propre post.

    Tu ne nous ferais pas un coup à la Romain Gary ?



    PS

    «Les pattes du canard sont courtes, il est vrai ; mais les allonger ne lui apporterait rien.»
    [ Tchouang-Tseu ]

    C'est pour ne pas contrarier Tchouang-tseu que je me suis permis de raccourcir les pattes des canards.

  9. #9
    Membre chevronné

    Profil pro
    Account Manager
    Inscrit en
    Décembre 2006
    Messages
    2 301
    Détails du profil
    Informations personnelles :
    Localisation : France, Savoie (Rhône Alpes)

    Informations professionnelles :
    Activité : Account Manager

    Informations forums :
    Inscription : Décembre 2006
    Messages : 2 301
    Points : 1 752
    Points
    1 752
    Par défaut
    Citation Envoyé par eyquem Voir le message
    Pourquoi parles tu de canards boiteux ? Le code que tu présentes est quand même malin.
    Une explication ici : http://en.wikipedia.org/wiki/Duck_typing#In_Python .

    Citation Envoyé par eyquem Voir le message
    Je suppose que tu utilises cet exec que tu affectionnes dans le cadre de ton programme démonstratif.
    Sinon, je préfère la simplicité suivante:
    - fonction isdigit() citée par peufeu, qui suffit bien en effet
    - je garde ta fonction isRational() , ne voyant pas par quoi la remplacer
    - un regroupement des fonctions en triplet, et un dictionnaire à clés triplets remplaçant haut la main de devoir écrire chaque fonction pour chaque string testée

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    # -*- coding: utf-8 -*-
    #!/usr/bin/env python
     
    import re
    from fractions import Fraction
     
    # The following pattern commes from the book "Dive into Python".
    # It will be use to test if a text is a valid roman number.
    PATTERN_ROMAN_NUMERAL = re.compile('''
        ^                   # beginning of string
        M{0,4}              # thousands - 0 to 4 M's
        (CM|CD|D?C{0,3})    # hundreds - 900 (CM), 400 (CD), 0-300 (0 to 3 C's),
                            #            or 500-800 (D, followed by 0 to 3 C's)
        (XC|XL|L?X{0,3})    # tens - 90 (XC), 40 (XL), 0-30 (0 to 3 X's),
                            #        or 50-80 (L, followed by 0 to 3 X's)
        (IX|IV|V?I{0,3})    # ones - 9 (IX), 4 (IV), 0-3 (0 to 3 I's),
                            #        or 5-8 (V, followed by 0 to 3 I's)
        $                    # end of string
        ''' ,re.VERBOSE)
     
     
    def isRational(stringToTest):
        try:
            Fraction(stringToTest)
            return True
        except:
            return False
     
    dico = dict(zip(((True,False,False),(False,True, True),(False,False,True),(False,False,False)),\
                    ('  est un nombre romain','  est un entier','  est un rationnel',\
                     "  n'est ni un nombre romain, ni un entier, ni un rationnel")))
     
     
    ###############
    ###############
    ##           ##
    ## FOR TESTS ##
    ##           ##
    ###############
    ###############
     
    if __name__ == '__main__':
     
        li = ['XVI','435','4/5','123.667','bigoudi']
     
        for u in li:
            print u + dico[bool(PATTERN_ROMAN_NUMERAL.match(u)),u.isdigit(),isRational(u)]
    Merci pour ce nettoyage.

    Citation Envoyé par eyquem Voir le message
    Au delà de ces questions de conception, je crois qu’il serait bon aussi de s’interroger sur les limites de validité de l’utilisation de Fraction pour discriminer les rationnels.
    De ce côté je n'ai pas de souci car je vais utiliser les fonctions dans un cadre très restrictif : petites valeurs entières...

    Citation Envoyé par eyquem Voir le message
    Enfin je trouve ce post un peu bizarre.
    Venant de moi cela ne devrait plus t'étonner...

    Citation Envoyé par eyquem Voir le message
    - Il y a deux fautes d'orthographie dans
    # The following pattern commes from the book "Dive into Python".
    # It will be use to test if a text is a valid roman number.
    Je parlerais plutôt de "fôte" de frappe.

    Citation Envoyé par eyquem Voir le message
    Souvent tu mets l'adresse de référence du code ou de la discussion
    Parce qu'un simple appel à Google renvoie au dit livre. Voir ici : http://diveintopython.adrahon.org/re..._numerals.html . Il faut aussi regarder dans le code disponible en téléchargement.

    Citation Envoyé par eyquem Voir le message
    Tu ne nous ferais pas un coup à la Romain Gary ?
    Non car je suis très fâché avec les regex...

  10. #10
    Membre extrêmement actif
    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    1 418
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 1 418
    Points : 1 658
    Points
    1 658
    Par défaut
    Aaaaaah mais bien sûr....j’avais lu des trucs sur cette histoire de canard. Mais ça ne m’étonne pas que je n’en ai rien retenu: je viens de relire l’article de wikipedia, je n’ai toujours rien compris. Ça m’a l’air surtout l’air d’être une histoire pour ceux qui aiment barboter dans la mare de la POO, ce qui moi, ne m’attire pas trop. Mais bon, l’article dit que Guido est un avocat convaincu du duck-typing, alors je me dis que ça ne peut pas être idiot cette histoire là....




    Pour ce qui est de la bizarrerie de ton post, l’explication est que, n’ayant pas trouvé la chaine de regex de ton post dans les sites de Dive into Python (mais je n’ai pas pensé que Il faut aussi regarder dans le code disponible en téléchargement.
    ), + tout le reste, je me suis demandé si tu ne présentais pas ce code comme provenant de Dive into Python alors qu’il s’agissait en fait de ton code.

    Ceci afin de voir s’il serait accueilli autrement que quand tu nous fais le coup du post avec des trucs marrants.....

    Romain Gary est le seul écrivain qui a eu le prix Goncourt deux fois alors que les statuts de ce prix l’interdisent. C’est parce qu’il l’a eu en 1975 en camouflant son livre, “La vie devant soi“ , sous le pseudonyme de Émile Ajar. Je suppose qu’il voulait surtout voir comment serait reçu son livre par des gens dont l’inconnaissance de l’auteur ne pourrait nourrir leurs a priori.

    C’est une idée comme un canard, boiteuse et caquetante....


    Nota Bene:

    en septembre est parue une actualisation de Dive into Python, qui couvre Python 3 et ses différences avec Python 2.

    http://diveintopython3.org/

  11. #11
    Membre éprouvé
    Homme Profil pro
    Inscrit en
    Décembre 2007
    Messages
    758
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : France

    Informations professionnelles :
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Décembre 2007
    Messages : 758
    Points : 970
    Points
    970
    Par défaut
    Citation Envoyé par eyquem Voir le message
    Aaaaaah mais bien sûr....j’avais lu des trucs sur cette histoire de canard. Mais ça ne m’étonne pas que je n’en ai rien retenu: je viens de relire l’article de wikipedia, je n’ai toujours rien compris. Ça m’a l’air surtout l’air d’être une histoire pour ceux qui aiment barboter dans la mare de la POO, ce qui moi, ne m’attire pas trop. Mais bon, l’article dit que Guido est un avocat convaincu du duck-typing, alors je me dis que ça ne peut pas être idiot cette histoire là....
    bonjour,

    je réagis juste sur ce point. la définition de wikipédia est correct mais je trouve qu'elle noie un peu le poisson...

    oula, des canards, des poissons, on va jamais s'en sortir

    une manière plus concise de dire en quoi consiste le duck typing (et la phrase n'est pas de moi):

    l'important, ce n'est pas ce que les choses sont, c'est ce que les choses font.
    sans avoir à chercher trop loin, on peut déjà remarquer ce que la librairie standard nous donne:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    for item in (0,1,2):
        print item
    for item in [0,1,2]:
        print item
    for item in "aeiou":
        print item
    quelque soit le type (tuple, liste, chaine), on itère de la même façon.

    une liste n'est pas un tuple, mais on peut itérer avec de la même façon: elle "quack" comme un tuple.

  12. #12
    Membre chevronné

    Profil pro
    Account Manager
    Inscrit en
    Décembre 2006
    Messages
    2 301
    Détails du profil
    Informations personnelles :
    Localisation : France, Savoie (Rhône Alpes)

    Informations professionnelles :
    Activité : Account Manager

    Informations forums :
    Inscription : Décembre 2006
    Messages : 2 301
    Points : 1 752
    Points
    1 752
    Par défaut
    Une petite amélioration du code juste pour le fun :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    # -*- coding: utf-8 -*-
    #!/usr/bin/env python
     
    import re
    from decimal import Decimal
    from fractions import Fraction
     
    # The following pattern comes from the book "Dive into Python".
    # It will be used to test if a text is a valid roman number.
    PATTERN_ROMAN_NUMERAL = re.compile("""
        ^                   # beginning of string
        M{0,4}              # thousands - 0 to 4 M's
        (CM|CD|D?C{0,3})    # hundreds - 900 (CM), 400 (CD), 0-300 (0 to 3 C's),
                            #            or 500-800 (D, followed by 0 to 3 C's)
        (XC|XL|L?X{0,3})    # tens - 90 (XC), 40 (XL), 0-30 (0 to 3 X's),
                            #        or 50-80 (L, followed by 0 to 3 X's)
        (IX|IV|V?I{0,3})    # ones - 9 (IX), 4 (IV), 0-3 (0 to 3 I's),
                            #        or 5-8 (V, followed by 0 to 3 I's)
        $                    # end of string
        """ ,re.VERBOSE)
     
    def isUpperRoman(stringToTest):
        return bool(PATTERN_ROMAN_NUMERAL.search(stringToTest))
     
    def isNatural(stringToTest):
        return stringToTest.isdigit()
     
    def isInteger(stringToTest):
        try:
    # We cannot use  isinstance(stringToTest, int) .
    # The same is true for the following tests.
            int(stringToTest)
            return True
        except:
            return False
     
    def isDecimal(stringToTest):
        try:
            Decimal(stringToTest)
            return True
        except:
            return False
     
    def isRational(stringToTest):
        try:
            Fraction(stringToTest)
            return True
        except:
            return False
     
     
    ###############
    ###############
    ##           ##
    ## FOR TESTS ##
    ##           ##
    ###############
    ###############
     
    if __name__ == '__main__':
        expToTest = ['XVI','12','-435','4/5','123.667','duck']
     
        functionsNames = ['isUpperRoman', 'isNatural', 'isInteger', 'isDecimal', 'isRational']
    # With Python 3, functionsNames is not needed because
    # we can use OrderedDict so as to have an ordered dictionnary.
        forTest = {'isUpperRoman': [isUpperRoman, '  is a roman number.'],
                   'isNatural': [isNatural, '  is a natural number.'],
                   'isInteger': [isInteger, '  is an integer number.'],
                   'isDecimal': [isDecimal, '  is a decimal number.'],
                   'isRational': [isRational, '  is a rational number.']}
     
        for onePossibleNumber in expToTest:
            kindFound = False
     
            for oneFunction in functionsNames:
                if forTest[oneFunction][0](onePossibleNumber):
                    print onePossibleNumber + forTest[oneFunction][1]
                    kindFound = True
                    break
     
            if not kindFound:
                print onePossibleNumber + '  is not a known number.'
    PS : pour l'histoire du canard boîteux, le plus typique est l'emploi de TRY et EXCEPT pour faire une action au lieu de faire quelque chose comme si j'ai cela alors on fait ceci, sinon on fait autre chose. Les canards boîteux essaient et si cela ne va pas, il passent à autre chose.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Un petit défi : tester si une chaîne est un nombre romain
    Par rambc dans le forum Général Python
    Réponses: 1
    Dernier message: 09/04/2009, 12h43
  2. [DBF] Tester si une chaîne est vide
    Par ®om dans le forum JDBC
    Réponses: 7
    Dernier message: 26/07/2007, 16h30
  3. Voir si une chaîne est composée de nombre
    Par Destiny dans le forum C#
    Réponses: 2
    Dernier message: 26/04/2007, 09h56
  4. une idée peut être?
    Par b.amine dans le forum Excel
    Réponses: 2
    Dernier message: 01/04/2007, 11h19
  5. Tester qu'une variable varchar est un nombre
    Par Oluha dans le forum MS SQL Server
    Réponses: 2
    Dernier message: 06/06/2005, 13h29

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo