Unify 2 functions to read files with python

2

Since some time ago I am trying to make a bash simulator using python, I am creating the tail and head commands, for this create 2 functions:

def head(textfile):
    content = []
    try:
        file = open(textfile, "r")
        for line in file:
            content.append(line)
    except:
        print("[*] Error: No se ha podido abrir el archivo '{}'".format(textfile))
    else:
        for string in content[:5]:
            print(string)

def tail(textfile):
    content = []
    try:
        file = open(textfile, "r")
        for line in file:
            content.append(line)
    except:
        print("[*] Error: No se ha podido abrir el archivo '{}'".format(textfile))
    else:
        for string in content[len(content) - 5:]:
            print(string)

The 2 functions are exaggeratedly similar, in fact they only change in one value:

for string in content[len(content) - 5:]:
# aquí el ':' está a la derecha

and

for string in content[:5]:
# y aquí el ':' está a la izquierda

I thought about changing that value to a parameter, but the ':' is set in different places (if I can not explain well read the comments in the code above) it bothers me to repeat code so: what is it that Can I do to have a single function?

    
asked by binario_newbie 28.05.2018 в 21:09
source

2 answers

1

The problem of your self-answer is that for the "tail" case it will not work correctly, since in your second example, what will execute your function will be in the background:

for string in content[-5:-1]:
    print(string)

and that will not print the last line, since in a slice the final element is excluded.

The only way to be able to print the last 5 elements of the list is to use content[-5:] , that is, omit the end. But how to achieve that?

Python has the primitive slice() that allows you to create "slices" using an alternative syntax. The disadvantage is that it is not the family syntax [inicio:fin:paso] , but slice(inicio, fin, paso) . The advantage is that this syntax can be passed as a parameter.

Using this trick:

def headtail(textfile, trozo):
    content = []
    try:
        file = open(textfile, "r")
        for line in file:
            content.append(line)
    except:
        print("[*] Error: No se ha podido abrir el archivo '{}'".format(textfile))
    else:
        for string in content[trozo]:
            print(string)

And the bad thing is the invocation, which is strange. To head:

headtail(file, slice(0,5))

To tail:

headtail(file, slice(-5, None))

If you want a slightly more friendly syntax, you can use this other trick , to generate slice() from a syntax "in brackets":

class HazSlice(object):
  def __getitem__(self, item):
    return item

trozo = HazSlice()

# Cabeza
headtail(file, trozo[:5])

# Tail
headtail(file, trozo[-5:])
    
answered by 28.05.2018 / 23:46
source
2

I already have the solution, I was going to delete the publication but leave the answer in case someone serves: send 2 new parameters the "minim" and maxim "function" it would look something like this:

def headtail(textfile, minim, maxim):
    content = []
    try:
        file = open(textfile, "r")
        for line in file:
            content.append(line)
    except:
        print("[*] Error: No se ha podido abrir el archivo '{}'".format(textfile))
    else:
        for string in content[minim:maxim]:
            print(string)

When you want to activate head you do it this way:

headtail(file,0,5)

and for tail like this:

headtail(file,-5,-1)
    
answered by 28.05.2018 в 22:01