2010-05-20 6 views
2

J'apprends Python (j'ai un fond C/C++).Comment écrire cet extrait de code en Python?

J'ai besoin d'écrire quelque chose de pratique en Python, tout en apprenant. J'ai le pseudo-code suivant (ma première tentative d'écriture d'un script Python, depuis que j'ai lu Python hier). J'espère que l'extrait détaille la logique de ce que je veux faire. BTW J'utilise python 2.6 sur Ubuntu Karmic.

Supposons que le script est appelé comme: script_name.py directory_path

import csv, sys, os, glob 

# Can I declare that the function accepts a dictionary as first arg? 
def getItemValue(item, key, defval) 
    return !item.haskey(key) ? defval : item[key] 


dirname = sys.argv[1] 

# declare some default values here 
weight, is_male, default_city_id = 100, true, 1 

# fetch some data from a database table into a nested dictionary, indexed by a string 
curr_dict = load_dict_from_db('foo') 

#iterate through all the files matching *.csv in the specified folder 
for infile in glob.glob(os.path.join(dirname, '*.csv')): 
    #get the file name (without the '.csv' extension) 
    code = infile[0:-4] 
    # open file, and iterate through the rows of the current file (a CSV file) 
    f = open(infile, 'rt') 
    try: 
    reader = csv.reader(f) 
    for row in reader: 
     #lookup the id for the code in the dictionary 
     id = curr_dict[code]['id'] 
     name = row['name'] 
     address1 = row['address1'] 
     address2 = row['address2'] 
     city_id = getItemValue(row, 'city_id', default_city_id) 

     # insert row to database table 

    finally: 
    f.close() 

J'ai les questions suivantes:

  1. est le code écrit d'une manière assez Pythonic (est-il une meilleure façon de l'implémenter)?

  2. Étant donné une table avec un schéma comme montré ci-dessous, comment puis-je écrire une fonction Python qui récupère des données de la table et renvoie dans un dictionnaire indexé par une chaîne (nom).

  3. Comment puis-je insérer les données de ligne dans la table (en fait je voudrais utiliser une transaction si possible, et engager juste avant que le fichier est fermé)

Schéma de la table:

create table demo (id int, name varchar(32), weight float, city_id int); 

BTW, ma base de données back-end est postgreSQL

[Modifier]

Wayne et al:

Pour clarifier, ce que je veux, c'est un ensemble de lignes. Chaque ligne peut être indexée par une clé (ce qui signifie que le conteneur des lignes est un dictionnaire (à droite)? Ok, maintenant une fois que nous avons récupéré une ligne en utilisant la clé, je veux aussi pouvoir accéder aux 'colonnes' la ligne - ce qui signifie que les données de la ligne elle-même est un dictionnaire.Je ne sais pas si Python prend en charge la syntaxe de tableau multidimensionnelle lorsqu'il s'agit de dictionnaires - mais la déclaration suivante aidera à expliquer comment je compte utiliser conceptuellement les données renvoyées par la base de données. dataset ['joe'] ['weight'] récupérera d'abord les données de la ligne indexées par la clé 'joe' (qui est un dictionnaire), puis indexera ce dictionnaire pour la clé 'weight' Je veux savoir comment construire un dictionnaire de dictionnaires à partir des données récupérées d'une manière pythonique comme vous l'avez fait auparavant

Une manière simpliste serait d'écrire quelque chose comme:

import pyodbc 

mydict = {} 
cnxn = pyodbc.connect(params) 
cursor = cnxn.cursor() 
cursor.execute("select user_id, user_name from users"): 

for row in cursor: 
    mydict[row.id] = row 

Est-ce correct/peut-il être écrit d'une manière plus pythonique?

+0

