{"id":3757,"date":"2016-03-08T06:00:56","date_gmt":"2016-03-08T11:00:56","guid":{"rendered":"http:\/\/kodegeek.com\/blog\/?p=3757"},"modified":"2016-03-06T12:11:06","modified_gmt":"2016-03-06T17:11:06","slug":"functors-en-python","status":"publish","type":"post","link":"http:\/\/kodegeek.com\/blog\/2016\/03\/08\/functors-en-python\/","title":{"rendered":"Functors en Python"},"content":{"rendered":"<p>Un &#8216;functor&#8217; es u objeto el cual puede ser llamado como si fuera una funci\u00f3n. En Python simplemente hay que implementar el m\u00e9todo &#8216;__call__&#8217;. En este ejemplo, vamos a tomar a los candidatos presidenciales del articulo anterior y vamos a escribir una peque\u00f1a clase (llamada SortKey) la cual nos va a permitir ordenar por cualquier attributo o combinaci\u00f3n de attributos (en nuestro ejemplo vamos a ordendar por sexo y luego por edad):<\/p>\n<pre lang=\"python\">\r\n#!\/usr\/bin\/env python3\r\n# A little fun with the candidates for the US presidency for 2016 election year\r\n# Revisited versions with functors, slots, abstract classes\r\n# @author josevnz@kodegeek.com\r\n#\r\nimport abc\r\n\r\nclass SortKey:\r\n    \r\n    def __init__(self, *attributes):\r\n        self.attributes = attributes\r\n    def __call__(self, instance):\r\n        return [getattr(instance, attribute) for attribute in self.attributes]\r\n\r\nclass Candidate(metaclass=abc.ABCMeta):\r\n    \r\n    __slots__ = (\"__name\", \"__sex\", \"__age\")\r\n\r\n    @abc.abstractmethod    \r\n    def __init__(self, name, sex=\"F\", age=21):\r\n        self.__name = name\r\n        self.__sex = \"F\" if sex not in [\"M\", \"F\"] else sex\r\n        self.__age = 21 if not (21 < = age <= 120) else age\r\n    \r\n    @property\r\n    def name(self):\r\n        return self.__name\r\n    \r\n    def get_party(self):\r\n        raise NotImplemented()\r\n    \r\n    party = abc.abstractproperty(get_party)\r\n    \r\n    @property\r\n    def sex(self):\r\n        return self.__sex\r\n    \r\n    @property\r\n    def age(self):\r\n        return self.__age\r\n    \r\n    def __hash__(self):\r\n        return hash(id(self))\r\n    \r\n    def __str__(self):\r\n        return \"{}=[name={}, sex={}, age={}]\".format(self.__class__.__name__,\r\n                                                            self.__name,\r\n                                                            self.__sex,\r\n                                                            self.__age\r\n                                                            )\r\n    \r\n    def __repr__(self):\r\n        return \"{}({}{}{}{})\".format(\r\n                                 self.__class__.__name__, \r\n                                 self.__name, \r\n                                 self.__sex, \r\n                                 self.__age\r\n                                )\r\n    \r\n    @abc.abstractmethod\r\n    def __bool__(self):\r\n        raise NotImplemented()\r\n    \r\n    def __lt__(self, other):\r\n        return self.__age < other.__age\r\n    \r\n    def __gt__(self, other):\r\n        return self.__age > other.__age\r\n    \r\n    def __eq__(self, other):\r\n        return (\r\n                self.__age == other.__age and \r\n                self.__name == other.__name and\r\n                self.__sex == other.__sex\r\n                )\r\n\r\nclass Republican(Candidate):\r\n    \r\n    def __init__(self, name, sex=\"F\", age=21):\r\n        return super().__init__(name, sex, age)\r\n    \r\n    party = \"Replublican Party (GOP)\"\r\n    \r\n    def __bool__(self):\r\n        return False\r\n            \r\nclass Democrat(Candidate):\r\n    \r\n    def __init__(self, name, sex=\"F\", age=21):\r\n        return super().__init__(name, sex, age)\r\n    \r\n    party = \"Democratic Party\"\r\n    \r\n    def __bool__(self):\r\n        return True\r\n    \r\nif __name__ == \"__main__\":\r\n        candidates = []\r\n        candidates.append(Democrat(\"Hillary Clinton\", \"F\", 68))\r\n        candidates.append(Republican(\"Donald Trump\", \"M\", 70))\r\n        candidates.append(Democrat(\"Bernie Sanders\", \"M\", 75))\r\n        candidates.append(Republican(\"Marco Rubio\", \"M\", 45))\r\n        candidates.sort(key=SortKey(\"sex\", \"age\"), reverse=False)\r\n        for candidate in candidates:\r\n            isDemocrat = \"yes\" if candidate else \"no\"\r\n            print(\"Candidate: {}, democrat? {}\".format(candidate, isDemocrat))        \r\n<\/pre>\n<p>Y la salida (f\u00edjense que definimos el orden en la linea 103, ademas de que ordenamos la lista primero para despu\u00e9s utilizarla):<\/p>\n<pre lang=\"bash\">\r\nCandidate: Democrat=[name=Hillary Clinton, sex=F, age=68], democrat? yes\r\nCandidate: Republican=[name=Marco Rubio, sex=M, age=45], democrat? no\r\nCandidate: Republican=[name=Donald Trump, sex=M, age=70], democrat? no\r\nCandidate: Democrat=[name=Bernie Sanders, sex=M, age=75], democrat? yes\r\n<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>Un &#8216;functor&#8217; es u objeto el cual puede ser llamado como si fuera una funci\u00f3n. En Python simplemente hay que implementar el m\u00e9todo &#8216;__call__&#8217;. En este ejemplo, vamos a tomar a los candidatos presidenciales del articulo anterior y vamos a escribir una peque\u00f1a clase (llamada SortKey) la cual nos va a permitir ordenar por cualquier <a class=\"read-more\" href=\"http:\/\/kodegeek.com\/blog\/2016\/03\/08\/functors-en-python\/\">[&hellip;]<\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[438,239],"tags":[797,798,765],"_links":{"self":[{"href":"http:\/\/kodegeek.com\/blog\/wp-json\/wp\/v2\/posts\/3757"}],"collection":[{"href":"http:\/\/kodegeek.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/kodegeek.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/kodegeek.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/kodegeek.com\/blog\/wp-json\/wp\/v2\/comments?post=3757"}],"version-history":[{"count":2,"href":"http:\/\/kodegeek.com\/blog\/wp-json\/wp\/v2\/posts\/3757\/revisions"}],"predecessor-version":[{"id":3759,"href":"http:\/\/kodegeek.com\/blog\/wp-json\/wp\/v2\/posts\/3757\/revisions\/3759"}],"wp:attachment":[{"href":"http:\/\/kodegeek.com\/blog\/wp-json\/wp\/v2\/media?parent=3757"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/kodegeek.com\/blog\/wp-json\/wp\/v2\/categories?post=3757"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/kodegeek.com\/blog\/wp-json\/wp\/v2\/tags?post=3757"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}