2
votes

I'm converting perl script to python.
I haven't used perl language before so many things in perl confused me.
For example, below, opt was declared as a scalar first but declared again as a hash. %opt = ();
Is it possible to declare a scalar and a hash with the same name in perl?

As I know, foreach $opt (@opts) means that scalar opt gets values of array opts one by one.
opt is an array at this time???
In addition, what does $opt{$opt} mean?
opt outside $opt{$opt} is a hash and opt inside $opt{$opt} is a scalar?
I'm so confused, please help me ...

sub ParseOptions
{
    local (@optval) = @_;
    local ($opt, @opts, %valFollows, @newargs);

    while (@optval) {
        $opt = shift(@optval);
        push(@opts,$opt);
        $valFollows{$opt} = shift(@optval);
    }

    @optArgs = ();
    %opt = ();

    arg: while (defined($arg = shift(@ARGV))) {
        foreach $opt (@opts) {
            if ($arg eq $opt) {
                push(@optArgs, $arg);
                if ($valFollows{$opt}) {
                    if (@ARGV == 0) {
                        &Usage();
                    }
                    $opt{$opt} = shift(@ARGV);
                    push(@optArgs, $opt{$opt});
                } else {
                    $opt{$opt} = 1;
                }
                next arg;
            }
        }
        push(@newargs,$arg);
    }

    @ARGV = @newargs;
}
2

2 Answers

7
votes

In Perl types SCALAR, ARRAY, and HASH are distinguished by the leading sigil in the variable name, $, @, and % respectively, but otherwise they may bear the same name. So $var and @var and %var are, other than belonging to the same *var typeglob, completely distinct variables.

A key for a hash must be a scalar, let's call it $key. A value in a hash must also be a scalar, and the one corresponding to $key in the hash %h is $h{$key}, the leading $ indicating that this is now a scalar. Much like an element of an array is a scalar, thus $ary[$index].

In foreach $var (@ary) the scalar $var does not really "get values" of array elements but rather aliases them. So if you change it in the loop you change the element of the array.

(Note, you have the array @opts, not @opt.)


A few comments on the code, in the light of common practices in modern Perl

  • One must always have use warnings; on top. The other one that is a must is use strict, as it enforces declaration of variables with my (or our), promoting all kinds of good behavior. This restricts the scope of lexical (my) variables to the nearest block enclosing the declaration

  • A declaration may be done inside loops as well, allowing while (my $var = EXPR) {} and foreach my $var (LIST) {}, and then $var is scoped to the loop's block (and is also usable in the rest of the condition)

  • The local is a different beast altogether, and in this code those should be my instead

  • Loop labels like arg: are commonly typed in block capitals

  • The & in front of a function name has rather particular meanings and is rarely needed. It is almost certainly not needed in this code

  • Assignment of empty list like my @optArgs = () when the variable is declared (with my) is unneeded and has no effect (with a global @name it may be needed to clear it from higher scope)

  • In this code there is no need to introduce variables first since they are global and thus created the first time they are used, much like in Python – Unless they are used outside of this sub, in which case they may need to be cleared. That's the thing with globals, they radiate throughout all code

Except for the last two these are unrelated to your Python translation task, for this script.


 It suppresses prototypes; informs interpreter (at runtime) that it's a subroutine and not a "bareword", if it hasn't been already defined (can do that with () after the name); ensures that the user-defined sub is called, if there is a builtin of the same name; passes the caller's @_ (when without parens, &name); in goto &name and defined ... see, for example, this post and this post

-2
votes

First, to make it clear, in perl, as in shell, you could surround variable names in curly brackets {} : ${bimbo} and $bimbo are the same scalar variable.

@bimbo is an array pointer ; %bimbo is a hash pointer ; $bimbo is a scalar (unique value).

To address an array or hash value, you will have to use the '$' : $bimbo{'index'} is the 'index' value of hash %bimbo. If $i contains an int, such as 1 for instance, $bimbo[$i] is the second value of the array @bimbo.

So, as you can see, @ or % ALWAYS refers to the whole array, as $bimbo{} or $bimbo[] refers to any value of the hash or array.

${bimbo[4]} refers to the 5th value of the array @bimbo ; %{bimbo{'index'}} refers to the 'index' value of array %bimbo.

Yes, all those structures could have the same name. This is one of the obvious syntax of perl.

And, euhm… always think in perl as a C++ edulcored syntax, it is simplified, but it is C.