s'il vous plaît répondez aux commentaires si vous voulez une réponse, sinon nous ne serons pas paginés. Il me semble parfaitement pythonique - les lignes que je pense sont renvoyées sous forme de tuples qui peuvent être accédées par index et par nom de colonne donc ce pourrait être 'mydict [row [0]] = row [1]' ou mydict [row. user_id] = row.user_name' (ils donnent tous les deux le même résultat.) Et oui, vous pouvez avoir des tableaux multidimensionnels, des listes/tuples dans des dicts et vice-versa à autant de dimensions que vous le souhaitez :-) – cryo

+0

Vous pouvez créer un dictionnaire comme par exemple. 'pour la ligne dans le curseur: mydict [row.user_id] = {'nom d'utilisateur': row.user_name, 'weight': row.weight}' – cryo

Répondre

5

pour obtenir la valeur du dictionnaire que vous devez utiliser la méthode .get du dict:

>>> d = {1: 2} 
>>> d.get(1, 3) 
2 
>>> d.get(5, 3) 
3 

Cela permettra d'éliminer la nécessité de getItemValue fonction. Je ne commenterai pas la syntaxe existante car elle est clairement étrangère à Python.La syntaxe correcte pour le ternaire en Python est:

true_val if true_false_check else false_val 
>>> 'a' if False else 'b' 
'b' 

Mais comme je dis ci-dessous, vous n'avez pas besoin du tout.

Si vous utilisez Python> 2.6, vous devez utiliser la déclaration with sur la try-finally:

with open(infile) as f: 
    reader = csv.reader(f) 
    ... etc 

Voyant que vous voulez avoir row comme le dictionnaire, vous devriez utiliser csv.DictReader et non un csv. reader simple. Cependant, cela n'est pas nécessaire dans votre cas. Votre requête sql pourrait simplement être construite pour accéder aux champs du dict row. Dans ce cas, vous auriez pas besoin de créer des éléments séparés city_id, name, etc. Pour ajouter par défaut city_id-row si elle n'existe pas, vous pouvez utiliser la méthode .setdefault:

>>> d 
{1: 2} 
>>> d.setdefault(1, 3) 
2 
>>> d 
{1: 2} 
>>> d.setdefault(3, 3) 
3 
>>> d 
{1: 2, 3: 3} 

et id, simplement row[id] = curr_dict[code]['id']

lors du tranchage, vous pouvez sauter 0:

>>> 'abc.txt'[:-4] 
'abc' 

en général, la bibliothèque de Python fournir un fetchone, fetchmany, fetchall des méthodes sur le curseur, qui renvoient l'objet , qui pourrait prendre en charge l'accès de type dict ou retourner un simple tuple. Cela dépend du module particulier que vous utilisez.

+0

ne hésitez pas à commenter la syntaxe. C'était mon tout premier script Python (et j'ai seulement commencé à lire sur Python hier), alors n'hésitez pas à corriger les erreurs que vous pouvez détecter. L'idée de la poste (en dehors de se lever et courir ASAP) est d'apprendre de «Pythonistas»;) – morpheous

+0

+1 pour les conseils utiles. Très apprécié – morpheous

2

Il semble assez Pythonic assez pour moi.

L'opération ternaire devrait ressembler à ceci bien (je pense que cela va revenir le résultat que vous attendez):

return defval if not key in item else item[key] 

Ouais, vous pouvez passer un dictionnaire (ou toute autre valeur) dans essentiellement un ordre quelconque. La seule différence est si vous utilisez le * args, ** kwargs (nommé par convention Techniquement, vous pouvez utiliser le nom que vous voulez) qui s'attendent à être dans cet ordre et le dernier ou deux arguments.

Pour insérer dans un DB, vous pouvez utiliser le module odbc:

import odbc 
conn = odbc.odbc('servernamehere') 
cursor = conn.cursor() 
cursor.execute("INSERT INTO mytable VALUES (42, 'Spam on Eggs', 'Spam on Wheat')") 
conn.commit() 

Vous pouvez lire ou de trouver beaucoup d'exemples sur le module odbc - Je suis sûr qu'il ya d'autres modules, mais on devrait bien fonctionner pour vous.

