השוואת פיתרונות קורס Python

בעבודה עם שורת הפקודה יותר מהר לכתוב את הפקודה השלמה בשורה אחת (כך יותר קל להעתיק ולהדביק, או ללחוץ חץ למעלה כדי להפעיל שוב). כלומר נרצה להפעיל:

$ python touch.py file1.txt file2.txt

כדי ליצור את שני הקבצים

אוקיי, עמלתי על אחד חדש והרי התוצאה:

import sys

n_file = 0
file_ = 0

if len(sys.argv) > 1:
    n_file = len(sys.argv)
    for i in range(1,n_file):
        file_ = sys.argv[i]
        path = r"C:\Python\modules_2\%s" % file_
        new_file = open (path,"w")

כיוון טוב יותר יהיה לרוץ על הרשימה (במקום על האינדקסים). במילים אחרות:

for filename in sys.argv[1:]:
  ...
import sys

file_ = 0
if len(sys.argv) > 1:
    for i in sys.argv[1:]:
        file_ = i
        path = r"C:\Python\modules_2\%s" % file_
        new_file = open (path,"w")

סתם מתוך סקרנות, למה עדיף לרוץ על הרשימה ולא על האינדקסים?

גדול. נשאר רק לוודא שהקובץ לא קיים כדי לא למחחק אותו. דרך קלה לעשות את זה היא לפתוח את הקובץ עם האות a בפרמטר השני (במקום w). האות a אומרת להוסיף לקובץ ולכן היא לא תמחק אם כבר קיים.

לשאלה שלך-

קוד מספר סיפור. סגנון הכתיבה עוזר למי שקורא להבין מה חשוב ומה לא חשוב. כשאתה כותב פרטים מיותרים אתה מבלבל את מי שקורא את הקוד ויותר קשה להתמקד במה התוכנית עושה.

במקרה שלך הבחירה בשם משתנה i (בתוכנית החדשה) היא מטעה. כי i נותן הרגשה של אינדקס שרץ על מספרים. גם השמירה למשתנה בשם file_ מיותרת ומבלבלת.
מאותה סיבה לולאה על אינדקסים היא מטעה כאן כי היא רומזת שאולי יש חשיבות למספר הקובץ (לאינדקס) ופה אין.

לכן הדבר הכי נכון זה לרוץ על הפריטים עצמם ולבחור שם משתנה רץ שיספר את זה למשל:

for filename in sys.argv[1:]:
  f = open(filename, 'a')
  f.close()

בצורה כזו מי שקורא מיד מבין שמדובר בלולאה שמצפה לקבל שמות קבצים. שים לב שגם לא נהוג להוסיף שם תיקיה בתוכנית כזו כי אולי משתמשים ירצו ליצור את הקבצים בתיקיה אחרת. תן למשתמשים שמזינים שמות קבצים לבחור את התיקיות בעצמם.

ראשית תודה על ההסבר המפורט !
החלפתי את הכל בקובץ הבא:

import sys

for filename in sys.argv[1:]:

    f = open(filename, 'a')
    f.close()

זה אכן עובד , אך לא הבנתי :
א. איך זה שלמרות שלא נתתי path הקובץ נפתח במקום הנכון…
ב. כיוון שהוא נפתח בנתיב אליו התכוונתי, זה אומר שהוא כבר נמצא בתיקיה מסויימת. כלומר המשתמש לא בחר
את שם התיקיה כפי שציינת
ג. האם תוכל להרחיב טיפה על ()f.close אני מבין שמדובר בסגירת התיקיה

הי ינון,
שלחתי אתמול את הפתרון לתרגיל מס’ 1 בנושא מודולים.
אני מאמין שבשטף ההתכתבויות לא שמת לב אליו. אשמח לפידבק.
בנוסף , אני עובד כעת על תרגיל 2 ונתקל בבעיות:
בהתחלה ניסיתי לרוץ על הרשימה של sys.argv ולהפוך כל ארגומנט ל integer

for num in (sys.argv[1:]):
    int(sys.argv[num])

כשהרצתי זאת, קיבלתי את הודעת השגיאה הבאה:

list indices must be integers, not str

שיניתי את הכיוון ורצתי על האינדקסים במקום על הרשימה:


number = len(sys.argv)

for num in (1,number):
    int(sys.argv[num])

ואז קיבלתי את הודעת השגיאה הבאה:

list index out of range

