<jupyter_start><jupyter_text>BUILT-IN FUNCTIONS - Part 2<jupyter_code># float
# Return a floating point number constructed from a number or string x

class Float1:
    def __index__(self):
        return 123

    def __float__(self):
        return -13579.2468

class Float2:
    def __index__(self):
        return 234

print(float(123))
print(float(123.456))
print(float('-123.456'))
print(float('    -123.456'))
print(float('-0.4E7'))
print(float(Float1()))
print(float(Float2()))
print(float('-Infinity'))
print(float('-Infinity')+float('+Infinity')) # = 0 ? LOL !!
# getattr
# getattr(object, name[, default])
# Return the value of the named attribute of object. name must be a string.
# If the string is the name of one of the object’s attributes, the result is the value of that attribute

class GetAttr1:
    def __init__(self) -> None:
        self.a = 123
        self.__b = 678 # private-name-mangling , this attr only access in the class, not public with new name _[ClassName]__[var]
    
    def get_b(self):
        return self.__b

float1_func = getattr(Float1, '__float__')
print(float1_func('anything'))

getattr1 = GetAttr1()
print(getattr(getattr1, 'a'))
print(getattr(getattr1, '_GetAttr1__b')) # access new name
print(getattr1.get_b()) # through public getter
print(getattr(getattr1, '__b')) # but can't this way

# globals
# Return a dictionary representing the current global symbol table.
# This is always the dictionary of the current module (inside a function or method, 
# this is the module where it is defined, not the module from which it is called)

print(type(globals()))
print(globals()['getattr1']) # get variable in above cell
# hasattr
# The arguments are an object and a string. The result is True if the string is the name of one of the object’s attributes, False if not.
# (This is implemented by calling getattr(object, name) and seeing whether it raises an AttributeError or not.)

print(hasattr(GetAttr1, 'get_b'))
print(hasattr(getattr1, 'get_b'))
print(hasattr(getattr1, 'a'))
print(hasattr(getattr1, '_GetAttr1__b'))
print(hasattr(getattr1, '__b')) # can not access, so return False

# hash
# Return the hash value of the object (if it has one). Hash values are integers.
# They are used to quickly compare dictionary keys during a dictionary lookup. 
# Numeric values that compare equal have the same hash value (even if they are of different types, as is the case for 1 and 1.0).

print(hash(getattr1))
print(hash(1))
print(hash(1.0))
print(hash(1.000001))
print(hash("hello world"))
print(hash("hello world") == hash("hello world"))
# dict is complicated ordered key-values so can't be hashed
print(hash(dict(a=1, b=2)))
# hex
# Convert an integer number to a lowercase hexadecimal string prefixed with “0x”

print(hex(123))
print(hex(-53))
# id
# Return the “identity” of an object. This is an integer which is guaranteed to be unique and constant
# for this object during its lifetime. Two objects with non-overlapping lifetimes may have the same id() value.
# In CPython : This is the address of the object in memory.

print(id(getattr1))
print(id(123))
print(id(GetAttr1))
print(id(GetAttr1()))

# input
# If the prompt argument is present, it is written to standard output without a trailing newline.
# The function then reads a line from input, converts it to a string (stripping a trailing newline), and returns that.

print(input("Type you var value = ")) # In jupyter, it opens modal to ask value
# int
# Return an integer object constructed from a number or string x, or return 0 if no arguments are given

print(int('-123'))
print(int('12312'))
print(int('011', base=2))
print(int('071', base=8))
print(int('0xfe', base=16))
# isinstance
# isinstance(object, classinfo)
# Return True if the object argument is an instance of the classinfo argument, 
# or of a (direct, indirect or virtual) subclass thereof. If object is not an object of the given type,
# the function always returns False. If classinfo is a tuple of type objects (or recursively, other such tuples),
# return True if object is an instance of any of the types.
# If classinfo is not a type or tuple of types and such tuples, a TypeError exception is raised.

print(isinstance(getattr1, GetAttr1))
print(isinstance(getattr1, (Float1, Float2, GetAttr1)))
print(isinstance(True, bool))
print(isinstance(True, type(False)))
print(isinstance(True, True))
# issubclass
# issubclass(class, classinfo)
# Return True if class is a subclass (direct, indirect or virtual) of classinfo. 
# A class is considered a subclass of itself. classinfo may be a tuple of class objects, 
# in which case return True if class is a subclass of any entry in classinfo. 
# In any other case, a TypeError exception is raised.