Pour la récupération que vous utilisez

cursor.execute("SELECT * FROM demo") 
#Reads one record - returns a tuple 
print cursor.fetchone() 
#Reads the rest of the records - a list of tuples 
print cursor.fetchall() 

pour faire un de ces enregistrements dans un dictionnaire:

record = cursor.fetchone() 
# Removes the 2nd element (at index 1) from the record 
mydict[record[1]] = record[:1] + record[2:] 

Bien que des cris pratiquement une expression de générateur si vous voulez tout le tralala à la fois

mydict = dict((record[1], record[:1] + record[2:] for record in cursor.fetchall()) 

qui devrait vous donner tous les dossiers emballés soigneusement dans un dictionnaire, en utilisant le nom comme une clé.

HTH

+0

1. c'est 'has_key' 2. c'est déprécié, utilisez' key in d' – SilentGhost

+0

+1 pour le code lié à la base de données. Merci – morpheous

+0

clé en d est nouveau - n'avait pas entendu, merci pour les heads-up (et j'ai réparé cette partie). @morpheous: n/p - comme je travaille actuellement avec des bases de données dans une langue inconnue, je sais à quel point les exemples de code sont importants! –

2

deux points requis après def s:

def getItemValue(item, key, defval): 
    ... 

opérateurs booléens: En python ! ->not; && ->and et || ->or (voir http://docs.python.org/release/2.5.2/lib/boolean.html pour les opérateurs booléens). Il n'y a pas d'opérateur ? : en python, il y a une expression return (x) if (x) else (x) bien que personnellement je l'utilise rarement en faveur de if.

booléens/None:True, False et None ont capitales avant eux.

Vérification des types d'arguments: En règle générale, vous ne déclarez pas les types de paramètres de fonction dans python. Vous pourriez aller par exemple assert isinstance(item, dict), "dicts must be passed as the first parameter!" dans la fonction bien que ce genre de "vérification stricte" soit souvent déconseillé car ce n'est pas toujours nécessaire en python.

mots-clés python:default n'est pas une réservée python keyword et est acceptable comme arguments et les variables

directives de style (juste pour la référence.):PEP 8 (la ligne directrice de style python) indique que le module import s ne devrait généralement être qu'un par ligne, bien qu'il y ait quelques exceptions (je dois admettre que je ne suis pas souvent le import sys et le os sur des lignes séparées, bien que je le suive habituellement autrement.)

les modes ouverts de fichier:rt n'est pas valide dans python 2.x - cela fonctionnera, bien que le t sera ignoré. Voir aussi http://docs.python.org/tutorial/inputoutput.html#reading-and-writing-files. Il est valid dans Python 3, donc je ne pense pas que ça ferait mal si vous voulez forcer le mode texte, en levant des exceptions sur les caractères binaires (utilisez rb si vous voulez lire des caractères non ASCII.)

travailler avec les dictionnaires: Python utilisé pour utiliser dict.has_key(key) mais vous devez utiliser key in dict maintenant (qui a largement remplacé, voir http://docs.python.org/library/stdtypes.html#mapping-types-dict.)

extensions de fichier split:code = infile[0:-4] pourrait être remplacé par code = os.path.splitext(infile)[0] (qui renvoie par exemple ('root', '.ext') avec le point dans l'extension (voir http://docs.python.org/library/os.path.html#os.path.splitext).

EDIT: a supprimé plusieurs déclarations de variables sur une seule ligne et ajouté une mise en forme. Corrigé aussi le rt n'est pas un mode valide en python quand il est en python 3.

+0

il passe le nom du répertoire, il n'a rien à voir avec 'sys.argv [0]' – SilentGhost

+0

Il est parfaitement bien de déclarer des variables dans une seule ligne – SilentGhost

+0

@SilentGhost: Modifié, merci pour les suggestions! – cryo

Questions connexes