ניסיתי לדבג באמצעות mpdb - אבל לא הבנתי מתי אני צריך להזין נתונים (כדי לראות ע"י הפקודה p number מה הערך של number )
אשמח לעזרה
תודה , עמיר

הי עמיר,

אנסה לענות על שתי ההודעות ברצף:

  1. למערכת ההפעלה יש ״תיקיה נוכחית״. זו התיקיה ממנה אתה מריץ את התוכנית. פתיחת קבצים ללא ציון תיקיה מתיחסת לתיקיה הנוכחית.

  2. משתמש יכול לבחור תיקיה אחרת! למשל נסה הפעלה כזו:

python touch.py C:\demo.txt

ואז הקובץ יווצר בתיקיה הראשית.

  1. בטח- פתיחת קובץ היא פעולה שבה התוכנית מבקשת ממערכת ההפעלה מעין ״צינור״ דרכו אפשר לקרוא או לכתוב לקובץ. כל צינור כזה תופס זיכרון ומספר הצינורות שתוכנית יכולה להחזיק בכל רגע נתון מוגבל. הפקודה close מחזירה את ה״צינור״ למערכת ההפעלה וכך מפנה את המשאבים.

כשאתה כותב:

with open('file.txt', 'r') as f:
  pass
  1. בטח ראיתי. אפילו לחצתי לייק (זה האייקון של הלב). אני עושה את זה כשהפיתרון טוב ואין לי מה להוסיף.

  2. נדמה לי ששתי הלולאות שלך לא מדויקות. לדבג לא יעזור לך כאן תסתכל שוב על הקוד ותשווה לדוגמאות קודמות של לולאות שכתבת וחפש את ההבדלים.

פייתון יפעיל את הפקודה close אוטומטית בסיום הבלוק שבתוך ה with.

הי,
עברתי לתוכנית שונה (בלי לולאה):

import sys

if len(sys.argv) == 3:

    num1 = int(sys.argv[1])
    num2 = int(sys.argv[2])
    sum = num1 + num2
    print sum
else:
    print"Usage: %s <num1><num2>" % sys.argv[0]
    sys.exit(1)

עד כאן זה עובד .
כשניסיתי להוסיף תנאי במקרה והוכנסו ערכים שלא ניתנים להמרה - זה לא עבד טוב:

import sys

if len(sys.argv) == 3:
    if not isinstance(sys.argv[1],int) or  not isinstance(sys.argv[2],int):
        print "Please enter number only "
        sys.exit()
        
    num1 = int(sys.argv[1])
    num2 = int(sys.argv[2])
    sum = num1 + num2
    print sum

else:
    print"Usage: %s <num1><num2>" % sys.argv[0]
    sys.exit(1)

כן ברור-

הערכים ב sys.argv הם באמת לא מסוג int ולכן זה לא יעבוד. נסה את זה:

>>> type(10)
<type 'int'>
>>> type('10')
<type 'str'>
>>> type('ten')
<type 'str'>

מה שאתה רוצה לבדוק זה לא אם הערך הוא כרגע int (כי הוא לא), אלא אם אפשר להמיר אותו ל int. בשביל זה תצטרך לדלג קדימה לשיעור על Exceptions:
https://www.tocode.co.il/bundles/python/lessons/exceptions

דרך אחרת

import sys

if len(sys.argv) != 3:
    print "Usage: %s <num1> <num2>" % sys.argv[0]
    sys.exit(1)

if not (sys.argv[1].isdigit() and sys.argv[2].isdigit()): 
    print "Enter number only"    
    sys.exit(1)

sum = 0
for num in sys.argv[1:]:
    sum += int(num)
print sum

הי,
נסיתי לפתור את תרגיל 3 (הסעיפים הראשונים) בסקריפט הבא:

import os
import sys

#(code_name,path) = sys.argv
for root,dirs,files in os.walk("."):
    for file in files:
        size = os.path.getsize(file) 
        if size > 1024 * 1024:
            print "%s is %d Bytes" % (file,size)  
            print  "Do you want to delete it Y\N? " 
            while True:
                delete = raw_input()
                if delete == 'Y':break
                os.remove(file)
                break

הבעיה שזה עובד רק מהתיקיה הנוכחית.
ברגע שאני מנסה להכניס path שהתוכנית תרוץ עליו זה נותן לי הודעת שגיאה.
אני חושב שזה קשור לפונקציה getsize
תודה

אפשר להעביר את הודעת השגיאה ישירות ל sys.exit-

sys.exit('Enter number only')

וזה חוסך את ה print.

לגבי השאלה שלך- תתחיל עם להוסיף הודעת הדפסה לפני הקריאה ל os.path.getsize ותראה מה אתה מעביר לפונקציה זו. בשביל ש os.path.getsize יעבוד גם על קבצים מתיקיות פנימיות שים לב שאתה צריך להעביר גם את שם התיקיה הפנימית (ואני לא בטוח שזה קורה בקוד שלך)

כן אבל כל הרעיון בתוכנית זה שאני מעביר path שיש בו תיקיות וקבצים והתוכנית בודקת האם הקובץ אכן גדול מ 1M ורק אז מחליטה להציג זאת למשתמש ולשאול אותו מה הוא רוצה לעשות עם זה. לכן לא הגיוני לכתוב את שם הקובץ ב path כי בשלב זה אני לא יודע מה גודלו - זה בדיוק תפקיד התוכנית !
לקחתי path שיש בו רק קבצים, מגדלים שונים (חלקם מעל 1M)
בנוסף, אם תסתכל תראה שהוספתי בקוד לעיל הודעת הדפסה של שם וגודל הקובץ והתוכנית אכן מדפיסה את שם הקובץ. אבל היא עובדת כראוי רק כאשר ב os.walk יש (".")
ברגע שבמקום (".") יש path
יש את הודעת השגיאה הבאה:

C:\Python\modules_2>python targil_3.py
8-9.2017.pdf
Traceback (most recent call last):
  File "targil_3.py", line 8, in <module>
    size = os.path.getsize(file)
  File "C:\Python27\lib\genericpath.py", line 57, in getsize
    return os.stat(filename).st_size
WindowsError: [Error 2] The system cannot find the file specified: '8-9.2017.pdf'

לא הבנת אותי…

התוכנית תקבל את ה path עם התיקיות והקבצים ותתחיל לסרוק ממנו,
ובשביל הדוגמא בוא נניח שאתה מעביר לה את . כלומר את התיקיה הנוכחית,
עכשיו בוא נניח שהיא הגיעה לתיקיה בשם hello ובתוכה יש קובץ שנקרא world.txt
(כי בתוך התיקיה הנוכחית יש לך תיקיה בשם hello ובתוכה הקובץ)

בשביל לקבל את הגודל תצטרך להפעיל:

os.path.getsize('hello/world.txt')

כי אתה מפעיל את התוכנית מהתיקיה הנוכחית ״.״ אבל הקובץ world.txt אינו נמצא בתיקיה הנוכחית אלא בתת תיקיה בשם hello.

עכשיו נסה את התוכנית שלך על התרחיש שתיארתי ותוסיף הודעת הדפסה לפני הקריאה ל os.path.getsize. תראה אם אתה באמת מעביר לה את המידע שהיא צריכה

הי ינון,
אני מגיש את הפתרון שלי לתרגיל 3 במודולים
שבת שלום וסופ"ש נעים

import os
import sys
import argparse

parser = argparse.ArgumentParser()
parser.add_argument("--path",help = "your path" )
parser.add_argument("--size",type = int,help = "min_size file regarding erasure (the No is in MB)"  )

args = parser.parse_args()
path = args.path
size = args.size


min_size = args.size * 1024 * 1024

path = "P:\\AmirKreiter\\python"
if len(sys.argv) != 5:
    print "Usage: %s <--path> <path> <--size><size>" % sys.argv[0]
    sys.exit(1)

for root,dirs,files in os.walk(path):
    for f in files:
        path = root + '\\' + f      
        size = os.path.getsize(path)

        if size > min_size:
            print "%s is %d Bytes" % (path,size)  
            print  "Do you want to delete it Y\N?"       
            delete = raw_input()
            if delete == 'Y':
                os.remove(path)

הי,
התחלה טובה, אבל לא הבנתי למה צריך להגדיר path קבוע ואחרי זה לדרוס אותו עם הפרמטר.

דבר נוסף עדיף לכתוב את כל הודעת השגיאה ישירות בתוך sys.exit למשל:

sys.exit('Usage: %s <--path> <path> <--size><size>" % sys.argv[0]')

שמח שהצלחת למצוא את הבעיה עם os.path.getsize ושאר הקוד נראה אחלה!

לייק 1

הי ערב טוב,
לגבי תרגיל 1 בקבצים, בבונוס 2 מבקשים שהתוכנית תתמוך במס’ קבצים כאשר תוכנם יתווסף לקובץ האחרון. איך זה משתלב עם הבונוס הראשון (לגבי הודעת שגיאה אם אין את הקובץ הראשון)

הי,

לא בטוח שהבנתי את הבעיה-

  1. אם הקובץ הראשון לא קיים יש לזרוק הודעת שגיאה

  2. אם הועברו לתוכנית 4 קבצים והקובץ הראשון כן קיים אז תוכן ה-3 הבאים ייכתב לסוף הקובץ הראשון (אם הוא לא קיים עדיין תופיע השגיאה)

אוקיי אבל בהוראות של התרגיל כתבת הפוך:" הוסיפו תמיכה במספר קבצים כך שההפעלה הבאה תעתיק את הקבצים file1.txt ו file2.txt לפי הסדר לסוף הקובץ file3.txt " כלומר אני מבין שהקובץ (file3.txt ) האחרון יכיל את תוכן הקבצים שבאו לפניו ולא שהקובץ הראשון (file1.txt) יכיל את כל מה שבא אחריו. לכן לא הבנתי מדוע צריך הודעת שגיאה דווקא על הקובץ הראשון.