简体   繁体   中英

Question about python module and calling a function from it

So I have been wracking my brain trying to figure this out for like 2 hours. As I understood it, when I define a module with functions, and move to a new file, I can import that module. Then to call a function from that module I can do something like module_name.function_name(inputs). Note that there is only one period!

So, there is a module called itertools. When I import itertools , I can call itertools.chain (list or list of lists) and it will create an iterator object for me. HOWEVER, now this is the part I don't get, I can ALSO call itertools.chain.from_iterable and it will ALSO create a different iterator object for me. I dont get how this is possible? How can itertools.chain and itertools.chain.from_iterable both be functions that return something, and how would I go about creating a module like that?

How can there be 2 periods in 1 function call when the stuff before the first period isnt a class? (I can also import classes from a module and then call methods defined within the class using Class_name.method_name(inputs). however I'm pretty sure chain is a function and not a class because it returns an output!!)

As @khelwood said in his/her comment, itertools.chain is a class, and therefore you are just calling a classmethod through itertools.chain.from_iterable : https://docs.python.org/fr/3/library/itertools.html#itertools.chain.from_iterable

EDIT (I didn't realize first link was in french, apologies) https://docs.python.org/3/library/itertools.html#itertools.chain.from_iterable

itertools.chain.from_iterable isn't a normal method, its a classmethod.

When classmethod is called, it gets the class as the first argument instead of the instance of that class (as we normally do with methods). This means we can use the class and its properties inside that method rather than a particular instance. Class methods are useful when you need to have methods that aren't specific to any particular instance.

There are several ways an object can be callable like a function and also have attributes.

  1. Add attributes to a function:
def chain(...):
    # logic of itertools.chain

chain.from_iterable = lambda *args: # logic of itertools.chain.from_iterable
  1. Create an object with a __call__ method:
class ChainClass:
    def __call__(self, ...):
        # logic of itertools.chain
    def from_iterable(self, ...):
        # logic of itertools.chain.from_iterable

chain = ChainClass()
# now chain is callable and chain.from_iterable is callable
  1. itertools.chain is actually a class:
class chain:
    def __init__(self, ...):
        # logic of itertools.chain
    @classmethod
    def from_iterable(cls, ...):
        # logic of itertools.chain.from_iterable

For itertools.chain , it is actually a class (though it is built-in, not written in Python). When you call itertools.chain([]) , you are instantiating the class.

You can verify that:

import itertools
ch = itertools.chain([])
isinstance(ch, itertools.chain) # True

Code example for itertools Chain in Python using Class

Reference: Need to implement the Python itertools function “chain” in a class

Code

File: my_itertools.py

class chain:
  def __init__(self, *iterables):         # Normal Constructor
    self.list = iter(iterables)           # iterator for iterables
    self.current = iter(next(self.list))  # current is first iterable in list

  def __iter__(self):
    while True:
      try:
        yield next(self.current)          # loop through current

      except StopIteration:               # out of current, set current to next
          try:
                                          # set next iterable
            self.current = iter(next(self.list))

          except StopIteration:
              break                       # Done, since have gone through list of all
                                          # iterables

  @classmethod
  def from_iterable(cls, iterables):    # Alternative constructor
    return cls(*iterables)              # returns a chain object
    

Usage

File: main.py

import my_itertools

a = [1, 2, 3]
b = [4, 5, 6]

for i in my_itertools.chain(a, b):
  print('chain: ', i)
# Outputs
chain:  1
chain:  2
chain:  3
chain:  4
chain:  5
chain:  6

for i in my_itertools.chain.from_iterable([a, b]):
  print('from iterable ', i)
# Outputs:
from iterable  1
from iterable  2
from iterable  3
from iterable  4
from iterable  5
from iterable  6

y = list(my_itertools.chain([1, 2, 3]))
print('y: ', y)
# Output: y:  [1, 2, 3]

print(f'Type {type(my_itertools.chain([1, 2, 3]))}')
Output: Type <class 'my_itertools.chain'>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM