<jupyter_start><jupyter_text>BUILT-IN FUNCTIONS - Part 1<jupyter_code># abs
# Return the absolute value of a number

class Abs1:
    def __abs__(self):
        return 123

print("=== abs ===")
print(abs(1))
print(abs(-1))
print(abs(-1.235))
print(abs(Abs1()))

# all
# Return True if all elements of the iterable are true (or if the iterable is empty)

class False1:
    def __bool__(self):
        print("False in class")
        return False

class True1:
    def __bool__(self):
        print("True in class")
        return True


all_lst1 = [1, -9, 2]
all_lst2 = [True, False, True]
all_lst3 = [True, False1(), True1()]

print("all_empty_list", all([]))
print("all_lst1", all(all_lst1))
print("all_lst2", all(all_lst2))
print("all_lst3") # print only text to see False in class
print(all(all_lst3)) # You won't see "True in class" before previous item is False (stop here)
# any
# Return True if any element of the iterable is true. If the iterable is empty, return False  => ( ! all ( lambda: ! item ) )

any_lst1 = [0, -9, 0]
any_lst2 = [False, False, True]
any_lst3 = [False, False, False]
any_lst4 = [True1(), False1(), False]

print("any_empty_list", any([]))
print("any_lst1", any(any_lst1))
print("any_lst2", any(any_lst2))
print("any_lst3", any(any_lst3))
print("any_lst4") # print only text to see True in class
print(any(any_lst4)) # You won't see "False in class" before previous item is True (stop here)

# try Morgan !!?
# any = ( not all ( lambda: not item ) )
def new_any(lst):
    return not all(map(lambda x: not x, lst))

print("=== Try with new any but not use any :D", )
print("new_any_empty_list", new_any([]))
print("new_any_lst1", new_any(any_lst1))
print("new_any_lst2", new_any(any_lst2))
print("new_any_lst3", new_any(any_lst3))
print("new_any_lst4") # print only text to see True in class
print(new_any(any_lst4)) # You won't see "False in class" before previous item is True (stop here)

# ascii
# As repr(), return a string containing a printable representation of an object,
# but escape the non-ASCII characters in the string returned by repr() using \x, \u or \U escapes.

class Ascii1:
    def __repr__(self) -> str:
        return 'Hay lắm nhaa'

print(ascii(1))
print(ascii(1.2) == '1.2')
print(ascii(False) == 'False')
print(ascii('Tiếng Việt'))
print(ascii(Ascii1()))
# bin
# Convert an integer number to a binary string prefixed with “0b”.
# The result is a valid Python expression. If x is not a Python int object,
# it has to define an __index__() method that returns an integer

class Bin1:
    def __index__(self):
        return 3

print(bin(42))
print(bin(-42))
print(bin(Bin1()))
# bool
# Return a Boolean value, i.e. one of True or False.
# x is converted using the standard truth testing procedure. 
# If x is false or omitted, this returns False; otherwise it returns True

class Bool1:
    def __init__(self, val) -> None:
        self.val = val

    def __bool__(self):
        return self.val

print("bool()", bool())
print("bool(0)", bool(0))
print("bool(1)", bool(1))
print("bool(-1)", bool(-1))
print("bool('0'))", bool('0')) # haha be careful
print("bool('a')", bool('a'))
print("bool(1.25)", bool(1.25))
print("bool(Bool1(False))", bool(Bool1(False)))
print("bool(Bool1(True))", bool(Bool1(True)))
# callable
# Return True if the object argument appears callable, False if not.
# If this returns True, it is still possible that a call fails, 
# but if it is False, calling object will never succeed.

class Callable1:
    def __call__(self):
        print("haha")

def callable2():
    print("hehe")

callable3 = lambda x: x * x

print(callable(0))
print(callable(False))
print(callable('aaaa'))
print(callable(callable2))
print(callable(callable3))
print(callable(lambda x: x + 1))
print(callable(Callable1()))
# chr
# Return the string representing a character whose Unicode code point is the integer i

print(chr(65))
print(chr(122))
print(chr(7979))
print(chr(99999))
# classmethod (decorator function)
# Transform a method into a class method.
# A class method receives the class as implicit first argument, just like an instance method receives the instance

class ClassMethod1:
    var1 = 1
    @classmethod
    def echo(cls, arg1):
        print(cls, cls.var1, arg1)

class SubClassMethod1(ClassMethod1):
    var1 = 10

ClassMethod1.echo("hello")
SubClassMethod1.echo("hi")
# complex
# Remember complex number ?? Nope, me too, just the name

