Python Concepts/Built-in Functions


Objective

edit
 

Page Index

edit

Lesson

edit

The Python interpreter has a number of functions and types built into it that are always available. This means that you don't have to import anything so that you can access them. Some of the built-in functions are so powerful, simple, common or useful, such as print() that it's difficult to imagine a block of code without them. As we have advanced through this course, we've seen and used many built-in functions (bin(), chr(), complex(), dict(), format(), hex(), input()) perhaps without realizing that they have their own place and classification in the Python documentation.

class range(start,stop[,step])

edit

In the python documentation the range() type is included under "Built-in Functions." However, range() is actually an immutable sequence type similar to lists and tuples. Conceptually range() is similar to a tuple containing a well-defined sequence of values. Both the sequence and the values may be huge, but range() occupies only a small amount of memory and it is very fast.

Of the three arguments stop must be included. If start is not included, it defaults to   If step is not included, it defaults to  

>>> list (range(4))
[0, 1, 2, 3] # 'stop' is not included in the range.
>>> 
>>> list (range(4,9))
[4, 5, 6, 7, 8]
>>> 
>>> list (range(4,37,7))
[4, 11, 18, 25, 32]
>>> 
>>> tuple(range(3,-7,-2))
(3, 1, -1, -3, -5)
>>> 
>>> tuple(range(3,-7,0))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: range() arg 3 must not be zero
>>> 
>>> tuple(range(3,-7,4))
() # Empty range.
>>>

range() supports indexing.

>>> range(-2,29,5)[2:5]
range(8, 23, 5)
>>> 
>>> range(-2,29,5)[2:5][:2]
range(8, 18, 5)
>>> 
>>> range(-2,29,5)[17]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
IndexError: range object index out of range
>>> range(-2,29,5)[2]
8
>>> range(-2,29,5)[-1]
28
>>>

An operation on range() may return True or False.

>>> 6 in range(-17,193 , 7)
False
>>> 4 in range(-17, 193 , 7)
True
>>>

Try it with big numbers.

>>> 100_000_000_000_000 in range ( -5_123_456_789, 1_000_000_000_000_000, 7 )
False
>>> 100_000_000_000_001 in range ( -5_123_456_789, 1_000_000_000_000_000, 7 )
False
>>> 100_000_000_000_002 in range ( -5_123_456_789, 1_000_000_000_000_000, 7 )
True
>>> 
>>> len(range ( -5_123_456_789, 1_000_000_000_000_000_456_789_123, 789_012_456 ))
1267407114292763
>>> 
>>> len(range ( 5_123_456_789, -1_000_000_000_000_000_456_789_123, -789_012_456 ))
1267407114292763
>>> 
>>> a,b,c =  5_123_456_789, -1_000_000_000_000_000_456_789_123, -789_012_456
>>> d,e,f = 407114292763 , 267407114292763 , 674071142
>>> range(a,b,c)[d:e:f]
range(-321218248000514199139, -210987544000000514199139, -531850527268144752)
>>> len(range(a,b,c)[d:e:f])
396_101
>>> range(a,b,c)[d:e:f][763::2345][-3]
-207760474949976816255955
>>> 
>>>  # and it's very fast.

globals()

edit

This expression has the appearance of a function but it returns and behaves like a dictionary representing the current global symbol table.

Invoke python on Unix and display information about globals():

