Movatterモバイル変換


[0]ホーム

URL:


Skip to content
DEV Community
Log in Create account

DEV Community

Konstantin
Konstantin

Posted on

     

Solving the "Chicken-Egg" problem with Python

Hello!

Nothing could be more tasty to Python than chicken and eggs. So today our Python decided to resolve an old phylosophical question: what was the first, chicken or egg. In order to do it, it has decided to create two classes and then to perform some modelling to make an ultimate answer to this question.

Ok, let's start. Our Python is a grand-pa of all pythons, and it's serial number is 2.7. To begin with, it created 3 files:

# filename: models/egg.pyimport models.chickenclass Egg(object):    def __init__(self, name):        super(Egg, self).__init__()        self.name = name    def wait(self):        return models.chicken.Chicken("Chicken from [{self.name}]".format(self=self))
# filename: models/chicken.pyimport models.eggclass Chicken(object):    def __init__(self, name):        super(Chicken, self).__init__()        self.name = name    def create_egg(self):        return models.egg.Egg("Egg of [{self.name}]".format(self=self))
# filename: main.pyimport models.chickenif __name__ == '__main__':    # Decision maker!    c = models.chicken.Chicken("Ryaba")    print(c.create_egg().wait().create_egg().name)

Grand-pa Python is happy with the results:

$ python2.7 main.py Egg of [Chicken from [Egg of [Ryaba]]]

For those of you who are sceptical about the circular dependencies in Python - yes, they are supported, but only to some extent. Generally, when the interpreter seesimport models.egg it checks if this module is imported and if it is, uses the address of this module from the cache. If it is not, it immediately creates a record in the cache and then starts doing actual import. That's why if you only haveimport <module_name> statements in your code you are safe.

As soon as we decide to usefrom <module_name> import <object> statement, our circular dependencies will not be able to be resolved. Let's try it!

# filename: models/egg.pyfrom models.chicken import Chickenclass Egg(object):    def __init__(self, name):        super(Egg, self).__init__()        self.name = name    def wait(self):        return Chicken("Chicken from [{self.name}]".format(self=self))
# filename: models/chicken.pyfrom models.egg import Eggclass Chicken(object):    def __init__(self, name):        super(Chicken, self).__init__()        self.name = name    def create_egg(self):        return Egg("Egg of [{self.name}]".format(self=self))
$ python2.7 main.py Traceback (most recent call last):  File "main.py", line 1, in <module>    import models.chicken  File "/data/models/chicken.py", line 1, in <module>    from models.egg import Egg  File "/data/models/egg.py", line 1, in <module>    from models.chicken import ChickenImportError: cannot import name Chicken$ python3.7 main.py Traceback (most recent call last):  File "main.py", line 1, in <module>    import models.chicken  File "/data/models/chicken.py", line 1, in <module>    from models.egg import Egg  File "/data/models/egg.py", line 1, in <module>    from models.chicken import ChickenImportError: cannot import name 'Chicken' from 'models.chicken' (/data/models/chicken.py)

This is more or less predictable and it is a real chicken-egg problem. In order to importChicken class to theegg module you need to parsechicken module (so, just an address of a module is not enough), and in order to completely parsechicken module, you need to complete parsing of anegg module. So, no way.

OK. And now I need your full attention: we are going to replaceimport <package>.<module> byfrom <package> import <module>.

# filename: models/egg.pyfrom models import chickenclass Egg(object):    def __init__(self, name):        super(Egg, self).__init__()        self.name = name    def wait(self):        return chicken.Chicken("Chicken from [{self.name}]".format(self=self))
# filename: models/chicken.pyfrom models import eggclass Chicken(object):    def __init__(self, name):        super(Chicken, self).__init__()        self.name = name    def create_egg(self):        return egg.Egg("Egg of [{self.name}]".format(self=self))

And the result is a bit unexpectable:

$ python2.7 main.py Traceback (most recent call last):  File "main.py", line 1, in <module>    import models.chicken  File "/data/models/chicken.py", line 1, in <module>    from models import egg  File "/data/models/egg.py", line 1, in <module>    from models import chickenImportError: cannot import name chicken$ python3.7 main.py Egg of [Chicken from [Egg of [Ryaba]]]

So, Python3 changed the way how packages are imported, generally they are appended to the sys.modules earlier than Python2. Good to know.

And the last surprise for today. Now we are usingimport <package>.<module> as <alias> syntax.

# filename: models/egg.pyimport models.chicken as chickenclass Egg(object):    def __init__(self, name):        super(Egg, self).__init__()        self.name = name    def wait(self):        return chicken.Chicken("Chicken from [{self.name}]".format(self=self))
# filename: models/chicken.pyimport models.egg as eggclass Chicken(object):    def __init__(self, name):        super(Chicken, self).__init__()        self.name = name    def create_egg(self):        return egg.Egg("Egg of [{self.name}]".format(self=self))

And can you predict the output?

$ python2.7 main.py Traceback (most recent call last):  File "main.py", line 1, in <module>    import models.chicken  File "/data/models/chicken.py", line 1, in <module>    import models.egg as egg  File "/data/models/egg.py", line 1, in <module>    import models.chicken as chickenAttributeError: 'module' object has no attribute 'chicken'$ python3.6 main.py Traceback (most recent call last):  File "main.py", line 1, in <module>    import models.chicken  File "/data/models/chicken.py", line 1, in <module>    import models.egg as egg  File "/data/models/egg.py", line 1, in <module>    import models.chicken as chickenAttributeError: module 'models' has no attribute 'chicken'$ python3.7 main.py Egg of [Chicken from [Egg of [Ryaba]]]

Python3.7 won :) Ok. What is really happened here is that there was abug in theimport A.B.C as D syntax which wasfixed in the version 3.7.

Thanks for reading!

Top comments(0)

Subscribe
pic
Create template

Templates let you quickly answer FAQs or store snippets for re-use.

Dismiss

Are you sure you want to hide this comment? It will become hidden in your post, but will still be visible via the comment'spermalink.

For further actions, you may consider blocking this person and/orreporting abuse

  • Location
    London
  • Joined

More fromKonstantin

DEV Community

We're a place where coders share, stay up-to-date and grow their careers.

Log in Create account

[8]ページ先頭

©2009-2025 Movatter.jp