complex_n1 = complex(1, 2)
complex_n2 = complex('1+2j')

print(complex_n1)
print(complex_n2)
print(complex_n1 + complex_n2)
print(complex_n1 * complex_n2) # I still can't get it :D
# delattr
# remember __dict__ ? this function try to delete key from its __dict__ (can't delete read-only attr)

class DelAttr1:
    var1 = 2
    var2 = 3

print(DelAttr1.__dict__)
print(DelAttr1.var1)
delattr(DelAttr1, "var1")
print(DelAttr1.__dict__)
print(DelAttr1.var1)

# dict
# return a dict from 3 signatures
# dict(**kwarg)
# dict(mapping, **kwarg)
# dict(iterable, **kwarg)

print(dict(a=1, b=2, c=3.4, d='e'))
print(dict([('two', 2), ('one', 1), ('three', 3)])) # list or key-value-tuples
print(list(zip(['a', 'b', 'c'], [1, 2, 3]))) # tricks with zip
print(dict(zip(['a', 'b', 'c'], [1, 2, 3]))) # tricks with zip
print(dict({"a": 1, "b": 2}, c=3))
print(dict(dict(a=1, b=2, c=3.4), c=3)) # like merge-or-update to new dict
# dir
# Without arguments, return the list of names in the current local scope.
# With an argument, attempt to return a list of valid attributes for that object.

class Dir1:
    def __init__(self, dct):
        self.items = dict(dct)

    def __dir__(self): # good match with __getattr__
        return self.items.keys()
    
    def __getattr__(self, name: str): # Custom get dynamic attr
        return self.items.get(name)

print(dir())
print("----------------")
print(dir(ClassMethod1))
print("----------------")
dir1 = Dir1({"a": 1, "b": 2})
print(dir(dir1))
print(dir1.a)
# divmod
# what if you need quotient and remainder also IN SINGLE function

(q1, m1) = divmod(87, 5)
print(q1, m1)

(q2, m2) = divmod(87.3, 7)
print(q2, m2) # floating problem, as close as it can

(q3, m3) = divmod(19, -7)
print(q3, m3) # remainder = 0 or x (with x has same sign of denominator)
# enumerate
# enumerate(iterable, start=0)
# Return an enumerate object. iterable must be a sequence, an iterator, or some other object which supports iteration

enum_lst1 = ["a", "b", "c"]
print(list(enumerate(enum_lst1, 3)))

enum_dct1 = {"x": 1, "y": 20, "z": 4}
print(list(enumerate(enum_dct1, 20)))

# explained
iter1 = iter(enum_dct1)
print(next(iter1), next(iter1), next(iter1))
# eval
# evil function !!! if you don't know what you doing, stay away from it

print(eval('1+2'))
eval_var_outside = 42
print(eval('eval_var_outside*2'))
# filter
# 'construct an iterator' from those elements of iterable for which function returns true

filter_lst1 = [1, 2, 3, 4, 5, 6, 7]
filtered_lst1 = filter(lambda x: x % 2 == 0, filter_lst1)
print(list(filter_lst1))

# only when you read values from iterator, it run the filter function
# let try

print('BEGIN')
filtered_lst2 = filter(lambda x: print(x), filter_lst1)
print('END')

print('Let Get List')
print(list(filtered_lst2))

# What about nested iterator ??
print("==== nested iterator")
filtered_lst3 = filter(lambda y: print("OUT", y) or y, filter(lambda x: print("IN", x) or x, filter_lst1))
filtered_lst3_list = list(filtered_lst3)<jupyter_output>[1, 2, 3, 4, 5, 6, 7]
BEGIN
END
Let Get List
1
2
3
4
5
6
7
[]
==== nested iterator
IN 1
OUT 1
IN 2
OUT 2
IN 3
OUT 3
IN 4
OUT 4
IN 5
OUT 5
IN 6
OUT 6
IN 7
OUT 7
{'fraction_non_alphanumeric': 0.1486182731720217, 'fraction_numerical': 0.03570011900039667, 'mean_word_length': 4.477190441708907, 'pattern_counts': {'":': 7, '<': 4, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '1', 'dir': 'jupyter-structured-clean-dedup', 'id': '564070', 'license': 'CC-BY-3.0', 'n_tokens_mistral': 2802, 'n_tokens_neox': 2681, 'n_words': 916, 'path': 'books/builtin-functions-1.ipynb', 'repo_name': 'khanhicetea/learn-python-intermediate', 'size': '7563'}