What's the Python version for “Code against an interface, not an object”?

后端 未结 4 2061
长情又很酷
长情又很酷 2021-01-30 06:45

Inspired by a great question (and bunch of great answers) from here.

Does the statement \"Code against an interface, not an object\" have any significance in Python?

相关标签:
4条回答
  • 2021-01-30 07:14

    "Code against an interface, not an object" doesn't make literal sense in Python because the language doesn't have an interface feature. The rough Python equivalent is "use duck typing." If you want to see if an object is a duck, in other words, you should check to see whether it has a quack() method, or better yet try to quack() and provide appropriate error handling, not test to see if it is an instance of Duck.

    Common duck types in Python are files (well, really, file-like objects), mappings (dict-like objects), callables (function-like objects), sequences (list-like objects), and iterables (things you can iterate over, which can be containers or generators).

    As an example, Python features that want a file will generally be happy to accept an object that implements the methods of file it needs; it needn't be derived from the file class. To use an object as standard out, for example, the main thing it is going to need is a write() method (and maybe flush() and close(), which needn't actually do anything). Similarly, a callable is any object that has a __call__() method; it needn't be derived from the function type (in fact, you can't derive from the function type).

    You should take a similar approach. Check for the methods and attributes you need for what you're going to do with an object. Better yet, document what you expect and assume that whoever is calling your code is not a total doofus. (If they give you an object you can't use, they will certainly figure that out quickly enough from the errors they get.) Test for specific types only when necessary. It is necessary at times, which is why Python gives you type(), isinstance(), and issubclass(), but be careful with them.

    Python's duck typing is equivalent to "code against an interface, not an object" in the sense that you're advised not to make your code too reliant on an object's type, but rather to see whether it has the interface you need. The difference is that in Python, "interface" just means an informal bundle of attributes and methods of an object that provide a certain behavior, rather than a language construct specifically named interface.

    You can formalize Python "interfaces" to some extent using the abc module, which allows you to declare that a given class is a subclass of a given "abstract base class" (interface) using any criteria you desire, such as "it has attributes color, tail_length, and quack, and quack is callable." But this is still much less strict than static languages having an interface feature.

    0 讨论(0)
  • 2021-01-30 07:16

    An interface means you expect certain methods to be present and standardised across objects; that is the point of an interface or abstract base class, or whatever implementation you wish to consider.

    For example (Java), one might have an interface for symmetric encryption like so:

    public interface cipher 
    {
        public void encrypt(byte[] block, byte[] key); 
        public void decrypt(byte[] block, byte[] key);    
    }
    

    Then you can implement it:

    public class aes128 implements cipher
    { 
        public void encrypt(byte[] block, byte[] key)
        {
            //...
        }
        public void decrypt(byte[] block, byte[] key)
        {
            //...
        }
    }
    

    It is then possible to declare an object like so:

    cipher c;
    

    What have we done here? Well, we've created this object c whose type must match that of the interface. c can refer to anything that matches this interface, so the next stage would be:

    c = new aes128();
    

    You can now call methods you expect a cipher to have.

    That's java. Now here's what you do in python:

    class aes128(Object):
    
        def __init__(self):
            pass
    
        def encrypt(self, block, key):
            # here I am going to pass, but you really 
            # should check what you were passed, it could be 
            # anything. Don't forget, if you're a frog not a duck
            # not to quack!
            pass
    

    When you want to use this, and you're not sure that the object you've been passed is, just try to use it:

    c = aes128()
    try:
        c.encrypt(someinput, someoutput)
    except:
        print "eh? No encryption method?!"
    

    Here, you're relying on c.encrypt's implementation to raise if it can't handle what it has been passed, if the method exists. Of course, if c is a string type and therefore not of the right type you require, it will also throw automatically, and you will catch (hopefully).

    In short, one form of programming is typed such that you have to obey the interface rules, the other is saying you don't even need to write them down, you simply trust that if it didn't error, it worked.

    I hope that shows you the practical difference between the two.

    0 讨论(0)
  • 2021-01-30 07:25

    What's the Python version for “Code against an interface, not an object.”?

    The proper quote is "program against an interface, not an implementation". The principle holds the same way in Python that it did in Smalltalk, the language it in which it originated.

    Does the statement "Code against an interface, not an object." have any significance in Python?

    Yes. It has the same significance in Python as it has in the language that this quote originated from (Smalltalk), and in every other language.

    0 讨论(0)
  • 2021-01-30 07:29

    To understand interfaces in Python you have to understand duck-typing. From the very Python glossary:

    duck-typing: A programming style which does not look at an object’s type to determine if it has the right interface; instead, the method or attribute is simply called or used (“If it looks like a duck and quacks like a duck, it must be a duck.”) By emphasizing interfaces rather than specific types, well-designed code improves its flexibility by allowing polymorphic substitution. Duck-typing avoids tests using type() or isinstance(). (Note, however, that duck-typing can be complemented with abstract base classes.) Instead, it typically employs hasattr() tests or EAFP programming.

    Python encourages coding for interfaces, only they are not enforced but by convention. Concepts like iterables, callables or the file interface are very pervasive in Python - as well the builtins that rely on interfaces like map, filter or reduce.

    0 讨论(0)
提交回复
热议问题