This series of posts is for those who have used a programming language before but are not familiar with Python. This post concludes — at least for now — this series.
We’ll wrap things up with an overview of Python’s many built-in functions.
The Built-in Functions page of the Python documentation currently lists 71 functions. (Python’s documentation is very good. And because Python is a well-known language, queries about it to your favorite Ai can also be useful.)
The built-in data types (aka classes) all behave like functions (they are callable), so they are considered among Python’s built-in functions:
002|
003| # Numbers…
004| a_new_bool_object = bool()
005| a_new_int_object = int()
006| a_new_float_object = float()
007| a_new_complex_object = complex()
008|
009| # String objects…
010| a_new_string_object = str()
011| a_new_bytes_object = bytes()
012| a_new_bytearray_object = bytearray()
013|
014| # List-like objects…
015| a_new_list_object = list()
016| a_new_tuple_object = tuple()
017| a_new_dict_object = dict()
018| a_new_set_object = set()
019| a_new_frozenset_object = frozenset()
020|
021| # Basic object…
022| a_new_object = object()
023|
We explored this in part 1, part 2, and part 3, so see those parts for details. The examples above all return default objects because no parameters were provided.
When provided with parameters these functions convert one data type to another:
002|
003| # Numbers…
004| bool_object = bool(42 < 21)
005| int_object = int(“42”)
006| float_object = float(“42.21”)
007| complex_object = complex(0, 1)
008|
009| # String objects…
010| string_object = str(42)
011| bytes_object = bytes(“hello!”, encoding=‘utf-8’)
012| bytearray_object = bytearray(“hello!”, encoding=‘utf-8’)
013|
014| # List-like objects…
015| list_object = list(“hello!”)
016| tuple_object = tuple(“hello!”)
017| dict_object = dict(x=21, y=42, z=63)
018| set_object = set(“hello!”)
019| frozenset_object = frozenset(“hello!”)
020|
I haven’t mentioned the complex number data type (line #7 in both the above). Python includes complex numbers among its built-in data types. The example directly above creates the complex number i.
Note that when turning a string into bytes or a bytearray (lines #11 and #12), the encoding parameter is required. Note also that the object constructor takes no parameters and always returns a basic object.
The slice function creates an object for indexing objects that behave as lists:
002|
003| a_list = [0,1,2,3,4,5,6,7,8,9,10,11]
004| print(f’{a_list = }‘)
005|
006| a_string = “Hello, World!”
007| print(f’{a_string = }‘)
008|
009| # A slice object…
010| a_slice = slice(2, 6)
011| print(f’{a_slice = }‘)
012| print()
013|
014| # A slice of a list…
015| list_part = a_list[a_slice]
016| print(f’{list_part = }‘)
017|
018| # Same as…
019| list_part = a_list[2:6]
020| print(f’{list_part = }‘)
021| print()
022|
023| # A slice of a string…
024| string_part = a_string[a_slice]
025| print(f’{string_part = }‘)
026|
027| # Same as…
028| string_part = a_string[2:6]
029| print(f’{string_part = }‘)
030| print()
031|
Note that slice requires at least one parameter (just as indexing does) and takes up to three (start, stop, step, again, just as indexing does).
When run, this prints:
a_list = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11] a_string = 'Hello, World!' a_slice = slice(2, 6, None) list_part = [2, 3, 4, 5] list_part = [2, 3, 4, 5] string_part = 'llo,' string_part = 'llo,'
The range function returns an ordered list of (unique) numbers. A simple example is that range(5) returns 0,1,2,3,4. A more involved example is range(10,40,5), which returns 10,15,20,25,30,35. The enumerate function binds index numbers to a list of items.
Both functions frequently appear in for loops:
002|
003| # A range object…
004| a_range = range(5)
005| print(f’{a_range = }‘)
006| print()
007|
008| # A range list…
009| list_of_range = list(a_range)
010| print(f’{list_of_range = }‘)
011| print()
012|
013| # Using range in a for loop…
014| for ix in range(3):
015| print(f’{ix = }‘)
016| print()
017|
018| # An enumeration object
019| an_enumeration = enumerate(a_range)
020| print(f’{an_enumeration = }‘)
021| print()
022|
023| # An enumeration list…
024| list_of_pairs = list(an_enumeration)
025| print(f’{list_of_pairs = }‘)
026| print()
027|
028| # An enumeration object
029| list_of_enumeration = list(enumerate(‘ABCD’))
030| print(f’{list_of_enumeration = }‘)
031| print()
032|
033| # Using enumerate in a for loop…
034| my_list = [‘foo’, ‘bar’, ‘nop’, ‘gif’]
035| for ix,value in enumerate(my_list):
036| print(f’{ix}: {value}‘)
037| print()
038|
039|
Note both are among the functions that return a list-like object rather than an actual list. (They return iterator or generator objects.) To get actual list objects, we use the list constructor.
[This may seem inconvenient, but it comes in handy when dealing with very large lists. Iterators and generators don’t create copies of their list; they maintain a reference to the “current” item. Therefore, they don’t consume much memory.]
When run, this prints:
a_range = range(0, 5) list_of_range = [0, 1, 2, 3, 4] ix = 0 ix = 1 ix = 2 an_enumeration = <enumerate object at 0x0000022628D6E480> list_of_pairs = [(0, 0), (1, 1), (2, 2), (3, 3), (4, 4)] list_of_enumeration = [(0, 'A'), (1, 'B'), (2, 'C'), (3, 'D')] 0: foo 1: bar 2: nop 3: gif
A number of other built-in functions return list-like objects. Five commonly used ones are: reversed, sorted, zip, filter, and map:
002|
003| a_list = [1,2,3,4,5,6,7,8]
004| print(f’{a_list = }‘)
005|
006| a_string = “Hello!”
007| print(f’{a_string = }‘)
008| print()
009|
010| # Reversing a list-like object…
011| reversed_list = list(reversed(a_list))
012| print(f’{reversed_list = }‘)
013|
014| reversed_string = list(reversed(a_string))
015| print(f’{reversed_string = }‘)
016| print()
017|
018| # Sorting a list-like object…
019| sorted_list = list(sorted(reversed_list))
020| print(f’{sorted_list = }‘)
021|
022| sorted_string = list(sorted(a_string))
023| print(f’{sorted_string = }‘)
024| print()
025|
026| # Zipping lists together…
027| for num,letter in zip(a_list, a_string):
028| print(f’{num} – {letter}‘)
029| print()
030|
031| items = list(range(12))
032| print(f’{items = }‘)
033| print()
034|
035| # Filtering a list…
036| def filter_function (item):
037| return item < 5
038|
039| filtered_items = list(filter(filter_function, items))
040| print(f’{filtered_items = }‘)
041| print()
042|
043| # Mapping a list to a new list…
044| def mapping_function (item):
045| return item * item
046|
047| mapped_items = list(map(mapping_function, items))
048| print(f’{mapped_items = }‘)
049| print()
050|
It should be obvious what the reversed and sorted functions do.
The zip function combines multiple list-like objects into a single list of tuples where each tuple has one element from each list. Note that zip stops when any of its input lists ends. It won’t go beyond its shortest input list.
The filter function takes two parameters: a function and a list-like object. It uses the function to filter the list, passing each list item in turn to the filter function. If that function returns True, the item is retained, else it’s discarded.
The map function also takes a function and a list-like object, but it returns a same-sized list consisting of the returned values from the mapping function. In this case, the squares of the numbers in the input list.
When run, this prints:
a_list = [1, 2, 3, 4, 5, 6, 7, 8] a_string = 'Hello!' reversed_list = [8, 7, 6, 5, 4, 3, 2, 1] reversed_string = ['!', 'o', 'l', 'l', 'e', 'H'] sorted_list = [1, 2, 3, 4, 5, 6, 7, 8] sorted_string = ['!', 'H', 'e', 'l', 'l', 'o'] 1 - H 2 - e 3 - l 4 - l 5 - o 6 - ! items = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11] filtered_items = [0, 1, 2, 3, 4] mapped_items = [0, 1, 4, 9, 16, 25, 36, 49, 64, 81, 100, 121]
The len (length), max (maximum), min (minimum), sum, all, and any functions expect a list-like object, but these return a numerical value:
002|
003| a_list = [21, 99, 42, 86, 63, 84, 105]
004|
005| # List length…
006| print(f’{len(a_list) = }‘)
007| print()
008|
009| # List maximum, miniumum, and sum…
010| print(f’{max(a_list) = }‘)
011| print(f’{min(a_list) = }‘)
012| print(f’{sum(a_list) = }‘)
013| print()
014|
015| # Are all list items true…
016| print(f’{all([21, 42, 63, 84]) = }‘)
017| print(f’{all([21, 42, 0, 84]) = }‘)
018| print()
019|
020| # Is any list item true…
021| print(f’{any([21, 42, 63, 84]) = }‘)
022| print(f’{any([0, 0, 63, 0]) = }‘)
023| print(f’{any([0, 0, 0, 0]) = }‘)
024| print()
025|
The len function returns the length of any list.
The max function and the min function return, respectively, the maximum and minimum of any list comprised of sortable items (i.e. that can be compared with less-than). That means we can, for example, find the alphabetic minimum or maximum in a list of strings.
The sum function expects a list of numeric objects it can sum together (integers, floats, complex numbers, or any data type that can be added with each other or other numeric values).
[Recall how the Point class we created in part 8, part 9, and part 10 implemented methods to do math with Point objects, so we can use the sum function with a list of Point objects. But while we did implement methods for comparing two Point objects for equality (i.e. using the == and != operators), we did not implement the methods that allow greater-than or less-then comparisons (using the < or <= or >= or > operators), so we cannot use the min or max functions with Point objects.]
The all function and the any function both take a list of items and return a value based on their Boolean values. They determine whether all items are True or any item is True, respectively.
When run, this prints:
len(a_list) = 7 max(a_list) = 105 min(a_list) = 21 sum(a_list) = 500 all([21, 42, 63, 84]) = True all([21, 42, 0, 84]) = False any([21, 42, 63, 84]) = True any([0, 0, 63, 0]) = True any([0, 0, 0, 0]) = False
There are four useful math functions: abs, divmod, pow, and round:
002|
003| # Absolute value…
004| print(f’{abs(–42) = }‘)
005|
006| print(f’{abs(–42.21) = }‘)
007| print()
008|
009| # Div-Mod…
010| square_index = 55
011|
012| row,col = divmod(square_index, 8)
013| print(f’{row=}, {col=}‘)
014|
015| # divmod is equivalent to…
016| row = int(square_index / 8)
017| col = square_index % 8
018| print(f’{row=}, {col=}‘)
019|
020| # or better yet…
021| row = square_index // 8
022| col = square_index % 8
023| print(f’{row=}, {col=}‘)
024| print()
025|
026| # Power…
027| print(f’4 to the power of 2 = {pow(4, 2)}‘)
028| print(f’4 to the power of -2 = {pow(4, –2)}‘)
029| print(f’4 to the power of 2.7 = {pow(4, 2.7)}‘)
030| print()
031|
032| print(f’4**2 = {4 ** 2}‘)
033| print(f’4**-2 = {4 ** –2}‘)
034| print(f’4**2.7 = {4 ** 2.7}‘)
035| print()
036|
037| # Rounding down…
038| print(f’{round(2.71828) = }‘)
039| print(f’{round(3.14159) = }‘)
040| print(f’{round(2.71828, 3) = }‘)
041| print(f’{round(3.14159, 3) = }‘)
042| print()
043|
The abs function returns the absolute value of a numeric input.
The divmod function performs an integer division, dividing the first argument by the second, and then performs a modulus operation using the same arguments. It returns both results in a tuple. Lines #16 and #17 show one form of the equivalent operation. Lines #21 and #22 show an alternate form using the integer division operator (//).
The pow function is equivalent to using the power operator (**). Note that both can handle negative exponents as well as fractional ones [see Exponents on my other blog for more on negative and fractional powers].
The round function rounds floating point numbers to the desired number of decimal digits (or none if the ndigits parameter isn’t supplied).
When run, this prints:
abs(-42) = 42 abs(-42.21) = 42.21 row=6, col=7 row=6, col=7 row=6, col=7 4 to the power of 2 = 16 4 to the power of -2 = 0.0625 4 to the power of 2.7 = 42.22425314473263 4**2 = 16 4**-2 = 0.0625 4**2.7 = 42.22425314473263 round(2.71828) = 3 round(3.14159) = 3 round(2.71828, 3) = 2.718 round(3.14159, 3) = 3.142
The bin, hex, and oct functions return the binary, hexadecimal, and octal string versions of their numeric inputs.
The chr function (character) converts a number to a character based on its Unicode ordinal value. The ord function (ordinal) does the opposite, returning the ordinal index value of a character:
002|
003| print(f’{bin(42) = }‘)
004| print(f’42 is {42:08b} in binary‘)
005| print()
006|
007| print(f’{hex(42) = }‘)
008| print(f’42 is {42:04x} in hexadecimal‘)
009| print()
010|
011| print(f’{oct(42) = }‘)
012| print(f’42 is {42:06o} in octal‘)
013| print()
014|
015| print(f’{chr(42) = }‘)
016| print()
017|
018| print(f’{ord(“*”) = }‘)
019| print()
020|
Note that we can also use formatted strings to obtain the binary, hexadecimal, or octal strings of a numeric value (lines #4, #8, and #12), and these offer a bit more control over how the number is displayed. For one, the built-in functions prefix the number with 0b, 0x, or 0o whereas formatted output does not. These three are mainly useful in an interactive environment when we want to convert a number.
The chr and ord functions are far more useful and make frequent appearances in code that processes text. For instance, they enabled the ROT13 example from last time.
When run, this prints:
bin(42) = '0b101010'
42 is 00101010 in binary
hex(42) = '0x2a'
42 is 002a in hexadecimal
oct(42) = '0o52'
42 is 000052 in octal
chr(42) = '*'
ord("*") = 42
We been using the print function throughout this series. Here we’ll see some of its extended capabilities. We’ve also touched on the difference between a string version of an object and its representation string, which we get using the str and repr functions respectively. The ascii function is related to the repr function in that both return a representation string. The ascii function also converts any non-printable characters to backslash “escaped” versions. The format function is another way to format output strings:
002|
003| # Print multiple values…
004| print(21, 42, “Hello!”, [1,2,3])
005| print()
006|
007| # Change the separator for multiple values (default is “, “)…
008| print(21, 42, 63, 86, sep=‘;’)
009| print()
010|
011| # Change the end-of-line character (default is “\n”)…
012| print(‘This text ‘, end=”)
013| print(‘is all on ‘, end=”)
014| print(‘one line!’)
015| print()
016|
017| # Use print to write to a file…
018| output_filename = r”C:\Demo\HCC\Python\output.txt”
019|
020| with open(output_filename, mode=‘w’) as output:
021| print(‘Hello, World!’, file=output, flush=True)
022| print(‘How are you feeling today?’, file=output, flush=True)
023| print(file=output, flush=True)
024|
025| print(f’wrote: {output_filename}‘)
026| print()
027|
028| # Representation versus string value…
029| a_string = “Hello, World!”
030|
031| print(f’{a_string}‘)
032| print(f’using str: {str(a_string)}‘)
033| print(f’using repr: {repr(a_string)}‘)
034| print()
035| print(f’using debug: {a_string = }‘)
036| print(f’using debug !s: {a_string = !s}‘)
037| print(f’using debug !r: {a_string = !r}‘)
038| print()
039|
040| # An older form of repr…
041| a_string = “Hello,\tWorld!\n”
042| print(f’a_string = {ascii(a_string)}‘)
043| print()
044|
045| # Use format for formatted outout…
046| print(f’{format(42) = }‘)
047| print(f’{format(42, “”) = }‘)
048| print(f’{format(42, “04x”) = }‘)
049| print()
050|
The print function has a sep parameter (line #8) that controls the separator between multiple values (the default is “, “). And note that print can take multiple values. The end parameter (lines #12 and #13) controls what print puts at the end (the default is “\n”).
The file parameter (lines #21 to #23) lets us redirect output from stdout to a file. Note that we can only use print with text files, not binary files (opened with mode="w" but not with mode="wb"). [See part 11 for more on opening files.]
Lines #31 to #37 illustrate different ways to get an object’s print string or representation string. Note that the str function is a data type (aka class) used as a constructor but the repr function is just a function that returns a string.
The ascii function (line #42) returns a representation string that escapes embedded non-printable characters (in this case, the tab and newline). Both str and repr send the tab and newline to the output as is.
The format function (lines #46 to #48) takes a value (any object) and a formatting string appropriate for that value. If no format string is given, the default is an empty string, which returns the string value of the object.
When run, this prints:
21 42 Hello! [1, 2, 3] 21;42;63;86 This text is all on one line! wrote: C:\Demo\HCC\Python\output.txt Hello, World! using str: Hello, World! using repr: 'Hello, World!' using debug: a_string = 'Hello, World!' using debug !s: a_string = Hello, World! using debug !r: a_string = 'Hello, World!' a_string = 'Hello,\tWorld!\n' format(42) = '42' format(42, "") = '42' format(42, "04x") = '002a'
Six built-in functions (type, super, id, hash, callable, isinstance, and issubclass) are for dealing with classes and instances of classes:
002|
003| class base:
004| ”’Simple name/value base class.”’
005|
006| def __init__ (self, name, value):
007| ”’New instance.”’
008| self.name = name
009| self.value = value
010|
011| def __hash__ (self):
012| ”’Return a hash value.”’
013| return hash(self.name) + hash(self.value)
014|
015| def __call__ (self, new_value):
016| ”’Set new value; return old value.”’
017| old_value = self.value
018| self.value = new_value
019| return old_value
020|
021| def __repr__ (self):
022| ”’Return a representation string.”’
023| return f’{self.name}: {self.value}‘
024|
025| class derived (base):
026| ”’A subclass of base that adds a data-type.”’
027|
028| def __init__ (self, name, value, dtype):
029| ”’New instance.”’
030| # Call the base class init method…
031| super().__init__(name, value)
032| self.dtype = dtype
033|
034| def __call__ (self, new_value, new_dtype):
035| ”’Set new value & dtype; return old value.”’
036| old_value = super().__call__(new_value)
037| self.dtype = new_dtype
038| return old_value
039|
040| def __repr__ (self):
041| ”’Return a representation string.”’
042| return f’{self.name}: {self.value} is {self.dtype}‘
043|
044|
045| # Create some base objects…
046| b1 = base(‘Foo’, 21)
047| b2 = base(‘Bar’, 42)
048|
049| # Create some derived objects…
050| d1 = derived(‘Alex’, 86.5, float)
051| d2 = derived(‘Blair’, “Drew”, str)
052|
053| print(f’{b1 = }‘)
054| print(f’{b2 = }‘)
055| print(f’{d1 = }‘)
056| print(f’{d2 = }‘)
057| print()
058|
059| print(f’{type(b1) = }‘)
060| print(f’{type(b2) = }‘)
061| print(f’{type(d1) = }‘)
062| print(f’{type(d2) = }‘)
063| print()
064|
065| print(f’{id(b1) = }‘)
066| print(f’{id(b2) = }‘)
067| print(f’{id(d1) = }‘)
068| print(f’{id(d2) = }‘)
069| print()
070|
071| print(f’{hash(b1) = }‘)
072| print(f’{hash(b2) = }‘)
073| print(f’{hash(d1) = }‘)
074| print(f’{hash(d2) = }‘)
075| print()
076|
077| print(f’{callable(b1) = }‘)
078| print(f’{callable(b2) = }‘)
079| print(f’{callable(d1) = }‘)
080| print(f’{callable(d2) = }‘)
081| print()
082|
083| print(f’{isinstance(b1, base) = }‘)
084| print(f’{isinstance(b1, derived) = }‘)
085| print(f’{isinstance(b2, type(b1)) = }‘)
086| print(f’{isinstance(b2, type(d1)) = }‘)
087| print()
088| print(f’{isinstance(d1, base) = }‘)
089| print(f’{isinstance(d1, derived) = }‘)
090| print(f’{isinstance(d2, type(b1)) = }‘)
091| print(f’{isinstance(d2, type(d1)) = }‘)
092| print()
093|
094| print(f’{issubclass(base, tuple) = }‘)
095| print(f’{issubclass(base, derived) = }‘)
096| print(f’{issubclass(derived, base) = }‘)
097| print(f’{issubclass(type(d1), type(b1)) = }‘)
098| print()
099|
Lines #3 to #23 define a simple name/value class called base. In the dunder init method (lines #6 to #9) we create two instance properties: name and value. We set these with (required) values passed to the method.
Lines #11 to #13 implement the dunder hash method, which must return an integer value. Providing this method allows instances of the class to act as keys in dictionaries or items in a set. Note that when we implement dunder hash, we should also implement the dunder eq method to enable object comparisons with the equals operator (==). I skipped it here to save space.
Lines #15 to #19 implement the dunder call method, which lets us treat instances of this class as function objects.
Lines #21 to #23 implement the dunder repr method, which gives objects of this class a string representation (something we should always do).
Lines #25 to #42 implements an extension of base called derived. This class inherits everything from the base class and then either adds new properties (line #32) and methods or overrides existing ones from base.
Lines #28 to #32 re-implement the dunder init method, and this overrides the one from the base class. We use the built-in super function to give us a reference to the superclass (i.e. base) and use that to call the base class’s dunder init method (line #31).
Lines #34 to #38 re-implement the dunder call method, which overrides the one from the base class, and we again use the super function to invoke that class’s dunder call method.
Lines #40 to #42 re-implement the dunder repr method to account for the dtype property, and this completely replaces the dunder repr method from base.
Lines #45 to #51 create two new instances of the base class (b1 and b2) and two new instances of the derived class (d1 and d2). Lines #53 to #98 exercise these new instances using various built-in functions.
Lines #53 to #56 invoke the dunder repr method to obtain and print string representations. Lines #65 to #62 use the type function to obtain each instance object’s data type (aka class). Note that type returns the object’s actual class (not a string). Lines #65 to #68 use the id function to obtain each object’s ID (memory location). Lines #71 to #74 use the hash function to get each objects hash value (which invokes the object’s dunder hash method).
Lines #77 to #80 use the callable function to determine whether an object has a dunder call method. Note this doesn’t invoke that method, it only tells us the method exists and we can treat the object as a function.
Likewise, the isinstance function (lines #83 to #86 and #88 to #91) returns True or False depending on whether a given object is an instance of a given class. The issubclass function (lines #94 to #97) returns True or False depending on whether a given class is a subclass of some other given class.
When run, this prints:
b1 = Foo: 21 b2 = Bar: 42 d1 = Alex: 86.5 is <class 'float'> d2 = Blair: Drew is <class 'str'> type(b1) = <class '__main__.base'> type(b2) = <class '__main__.base'> type(d1) = <class '__main__.derived'> type(d2) = <class '__main__.derived'> id(b1) = 2799129471232 id(b2) = 2799129427024 id(d1) = 2799129471568 id(d2) = 2799129427344 hash(b1) = 8498221605137793095 hash(b2) = -6886228356769053774 hash(d1) = 7948385794103204923 hash(d2) = 1533453739743887147 callable(b1) = True callable(b2) = True callable(d1) = True callable(d2) = True isinstance(b1, base) = True isinstance(b1, derived) = False isinstance(b2, type(b1)) = True isinstance(b2, type(d1)) = False isinstance(d1, base) = True isinstance(d1, derived) = True isinstance(d2, type(b1)) = True isinstance(d2, type(d1)) = True issubclass(base, tuple) = False issubclass(base, derived) = False issubclass(derived, base) = True issubclass(type(d1), type(b1)) = True
Four built-in functions let us probe and manipulate instance and class attributes. The hasattr function returns True or False depending on whether the object has the specified attribute. The getattr function returns the value of the specified attribute, and the setattr function changes the value of the specified attribute. Lastly, the delattr function deletes the specified attribute:
002|
003| class Point:
004| ”’Simple 3D point class.”’
005|
006| def __init__ (self, x=0, y=0, z=0):
007| ”’New instance.”’
008| self.x = x
009| self.y = y
010| self.z = z
011|
012| def __repr__ (self):
013| ”’Return representation string.”’
014| return f’<{type(self).__name__} @{id(self):012x}>‘
015|
016| def __str__ (self):
017| ”’Return print string.”’
018| return f’[{self.x}, {self.y}, {self.z}]‘
019|
020|
021| # Create a new point object…
022| p1 = Point(2.1, 4.2, 6.3)
023|
024| print(f’point-1 str = {p1}‘)
025| print(f’point-1 repr = {p1!r}‘)
026| print()
027|
028| # Test to see if p1 has desired attributes…
029| print(f’{hasattr(p1, “x”) = }‘)
030| print(f’{hasattr(p1, “w”) = }‘)
031| print()
032|
033| print(f’{hasattr(p1, “__str__”) = }‘)
034| print(f’{hasattr(p1, “__repr__”) = }‘)
035| print(f’{hasattr(p1, “__eq__”) = }‘)
036| print(f’{hasattr(p1, “__hash__”) = }‘)
037| print(f’{hasattr(p1, “foobar”) = }‘)
038| print()
039|
040| # Get the value of some of p1’s attributes…
041| print(f’{getattr(p1, “x”) = }‘)
042| print(f’{getattr(p1, “w”, –1) = }‘)
043| try:
044| print(f’{getattr(p1, “w”) = }‘)
045|
046| except Exception as e:
047| print(f’OOPS! “{e}” ({type(e).__name__})‘)
048|
049| finally:
050| print()
051|
052| # Get p1’s str method…
053| object_str_method = getattr(p1, “__str__”)
054| print(object_str_method)
055|
056| # Use the method…
057| print(f’{object_str_method() = }‘)
058| print()
059|
060| # Get the Point class’s str method…
061| class_str_method = getattr(Point, “__str__”)
062| print(class_str_method)
063|
064| # Use the method…
065| print(f’{class_str_method(p1) = }‘)
066| print()
067|
068| # Use setattr to add some new attributes…
069| setattr(p1, “w”, 8.4)
070| setattr(p1, “u”, 0.0)
071| print(f’{getattr(p1, “w”) = }‘)
072| print(f’{getattr(p1, “u”) = }‘)
073| print()
074|
075| # Use delattr to remove some attributes…
076| delattr(p1, “x”)
077| delattr(p1, “y”)
078| delattr(p1, “z”)
079| print(f’{getattr(p1, “x”, “Gone!”) = }‘)
080| print(f’{getattr(p1, “y”, “Gone!”) = }‘)
081| print(f’{getattr(p1, “z”, “Gone!”) = }‘)
082| print(f’{getattr(p1, “w”, “Gone!”) = }‘)
083| print(f’{getattr(p1, “u”, “Gone!”) = }‘)
084| print()
085|
Note that the getattr function has an optional third parameter that provides a default value in case attribute doesn’t exist. If the parameter isn’t supplied and the attribute does not exist, Python raises an Exception.
Lines #52 to #58 demonstrate using getattr to obtain an instance object’s method, while lines #60 to #66 demonstrate using getattr to objection a class’s method. Note how, in the former case, the self parameter is pre-supplied, but in the latter case, an object must be provided. (This is because the object knows itself, but the class has no way to know which instance is involved.)
The setattr function has a required third parameter that provides the new value for the attribute. Note that, if the attribute doesn’t exist, setattr creates it.
When run, this prints:
point-1 str = [2.1, 4.2, 6.3] point-1 repr = <Point @022d1a332900> hasattr(p1, "x") = True hasattr(p1, "w") = False hasattr(p1, "__str__") = True hasattr(p1, "__repr__") = True hasattr(p1, "__eq__") = True hasattr(p1, "__hash__") = True hasattr(p1, "foobar") = False getattr(p1, "x") = 2.1 getattr(p1, "w", -1) = -1 OOPS! "'Point' object has no attribute 'w'" (AttributeError) <bound method Point.__str__ of <Point @022d1a332900>> object_str_method() = '[2.1, 4.2, 6.3]' <function Point.__str__ at 0x0000022D1A411B20> class_str_method(p1) = '[2.1, 4.2, 6.3]' getattr(p1, "w") = 8.4 getattr(p1, "u") = 0.0 getattr(p1, "x", "Gone!") = 'Gone!' getattr(p1, "y", "Gone!") = 'Gone!' getattr(p1, "z", "Gone!") = 'Gone!' getattr(p1, "w", "Gone!") = 8.4 getattr(p1, "u", "Gone!") = 0.0
We’ve seen the built-in iter and next functions before (see part 3, for instance), but here’s a quick demo:
002|
003| a_list = [1,2,3,4,5,6]
004|
005| a_string = “ABCDEF”
006|
007| # Get an iterator over the list…
008| iter_list = iter(a_list)
009| print(iter_list)
010| print()
011|
012| try:
013| print(f’{next(iter_list) = }‘)
014| print(f’{next(iter_list) = }‘)
015| print(f’{next(iter_list) = }‘)
016| print(f’{next(iter_list) = }‘)
017| print(f’{next(iter_list) = }‘)
018| print(f’{next(iter_list) = }‘)
019| print(f’{next(iter_list) = }‘)
020|
021| except Exception as e:
022| print(f’OOPS! Got a {type(e).__name__}‘)
023|
024| finally:
025| print()
026|
027| # Get an iterator over the string…
028| iter_string = iter(a_string)
029| print(iter_string)
030| print()
031|
032| try:
033| print(f’{next(iter_string) = }‘)
034| print(f’{next(iter_string) = }‘)
035| print(f’{next(iter_string) = }‘)
036| print(f’{next(iter_string) = }‘)
037| print(f’{next(iter_string) = }‘)
038| print(f’{next(iter_string) = }‘)
039| print(f’{next(iter_string) = }‘)
040|
041| except Exception as e:
042| print(f’OOPS! Got a {type(e).__name__}‘)
043|
044| finally:
045| print()
046|
When run, this prints:
<list_iterator object at 0x0000017A35F64100> next(iter_list) = 1 next(iter_list) = 2 next(iter_list) = 3 next(iter_list) = 4 next(iter_list) = 5 next(iter_list) = 6 OOPS! Got a StopIteration <str_ascii_iterator object at 0x0000017A33BA2BF0> next(iter_string) = 'A' next(iter_string) = 'B' next(iter_string) = 'C' next(iter_string) = 'D' next(iter_string) = 'E' next(iter_string) = 'F' OOPS! Got a StopIteration
Note that when an iterator is exhausted, it cannot be reset. Iterators are once through and done. They are among the functions that return a list-like object that is not a list.
We’ve also seen the built-in property, classmethod, and staticmethod functions before (see part 10):
002|
003| class Point:
004| ”’Simple 2D point class.”’
005|
006| def __init__ (self, x=0, y=0):
007| ”’New instance.”’
008| self._x = x
009| self._y = y
010|
011| @property
012| def x (self): return self._x
013|
014| @property
015| def y (self): return self._y
016|
017| @classmethod
018| def x_axis (cls): return Point(x=1)
019|
020| @classmethod
021| def y_axis (cls): return Point(y=1)
022|
023| @staticmethod
024| def dot_product (p1, p2):
025| x = p1.x * p2.x
026| y = p1.y * p2.y
027| return x+y
028|
029| def __repr__ (self):
030| ”’Return print string.”’
031| return f’[{self.x:+.3f}, {self.y:+.3f}]‘
032|
033| # Create a new point object…
034| p1 = Point(2.1, 4.2)
035| print(f’{p1}‘)
036|
037| # Get the x-axis and y-axis basis vectors…
038| px = Point.x_axis()
039| py = Point.y_axis()
040| print(f’{px}‘)
041| print(f’{py}‘)
042| print()
043|
044| # Get the dot product between p1 and the x-axis…
045| print(f’{Point.dot_product(p1, px) = }‘)
046| # Get the dot product between p1 and the y-axis…
047| print(f’{Point.dot_product(p1, py) = }‘)
048| print()
049|
All three are decorator functions [see also Function definitions]. Decorators add a wrapper around a function or class and can modify the function or class they wrap. These are advanced topics we’ll cover in detail another time.
The property decorator (lines #11 and #14) converts a method to an attribute. In this 2D Point class, dunder init creates attributes called _x and _y (lines #8 and #9; the leading underbar is canonical Python for “this is a private attribute”). Instead, we use a property decorator to convert the x and y methods to (read-only) attributes. When dunder repr uses self.x and self.y, it is accessing the properties.
The classmethod decorator (lines #17 and #20) converts an instance method to a class method. Rather than a self parameter, class methods have a class parameter (which we spell cls because class is a reserved keyword). Class methods only know about the class, not any instance object. We use it here to create two methods that return pre-determined Point objects.
The staticmethod decorator (line #23) converts an instance method to a static classmethod. These have neither a self nor a cls parameter. They are essentially ordinary functions but including them in the class associates the function with the data type.
When run, this prints:
[+2.100, +4.200] [+1.000, +0.000] [+0.000, +1.000] Point.dot_product(p1, px) = 2.1 Point.dot_product(p1, py) = 4.2
Two built-in functions, globals and locals, return a dictionary of available variables:
002|
003| Red = ‘#ff0000’
004| Green = ‘#00ff00’
005| Blue = ‘#0000ff’
006|
007| def my_function (r, g, b):
008| x = 21
009| y = 42
010|
011| print(‘Globals:’)
012| for name,value in globals().items():
013| print(f’{name}: {value}‘)
014| print()
015|
016| print(‘Locals:’)
017| for name,value in locals().items():
018| print(f’{name}: {value}‘)
019| print()
020|
021|
022| my_function(Red, Green, Blue)
023|
The globals function returns a dictionary of variables at the module level.
The locals function returns a dictionary of variable at the current scope (which means it returns the same names as globals when called at the module level.
When run, this prints:
Globals:
__name__: __main__
__doc__: None
__package__: None
__loader__: <class '_frozen_importlib.BuiltinImporter'>
__spec__: None
__annotations__: {}
__builtins__: <module 'builtins' (built-in)>
__file__: C:\Demo\HCC\Python\source\fragment.py
Red: #ff0000
Green: #00ff00
Blue: #0000ff
my_function: <function my_function at 0x0000024AEC291940>
Locals:
r: #ff0000
g: #00ff00
b: #0000ff
x: 21
y: 42
name: my_function
value: <function my_function at 0x0000024AEC291940>
The first list, from globals, contains many special dunder names (names enclosed in double underbars). For example, the __name__ entry holds the name of the current module (in this case __main__ — see part 7 for details), and __file__ contains the filename.
The second list, from locals, contains only the local variables from my_function. These include the function parameters as well as the name and value variables used in the for loops.
Three built-in functions, vars, dir, and help, explore Python objects and are mainly intended for the interactive development environment:
002|
003| class Point:
004| ”’Simple 3D point class.”’
005|
006| def __init__ (self, x=0, y=0, z=0):
007| ”’New instance.”’
008| self.x = x
009| self.y = y
010| self.z = z
011|
012| print(‘vars(Point):’)
013| for name,value in vars(Point).items():
014| print(f’{name}: {value}‘)
015| print()
016|
017| print(‘dir(Point):’)
018| for item in dir(Point):
019| print(f’{item}‘)
020| print()
021|
022| print(‘help(Point):’)
023| help(Point)
024|
The vars function (line #13) returns a dictionary listing the variables of a given object. If invoked without an argument, it acts like locals.
The dir function (line #18) returns a list a given object’s variable names (but not values). If invoked without an argument, it is the equivalent of:
list(sorted(locals().keys()))
It returns a sorted list of variable names.
The help function (line #23) is an interactive utility that writes output to the console. The function doesn’t return a value (technically, it returns None). If invoked without an argument, it prints information about the help function. If invoked with an argument, it prints information about the passed object.
When run, this prints:
vars(Point):
__module__: __main__
__firstlineno__: 3
__doc__: Simple 3D point class.
__init__: <function Point.__init__ at 0x000002D0A49F1940>
__static_attributes__: ('x', 'y', 'z')
__dict__: <attribute '__dict__' of 'Point' objects>
__weakref__: <attribute '__weakref__' of 'Point' objects>
dir(Point):
__class__
__delattr__
__dict__
__dir__
__doc__
__eq__
__firstlineno__
__format__
__ge__
__getattribute__
__getstate__
__gt__
__hash__
__init__
__init_subclass__
__le__
__lt__
__module__
__ne__
__new__
__reduce__
__reduce_ex__
__repr__
__setattr__
__sizeof__
__static_attributes__
__str__
__subclasshook__
__weakref__
help(Point):
Help on class Point in module __main__:
class Point(builtins.object)
| Point(x=0, y=0, z=0)
|
| Simple 3D point class.
|
| Methods defined here:
|
| __init__(self, x=0, y=0, z=0)
| New instance.
|
| ----------------------------------------------------------------------
| Data descriptors defined here:
|
| __dict__
| dictionary for instance variables
|
| __weakref__
| list of weak references to the object
Sometimes the output of these functions is lengthy. The help function, in particular, prints very full documentation of whatever object is passed to it. The best thing is to actually try these in the Python IDLE [see part 7].
This post has gotten quite long but still hasn’t touched on all 71 built-in functions. One of the remaining ones, the open function for reading and writing files, was discussed at length in part 11.
The input function provides a way to get user input:
002|
003| print(“Type some stuff, and press [Enter]:”)
004| stuff = input()
005| print(“Thank you.”)
006| print()
007|
008| print(“You typed:”)
009| print(stuff)
010| print()
011|
012| ok = input(“Is that correct? [Y]/[N] + [Enter]: “)
013|
014| if ok.lower().startswith(‘y’):
015| print(“Input validated.”)
016| else:
017| print(“Input rejected.”)
018| print()
019|
Here’s what it looked like when run:
Type some stuff, and press [Enter]: This is a line of text. Thank you. You typed: This is a line of text. Is that correct? [Y]/[N] + [Enter]: y Input validated.
The remaining functions are fairly specialized, and I’ll just mention them in passing:
aiter— the asynchronous version ofiteranext— the asynchronous version ofnext.breakpoint— halt execution and enter debugger at this point.compile— compile Python source code into an executable code object.eval— evaluate Python source code and return a value.exec— execute Python source code.memoryview— returns a “memory view” object of its given object.__import__— an alternate way to import modules.
Chances are you won’t use most of these unless you become a Python developer and get deep into the Python weeds.
And on that note, we’re done for this first series. I hope it was helpful.
Link: Zip file containing all code fragments used in this post.
∅
ATTENTION: The WordPress Reader strips the style information from posts, which can destroy certain important formatting elements. If you’re reading this in the Reader, I highly recommend (and urge) you to [A] stop using the Reader and [B] always read blog posts on their website.
This post is: This is Python! (part 12)