$ python3.6
Python 3.6.3 (v3.6.3:2c5fed86e0, Oct  3 2017, 00:32:08) 
[GCC 4.2.1 (Apple Inc. build 5666) (dot 3)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> 
>>> type(globals())
<class 'dict'>
>>> 
>>> globals()
{
'__name__'       : '__main__', 
'__doc__'        : None, 
'__package__'    : None, 
'__loader__'     : <class '_frozen_importlib.BuiltinImporter'>, 
'__spec__'       : None, 
'__annotations__': {}, 
'__builtins__'   : <module 'builtins' (built-in)>
}
# Braces '{}' enclose a dictionary.
# Each key '__name__', '__doc__', '__package__' .... is a string.
# Each value '__main__', None, None, .... may or may not be a string. Most values above are not strings.
>>> quit()
$

When you invoke python interactively, the above global variables are predefined. Unless you really know what you are doing, it is recommended that you do not attempt to change any of the predefined global variables.

Python source file tmp1.py:

$ head -3 tmp1.py
# tmp1.py
print ('\n'.join([ ((v + (' '*30))[:20] + str(v1)) for v in globals() for v1 in (globals()[v],) ]))
exit (0)
$

When python is invoked by executing python source file tmp1.py on Unix, the following global variables are predefined:

$ python3.6 tmp1.py
__name__            __main__
__doc__             None
__package__         None
__loader__          <_frozen_importlib_external.SourceFileLoader object at 0x10189e2b0>
__spec__            None
__annotations__     {}
__builtins__        <module 'builtins' (built-in)>
__file__            tmp1.py
__cached__          None
$

The values '__file__', '__cached__' have been added and value '__loader__' has changed.

Within the listcomp above:

  • Variables v, v1 are local to the listcomp and do not appear in the list of global symbols. This is why a listcomp was used.
  • Each value has been converted to str for printing. (Actually so that method '\n'.join(....) will work properly.)

Accessing dictionary globals()

edit
>>> v1 = 6 ; t1 = (1,2,3)
>>> globals()
{
'__name__': '__main__', 
'__doc__': None, 
'__package__': None, 
'__loader__': <class '_frozen_importlib.BuiltinImporter'>, 
'__spec__': None, 
'__annotations__': {}, 
'__builtins__': <module 'builtins' (built-in)>, 
'v1': 6, 
't1': (1, 2, 3)
}
>>> 
>>> v1 in globals()
False
>>> 'v1' in globals() # Each key is a string.
True
>>> 'v2' in globals() # Use this feature to determine whether or not global variable v2 exists.
False
>>> 
>>> s1 = 'v1'
>>> globals()
{
# 7 predefined global variables as above.
'v1': 6, 
't1': (1, 2, 3), 
's1': 'v1'
}
>>> s1 in globals() 
True
>>> globals()[s1]
6
>>> 's1' in globals()
True
>>> globals()['s1']
'v1'
>>>

To delete a global variable:

>>> v3 = [1,2,3]
>>> v3
[1, 2, 3]
>>> del globals()['v3']
>>> v3
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'v3' is not defined
>>>

Creating global variables

edit

During execution of python code global variables that did not exist in the code may be created.

>>> v3
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'v3' is not defined
>>> 
>>> for num in  range (3,7) :
...     s1 = 'v' + str(num)
...     globals()[s1] = num**2
... 
>>> v3
9
>>> 
>>> globals()
{
# 7 predefined variables.
'num': 6, 
's1' : 'v6', 
'v3' : 9, 
'v4' : 16, 
'v5' : 25, 
'v6' : 36
}
>>> 
>>> v3,v4,v5,v6
(9, 16, 25, 36)
>>>

Importing modules

edit
>>> import decimal
>>> globals()
{
# ....
'decimal': <module 'decimal' from '/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/decimal.py'>
}
>>> d1 = Decimal(3)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'Decimal' is not defined
>>> d1 = decimal.Decimal(3);d1
Decimal('3')
>>> D = decimal.Decimal
>>> d2 = D(6);d2
Decimal('6')
>>>

Change syntax of import statement slightly and try again:

>>> from decimal import *
>>> 
>>> globals()
'__name__'            '__main__'
'__doc__'             None
'__package__'         None
'__loader__'          <class '_frozen_importlib.BuiltinImporter'>
'__spec__'            None
'__annotations__'     {}
'__builtins__'        <module 'builtins' (built-in)>
'getcontext'          <built-in function getcontext>
'setcontext'          <built-in function setcontext>
'localcontext'        <built-in function localcontext>
'Decimal'             <class 'decimal.Decimal'>
'Context'             <class 'decimal.Context'>
'DecimalTuple'        <class 'decimal.DecimalTuple'>
'DecimalException'    <class 'decimal.DecimalException'>
'Clamped'             <class 'decimal.Clamped'>
'Rounded'             <class 'decimal.Rounded'>
'Inexact'             <class 'decimal.Inexact'>
'Subnormal'           <class 'decimal.Subnormal'>
'Underflow'           <class 'decimal.Underflow'>
'Overflow'            <class 'decimal.Overflow'>
'DivisionByZero'      <class 'decimal.DivisionByZero'>
'FloatOperation'      <class 'decimal.FloatOperation'>
'InvalidOperation'    <class 'decimal.InvalidOperation'>
'ConversionSyntax'    <class 'decimal.ConversionSyntax'>
'DivisionImpossible'  <class 'decimal.DivisionImpossible'>
'DivisionUndefined'   <class 'decimal.DivisionUndefined'>
'InvalidContext'      <class 'decimal.InvalidContext'>
'DefaultContext'      Context(prec=28, rounding=ROUND_HALF_EVEN, Emin=-999999, Emax=999999, capitals=1, clamp=0, 
                      flags=[], traps=[InvalidOperation, DivisionByZero, Overflow])
'HAVE_THREADS'        True
'BasicContext'        Context(prec=9, rounding=ROUND_HALF_UP, Emin=-999999, Emax=999999, capitals=1, clamp=0, 
                      flags=[], traps=[Clamped, InvalidOperation, DivisionByZero, Overflow, Underflow])
'ExtendedContext'     Context(prec=9, rounding=ROUND_HALF_EVEN, Emin=-999999, Emax=999999, capitals=1, clamp=0, flags=[], traps=[])
'MAX_PREC'            999999999999999999
'MAX_EMAX'            999999999999999999
'MIN_EMIN'            -999999999999999999
'MIN_ETINY'           -1999999999999999997
'ROUND_UP'            'ROUND_UP'
'ROUND_DOWN'          'ROUND_DOWN'
'ROUND_CEILING'       'ROUND_CEILING'
'ROUND_FLOOR'         'ROUND_FLOOR'
'ROUND_HALF_UP'       'ROUND_HALF_UP'
'ROUND_HALF_DOWN'     'ROUND_HALF_DOWN'
'ROUND_HALF_EVEN'     'ROUND_HALF_EVEN'
'ROUND_05UP'          'ROUND_05UP'
>>> 
>>> d1 = Decimal(6); d1 # With this syntax class Decimal is defined as global variable.
Decimal('6')
>>> 
>>> type(globals()['MIN_ETINY'])
<class 'int'>
>>> type(globals()['DefaultContext'])
<class 'decimal.Context'>
>>> type(globals()['DivisionByZero'])
<class 'type'>
>>> 
>>> type(globals()['ROUND_HALF_UP'])
<class 'str'>
>>> globals()['ROUND_HALF_UP'] == 'ROUND_HALF_UP' # In this case key and value are the same.
True
>>>
Printing globals()
edit

To view the contents of globals(), simply enter:

>>> from decimal import *
>>> globals()
{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <class '_frozen_importlib.BuiltinImporter'>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, 'getcontext': <built-in function getcontext>, 'setcontext': <built-in function setcontext>, 'localcontext': <built-in function localcontext>, 'Decimal': <class 'decimal.Decimal'>, 'Context': <class 'decimal.Context'>, 'DecimalTuple': <class 'decimal.DecimalTuple'>, 'DecimalException': <class 'decimal.DecimalException'>, 'Clamped': <class 'decimal.Clamped'>, 'Rounded': <class 'decimal.Rounded'>, 'Inexact': <class 'decimal.Inexact'>, 'Subnormal': <class 'decimal.Subnormal'>, 'Underflow': <class 'decimal.Underflow'>, 'Overflow': <class 'decimal.Overflow'>, 'DivisionByZero': <class 'decimal.DivisionByZero'>, 'FloatOperation': <class 'decimal.FloatOperation'>, 'InvalidOperation': <class 'decimal.InvalidOperation'>, 'ConversionSyntax': <class 'decimal.ConversionSyntax'>, 'DivisionImpossible': <class 'decimal.DivisionImpossible'>, 'DivisionUndefined': <class 'decimal.DivisionUndefined'>, 'InvalidContext': <class 'decimal.InvalidContext'>, 'DefaultContext': Context(prec=28, rounding=ROUND_HALF_EVEN, Emin=-999999, Emax=999999, capitals=1, clamp=0, flags=[], traps=[InvalidOperation, DivisionByZero, Overflow]), 'HAVE_THREADS': True, 'BasicContext': Context(prec=9, rounding=ROUND_HALF_UP, Emin=-999999, Emax=999999, capitals=1, clamp=0, flags=[], traps=[Clamped, InvalidOperation, DivisionByZero, Overflow, Underflow]), 'ExtendedContext': Context(prec=9, rounding=ROUND_HALF_EVEN, Emin=-999999, Emax=999999, capitals=1, clamp=0, flags=[], traps=[]), 'MAX_PREC': 999999999999999999, 'MAX_EMAX': 999999999999999999, 'MIN_EMIN': -999999999999999999, 'MIN_ETINY': -1999999999999999997, 'ROUND_UP': 'ROUND_UP', 'ROUND_DOWN': 'ROUND_DOWN', 'ROUND_CEILING': 'ROUND_CEILING', 'ROUND_FLOOR': 'ROUND_FLOOR', 'ROUND_HALF_UP': 'ROUND_HALF_UP', 'ROUND_HALF_DOWN': 'ROUND_HALF_DOWN', 'ROUND_HALF_EVEN': 'ROUND_HALF_EVEN', 'ROUND_05UP': 'ROUND_05UP'}
>>>

While the above information is 100% accurate, without formatting it's not very helpful.

Basic formatted output can be accomplished with:

>>> from decimal import *
>>> for v in globals() : print (v, '    ', globals()[v])
... 
__name__      __main__
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
RuntimeError: dictionary changed size during iteration
>>> v = 0
>>> for v in globals() : print (v, '    ', globals()[v])
... 
__name__      __main__
__doc__      None
__package__      None
__loader__      <class '_frozen_importlib.BuiltinImporter'>
...............................
ROUND_HALF_UP      ROUND_HALF_UP
ROUND_HALF_DOWN      ROUND_HALF_DOWN
ROUND_HALF_EVEN      ROUND_HALF_EVEN
ROUND_05UP      ROUND_05UP
v      v
>>>

The above adds variable 'v' and it does not show which of the above values are strings.

Try again using a listcomp:

>>> from decimal import *
>>> print ( '\n'.join(
... [
... sx
... for keys in ([ v for v in globals() ], )
... for len1 in ( sorted( [ len(k) for k in keys ] )[-1]+4,  )
... for k in keys
... for v in (globals()[k],)
... for k1 in ( ('**error**', "'" + k + "'")[isinstance(k,str)], )
... for single_quote in ( ("", "'")[isinstance(v,str)], )
... for v1 in ( single_quote + str(v) + single_quote,  )
... for sx in ( (k1 + (' '*len1))[:len1] + v1, )
... ]
... ))
'__name__'            '__main__'
'__doc__'             None
'__package__'         None
'__loader__'          <class '_frozen_importlib.BuiltinImporter'>
'__spec__'            None
'__annotations__'     {}
'__builtins__'        <module 'builtins' (built-in)>
................................................
'ROUND_DOWN'          'ROUND_DOWN'
'ROUND_CEILING'       'ROUND_CEILING'
'ROUND_FLOOR'         'ROUND_FLOOR'
'ROUND_HALF_UP'       'ROUND_HALF_UP'
'ROUND_HALF_DOWN'     'ROUND_HALF_DOWN'
'ROUND_HALF_EVEN'     'ROUND_HALF_EVEN'
'ROUND_05UP'          'ROUND_05UP'
>>>

Global communication

edit

globals() may be used for communication between nested functions. In the code below, function2() is defined within function1() and function3() is defined within function2().

By means of globals(), function3() can access the local variables of both function1() and function2():

def function1() :
    def function2() :
        def function3() :
            I1 = 6
            globals()['f3locals'] = dict(locals())
            print ('''
function3():
f1locals = {}
f2locals = {}
f3locals = {}
'''.format(
globals()['f1locals'],
globals()['f2locals'],
globals()['f3locals'],
))
            del globals()['f3locals']
        I1 = 4
        globals()['f2locals'] = dict(locals())
        function3()
        del globals()['f2locals']
    I1 = 2
    globals()['f1locals'] = dict(locals())
    function2()
    del globals()['f1locals']

function1()

for v in ('f1locals', 'f2locals', 'f3locals') :
    print (v in globals())
function3():
f1locals = {'I1': 2, 'function2': <function function1.<locals>.function2 at 0x102164158>}
f2locals = {'I1': 4, 'function3': <function function1.<locals>.function2.<locals>.function3 at 0x1021641e0>}
f3locals = {'I1': 6}

False
False
False

Notice that:

  • function2 is local to function1, and
  • function3 is local to function2.

locals()

edit

This expression has the appearance of a function but it returns and behaves like a dictionary representing the current local symbol table. At module level, globals and locals are the same dictionary. This means that, outside the body of a function, globals() and locals() are the same. Within the body of a function locals() assumes its individual identity.

Outside a function

edit

Invoke python on Unix and display globals() and locals():

$ python3.6
Python 3.6.3 (v3.6.3:2c5fed86e0, Oct  3 2017, 00:32:08) 
[GCC 4.2.1 (Apple Inc. build 5666) (dot 3)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> globals()
{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <class '_frozen_importlib.BuiltinImporter'>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>}
>>> 
>>> locals()
{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <class '_frozen_importlib.BuiltinImporter'>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>}
>>> 
>>> locals()['v1'] = 6
>>> 
>>> globals()
{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <class '_frozen_importlib.BuiltinImporter'>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, 'v1': 6}
>>> 
>>> locals()
{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <class '_frozen_importlib.BuiltinImporter'>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, 'v1': 6}
>>> 
>>> del globals()['v1']
>>> 
>>> globals()
{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <class '_frozen_importlib.BuiltinImporter'>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>}
>>> 
>>> locals()
{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <class '_frozen_importlib.BuiltinImporter'>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>}
>>> quit ()
$

The above operations show that, outside a function, a change in globals() is immediately reflected in locals() and vice-versa.

Inside a function

edit

The code below shows that, within a function, locals() is local.

def function1 () :
    print ('1. globals() =', globals())
    print ('1. locals() =',  locals())
    t1 = (1,2,3)
    print ('2. globals() =', globals())
    print ('2. locals() =',  locals())
    globals()['v1'] = 1.5
    print ('3. globals() =', globals())
    print ('3. locals() =',  locals())

function1()

print ('4. globals() =', globals())
print ('4. locals() =',  locals())
1. globals() = {
# Predefined globals.
'function1': <function function1 at 0x100561e18>
}
1. locals() = {}

# A change in locals() does not appear in globals():
2. globals() = {
# Predefined globals.
'function1': <function function1 at 0x100561e18>
}
2. locals() = {'t1': (1, 2, 3)}

# A change in globals() does not appear in locals():
3. globals() = {
# Predefined globals.
'function1': <function function1 at 0x100561e18>, 
'v1': 1.5
}
3. locals() = {'t1': (1, 2, 3)}

# Outside function1() globals() and locals() are the same, and globals() keeps the value 'v1':
4. globals() = {
# Predefined globals.
'function1': <function function1 at 0x100561e18>, 
'v1': 1.5
}
4. locals() = {
# Predefined globals.
'function1': <function function1 at 0x100561e18>, 
'v1': 1.5
}

Variable name duplicated

edit

The following code shows that it's possible to have the same variable name in both globals() and locals() with different values:

L2 = [1,2,3]

def function2 () :
    print ('1. globals() =', globals())
    print ('1. locals() =',  locals())
    L2 = [4,5,6]
    print ('2. globals() =', globals())
    print ('2. locals() =',  locals())

function2()
1. globals() = {
# Predefined variables.
'L2': [1, 2, 3], 
'function2': <function function2 at 0x100561e18>
}
1. locals() = {}

2. globals() = {
# Predefined variables.
'L2': [1, 2, 3], 
'function2': <function function2 at 0x100561e18>
}
2. locals() = {'L2': [4, 5, 6]}

Inside a listcomp

edit

Within a listcomp locals() is local to the listcomp:

>>> print ([
... locals1
... for l in 'x'
... for v1 in (1,)
... for L2 in ([4,5,6],)
... for locals1 in (locals(),)
... ])
[{
'L2': [4, 5, 6], 
'v1': 1, 
'l': 'x', 
'.0': <str_iterator object at 0x1022acc88>
}]
>>>

Assignments

edit
 
  • In your python code experiment with statements like import sys, from sys import * and the same for subprocess or re instead of sys. Use globals() so that you can see exactly what you have imported.

Further Reading or Review

edit
  Completion status: this resource is a stub, which means that pretty much nothing has been done yet.

References

edit

1. Python's documentation:

"Built-in Functions"

2. Python's methods:


3. Python's built-in functions:

"class range(start, stop(, step))", "Ranges", "globals()", "locals()"