I'm not sure, if I understand your problem correctly...

but if your problem is the terminal width, then you can change the default terminal width from 80 to 132 (Edit --> Window Size) or simply, you use for example PuTTY. Sometimes my PuTTY starts on the left monitor and goes over to the second monitor, so I can see  long lines in its entirety.

Of course, my loop is a little bit too short ;-(  the correct one is

ClassMethod Merge(obj...) {
   set res=obj(1)
   do res.%Remove("NextCursor")
   for i=2:1:obj {
      for j=0:1:obj(i).OptOuts.%Size()-1 do res.OptOuts.%Push(obj(i).OptOuts.%Get(j))
   }
   quit res
}

 Sorry, it seems, a telephone call and writing  does not go together.

Sorry to say, but your comparsion has some sore points:

a) The very first mistake is, you are comparing programing languages!
This is a disputable attempt because each programing language was created with a specific aim (i.e. use case) in mind. So there are very few languages which can be compared to each other. ObjecStript was created as an Operating-System-and-Database-and-Programing-Language. Nowdays, it's a Database-and-Programming-Language. Python is just a programming language! 

b) The second mistake is, comparing methods with the same name (one may think, they do the same thing) but they have different internal behaviour.

Your Python code reads one line from the file (i.e. characters until the next LF):   
  

line = file.readline()

but your ObjecScript code:

set strBuffer = FileReader.ReadLine(.len, .tSC, .eol)

reads a chunk of data from a stream and tries to extract a line from this chunk (take a look at the source code!). Here you loose (probably) most of the time. 
   
The more comparable statement should have been:

read strBuffer

assuming, the file was opened as   

open filename:"R":0

c) Apart from OS, CPU and Disk (HDD, SSD), where there is no information, did you made both runs under the same buffer state (cold or warm)?

In my opinion you're comparing apples with oranges.

<Nitpicking ON>

For the LAST() function you can also use just an expression:

LAST(y,m)  QUIT $ZDATEH(m=12+y*100+(m#12)+1*100+1,8)-1

<Nitpicking OFF>

By the way, if you are just interested, how many days a month in a given year has, there is a simple formula:

LastDay(y,m)  quit $s(m-2:m\8+m#2+30, 1:y#4=0+28)

In the above formula, it's OK to use short leap year calculation (y#4=0) for contemporary dates (date from 1901 until 2099) else case you have to stick to the long format: (y#4=0)-(y#100=0)+(y#400=0)

As we know, an email can contain one or more attached email(s), which in turn can contain other attached mails ... so we have to work recursively until the end. The following program excerpt should show the concept:

ClassMethod GetMails(popAddr, popUser, popPass)
{
   set pop=##class(%Net.POP3).%New(), cnt=0
   if pop.Connect(popAddr, popUser, popPass) {
      if pop.GetMailBoxStatus(.cnt,.siz) {
         for id=1:1:cnt {
            if pop.Fetch(id,.msg,0) do ..getParts(pop,msg,id,0)
         }
      }
   }
}

ClassMethod getParts(pop, msg, id, lev)
{
   for i=1:1:msg.Parts.Count() {
      set part=msg.Parts.GetAt(i)
      set typ=$zcvt(part.CntentType,"l")
      set dsp=part.Headers.GetAt("content-disposition")
      
      if typ["message/rfc822" {
         // this is another email, we step one level deeper
         if pop.GetAttachedEmail(msg.Parts.GetAt(i), .new) do ..getParts(pop, new, id, lev+1)
         
      } elseif dsp["attachment" {
         // attachments
         if typ["application/pdf" {
         } elseif typ["image" {
         } elseif ... {
         }
      } elseif typ["text" {
      } elseif ... {
      }
   }
}

You could create an abstract class, which adds all the information you need to your class(es), see the example below.
Then include this class into the class(es) where you need this kind of information:

Class Your.Class Extends (%Persistent, DC.ClassInfo)  { ... }
Class Your.OtherClass Extends (%Persistent, DC.ClassInfo) { ... }

and use it as follows:

set allProps = ##class(Your.Class).PropertyInfo()
write allProps.%ToJSON() --> [prop1, prop2, ...]  // here you get the names of all properties
set oneProp = ##class(Your.Class).PropertyInfo("aPropertyName") --> {"Type":"%String"} // Info about one property

The same goes for the methods too.

Class definition for the (example) DC.ClassInfo class:

Class DC.ClassInfo [ Abstract ]
{
/// Return information about properties
/// 
/// 1) return list of all properties
///        obj.PropertyInfo() --> [Propertynam1, Propertyname2, Propertyname3, ...]
/// 
/// 2) return info for a specific property
///    obj.PropertyInfo(propertyname) --> {"Type":type, "MaxLen":nn, "Scale":n, ...}
///    
ClassMethod PropertyInfo(name = "") As %DynamicObject [ CodeMode = objectgenerator ]
{
    set prp=%compiledclass.Properties, all={}

    for i=1:1:prp.Count() {
        set p=prp.GetAt(i), inf={}
        // Add all the infos you need...
        set inf.Type=p.Type
        set x=p.Parameters.GetAt("MAXLEN") set:x]"" inf.MaxLen=x
        set x=p.Parameters.GetAt("SCALE") set:x]"" inf.Scale=x
        do all.%Set(p.Name,inf)
    }
    
    do %code.WriteLine($c(9)_"set prp="_all.%ToJSON())
    do %code.WriteLine($c(9)_"if name]"""" quit prp.%Get(name)")
    do %code.WriteLine($c(9)_"set itr=prp.%GetIterator(), names=[]")
    do %code.WriteLine($c(9)_"while itr.%GetNext(.k) { do names.%Push(k) }")
    do %code.WriteLine($c(9)_"quit names")
    quit $$$OK
}

/// Return information about properties
/// 
/// 1) return list of all properties
///        obj.PropertyInfo() --> [Propertynam1, Propertyname2, Propertyname3, ...]
/// 
/// 2) return info for a specific property
///    obj.PropertyInfo(propertyname) --> {"Type":type, "MaxLen":nn, "Scale":n, ...}
///    
ClassMethod MethodInfo(name = "") As %DynamicObject [ CodeMode = objectgenerator ]
{
    set mth=%compiledclass.Methods, all={}
    
    for i=1:1:mth.Count() {
        set m=mth.GetAt(i)
        // Add all the infos you need...            
        set inf={}, spc=m.FormalSpecParsed
        set inf.SqlProc=m.SqlProc            
        set inf.ClassMethod=m.ClassMethod
        set inf.ReturnType=m.ReturnType
        set inf.Args=[]
        for j=1:1:$ll(spc) {
            set arg={}, itm=$li(spc,j), arg.Name=$li(itm), arg.Type=$li(itm,2)
            set arg.ByRef=$li(itm,3)="&", arg.DefValue=$li(itm,4)
            do inf.Args.%Push(arg)
        }
        do all.%Set(m.Name,inf)
    }
    
    do %code.WriteLine($c(9)_"set mth="_all.%ToJSON())
    do %code.WriteLine($c(9)_"if name]"""" quit mth.%Get(name)")
    do %code.WriteLine($c(9)_"set itr=mth.%GetIterator(), names=[]")
    do %code.WriteLine($c(9)_"while itr.%GetNext(.k) { do names.%Push(k) }")
    do %code.WriteLine($c(9)_"quit names")
    quit $$$OK
}
}

The class should work, but it's only partially tested. Also, you may want to omit all the inherited properties and methods

set p=prp.GetAt(i)  continue:p.Origin '= %class.Name // skip inherited propps
set m=mth.GetAt(i) continue:m.Origin '= %class.Name // skip inherited methods

it's up to you. Also you can add other informations, depending on your needs, see the respective classes (%Dictionary.CompiledClass, %Dictionary.CompiledProperties and %Dictionary.CompiledMethods)

You are on a right way, but obviously you use indirection on local variables in block environment.

the wrong way:

Method testErr()
{
   set myvar(1)=123, ref=$na(myvar)
   set ref=$query(@ref)  -->  this gives you always: ref=""
}

The correct way

Method testOK() [ PublicList = myvar]
{
   new myvar
   set myvar(1)=123, ref=$name(myvar)
   set ref=$query(@ref) 
   write ref," ",@ref ---> myvar(1)," ",123
}

i.e. indirection needs variables with global scope

First, resetting a password means, the user gets a new password, in your use case, this is not an option.

Second, if you want (for whatever reason)  to validate the user in some stage of the application, then you must calculate the PBKDF2 from useres input (the password) and from (the stored) salt. The hash you get should be equal to the hash, storted in the database. PBKDF2 is a one way salted password hash.

By the way, you have to care about not to transfer the users (clear text) input to your computation over an unsecure way!

I think, the $zconvert() function will cover only the necessary entities. But you can use a simple method to convert characters to currently known(*) entities.

ClassMethod ToHTML(str)
{
   for i=$length(str):-1:1 set c=$ascii(str,i) set:$data(^entityChars(0,c),c) $extract(str,i)=c
   quit str
}

ClassMethod FromHTML(str)
{
   set i=0
   while $locate(str,"&[A-Za-z]+;",i,j,v) {
   set:$data(^entityChars(1,v),c) s=$length(v), $extract(str,j-s,j-1)=$c(c), j=j-s+1
   set i=j
   }
   quit str
}

I have a table (the ^entityChars() global) which contains more the 1400 entities. You can download the above class, together with the table from my FTP server (File: DC.Entity.xml):

Adr: ftp.kavay.at
Usr: dcmember
Psw: member-of-DC

A sample output:

USER>write ##class(DC.Entity).ToHTML("Flávio Lúcio Naves Júnior")
Fl&aacute;vio L&uacute;cio Naves J&uacute;nior
USER>write ##class(DC.Entity).FromHTML("Fl&aacute;vio L&uacute;cio Naves J&uacute;nior")
Flávio Lúcio Naves Júnior

(*) Currently known, because (1) I do not have all the currently known entities in my table and (2) with each new day, the W3C and the Unicode consortium can extend the current entity list.

With the global name lengths, there are two pitfalls,

- first, names could have arbitrary lengths, but only the first 31 characters are considered, but this was already mentioned  (Roger Merchberger)

- second, a global name can contain a period ("."), but the first (after the caret) or the last character must not be a period, where at "last" means, the period may not appear at the position 31.

The following short test shows this.

set glb="^abcdefghijklmnopqrstuvwxyz1234ABCDE.FG", @glb="myTest"
for i=37:-1:30 set $extract(glb,i-1,i)="."_$e(glb,i-1) try { write i,?4,glb," " write:$d(@glb)!1 $zr," ",$get(@glb),! } catch e { write e.Name,! }

the output is:

37  ^abcdefghijklmnopqrstuvwxyz1234ABCD.EFG ^abcdefghijklmnopqrstuvwxyz1234A myTest
36  ^abcdefghijklmnopqrstuvwxyz1234ABC.DEFG ^abcdefghijklmnopqrstuvwxyz1234A myTest
35  ^abcdefghijklmnopqrstuvwxyz1234AB.CDEFG ^abcdefghijklmnopqrstuvwxyz1234A myTest
34  ^abcdefghijklmnopqrstuvwxyz1234A.BCDEFG ^abcdefghijklmnopqrstuvwxyz1234A myTest
33  ^abcdefghijklmnopqrstuvwxyz1234.ABCDEFG <SYNTAX>
32  ^abcdefghijklmnopqrstuvwxyz123.4ABCDEFG ^abcdefghijklmnopqrstuvwxyz123.4
31  ^abcdefghijklmnopqrstuvwxyz12.34ABCDEFG ^abcdefghijklmnopqrstuvwxyz12.34
30  ^abcdefghijklmnopqrstuvwxyz1.234ABCDEFG ^abcdefghijklmnopqrstuvwxyz1.234

i = 34..37:  always the same global (^abcdefghijklmnopqrstuvwxyz1234A) hence, the same content

i = 33: the last character is a period, hence a syntax error

i = 30..32: different globals,

and the global name length is always 31 characters long.

By the way, if you start this example with

set glb = $name(^abcdefghijklmnopqrstuvwxyz1234ABCDE.FG)

which is the preferred method over 

set glb="^abcdefghijklmnopqrstuvwxyz1234ABCDE.FG"

the you end up with a cropped value in glb

^abcdefghijklmnopqrstuvwxyz1234A

This is not so simple because parts of a namespace could be mapped in more then one database.

But take a look at the %SYS.Namespace class:

do ##class(%SYS.Namespace).GetAllNSInfo("Namespace", .info)

write ##class(%SYS.Namespace).GetGlobalDest(,"aGlobalname")  // gives you the global database for a specific global

write ##class(%SYS.Namespace).GetRoutineDest(,"aRoutinename")  // gives you the global database specific routine