class Float3(Float1):
    pass

print(issubclass(Float3, Float1))
print(issubclass(Float3, Float2))
print(issubclass(Float3, (Float2, Float1)))
print(issubclass(Float3, type))
# iter
# iter(object[, sentinel])

iter_lst1 = [1, 2, 3]

print(iter(iter_lst1))
print(tuple(iter(iter_lst1))) # convert interator to tuple or list

# with sentinel , if next item equals sentinel , StopIteration will be raised to stop

class Iter1:
    def __init__(self):
        self.count = 0
  
    def __call__(self):
        self.count = self.count + 1
        return self.count

iter_obj1 = Iter1()
print(dir(iter_obj1))
print(list(iter(iter_obj1, 10)))

iter_obj2 = Iter1()
for iter_val2 in iter(iter_obj2, 5):
    print(iter_val2)
# len
# Return the length (the number of items) of an object. The argument may be a sequence (such as a string, bytes, tuple, list, or range) 
# or a collection (such as a dictionary, set, or frozen set).

print(len("123 456 789"))
print(len("Tiếng Việt")) # unicode => not len of bytes
print(len([3, 2 , 1]))
print(len((3, 2 , 1)))
print(len(range(0, 10)))
print(len({"a": 1, "b": 2, "c": { "x": 1, "y": 3 }})) # first level keys
print(len({1, 2, 3}))
# list
# list([iterable])
# Rather than being a function, list is actually a mutable sequence type

print(list("123"))
print(list(iter(Iter1(), 10)))
# map
# map(function, iterable, ...)
# Return an iterator that applies function to every item of iterable, yielding the results

map_lst1 = list(range(1, 10))
print(map_lst1)

# Btw, just for lab, should not write 3 lambdas in 1 line
map1 = map(lambda x: x * 2, map(lambda y: y + 1, filter(lambda z: z % 2 == 0, map_lst1))) # each iter cycle run from inside to outside => filter even => +1 => * 2
print(list(map1))

# run 1 lambda parallel with multi parameters
def map_lambda_multi1(x, y):
    return x + y

map2 = map(map_lambda_multi1, [1, 2, 3], [100, 200, 300])
print(list(map2))
# max
# max(iterable, *[, key, default])
# max(arg1, arg2, *args[, key])
# Return the largest item in an iterable or the largest of two or more arguments.

print(max(map_lst1))
print(max(8, 5, 100, 9))

# with key
max_lists = [{"num": x} for x in range(0, 10)]
print(max_lists)
print(max(max_lists, key=lambda x: x['num']))

# max of empty
print(max([])) # ValueError
# min
# Opposite of above max

print(min(map_lst1))
print(min(8, 5, 100, 9))

# with key
min_lists = [{"num": x} for x in range(0, 10)]
print(min_lists)
print(min(min_lists, key=lambda x: x['num']))

# min of empty
print(min([])) # ValueError
# next
# Retrieve the next item from the iterator by calling its __next__() method. 
# If default is given, it is returned if the iterator is exhausted, otherwise StopIteration is raised.

iter_next1 = map(lambda x: x * 2, map_lst1)
print(next(iter_next1)) # get first item out
make_list_from_next = [next(iter_next1) for i in range(0, 3)]
print(make_list_from_next)

make_list_from_next = [next(iter_next1) for i in range(0, 100)] # StopIteration is raised<jupyter_output>2
[4, 6, 8]
{'fraction_non_alphanumeric': 0.11935275080906149, 'fraction_numerical': 0.03313915857605178, 'mean_word_length': 4.731454005934718, 'pattern_counts': {'":': 7, '<': 4, '<?xml version=': 0, '>': 9, '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': '563880', 'license': 'CC-BY-3.0', 'n_tokens_mistral': 2655, 'n_tokens_neox': 2502, 'n_words': 983, 'path': 'books/builtin-functions-2.ipynb', 'repo_name': 'khanhicetea/learn-python-intermediate', 'size': '7725'}