Implement CallableMeta and CallableCalss in Python

這篇文章同步發表中文版本

Preface

Recently, I have written LeetCode with friends. Looking at their codes let me get more insight to solve problems.

938. Range Sum of BST

URL: https://leetcode.com/problems/range-sum-of-bst/

Inspired by a Ruby code which wrote by my friend, I wrote the same logical code with Python, as shown below.

938. Range Sum of BST. Using closure block to solve with python.

Off cause, the problem has more quickly, and more simple solution, but this is more interesting.

But, the inner function `block` is dangerous or called “dirty” from Functional Programming.

That because of the function change the outer variable `s` when it executing. (Not enough pure functional)

So, I edited the code below.

More Functional Programming Solution.

or combine to one line.

You can easily change in-order travel to post-order or pre-order, and it’s safety.

771. Jewels and Stones

URL: https://leetcode.com/problems/jewels-and-stones

This problem is easily solved with Python, but it hard to read.

Inspired by LiveScript’s backcall(`<-`), Clojure, cl-arrows(Common Lisp)(`->`), I wrote a pipe function to chain functions.

Simple pipe funciton.

OK, now more easy to understand what the code doing.

  1. Filter characters
  2. Then, Count each unique character
  3. Last, Sum all count

Callable Class

Sometimes, the pipe function is hard to use. That because some function must wrap by lambda to pass arguments. If there is a way to pass arguments, and easily reading too, it must be better. So, I wrote a Class that can wrap data and makes instance callable. If the input function doesn’t exist (None), it will return the processed data.

class CallableWrapper:
def __init__(self, wrap):
self.wrap = wrap
def __call__(self, f=None, *args):
if f == None:
return self.wrap
return CallableWrapper(f(self.wrap, *args))

So, you can use like below.

print(CallableWrapper([1,2,3,4,5,6])
(sum, 10)
(float)
()) # => Oupte: 31.0
# or
(CallableWrapper([1,2,3,4,5,6])
(sum, 10)
(float)
()) # => (31.0,)

※ Note1: Since Python Syntax Limit, Sometimes you must using brackets “()” to wrap expression.

※ Note2: There is a built-in function call `callable`(downcase). It checks an instance is callable. If callable return True, else False.(So…`callable(CallableWrapper([1,2,3,4,5])) #=> True`)

Callable Meta-Class

But…how about the custom class? It’s possibly easy to make a new class is callable? Well, it’s possible, and I wrote a meta-class, as shown below..

Callable Class and Callable Meta-Calss
class CallableList(list, Callable): # or class CallableList(list, metaclass = CallableMeta):
def hello(self):
print("Hello World")
a = CallableList([1,2,3,4,5,6]) # => CallableList(a)
print(callable(a)) # => True
print(a) # => [1,2,3,4,5,6]
print(a()) # => [1,2,3,4,5,6]
print(a(sum)()) # => 21
print(a(sum)
(lambda x,i: x+i, 50)()) # => 71

You can use `metaclass=CallableMeta` when designing a new class(or directly inherit `Callable`). Define class `__call__` to override CallableMeta behavior(That means it’s useless to assign CallableMeta as metaclass). And with `super()`, that like pre-do or post-do. (A little like the decorator)

At last

With CallableMeta Class, the instance seems like has dynamic methods.

If you have other opinions or found bugs, be relax to leave your opinion. After reading this article, you can read more :

  • maybe, pydash has a similar way to do.
  • You can go to GitHub Gist found all codes.
  • Maybe, I will write and collect to a package for myself
  • or to read the Chinese version of this article.

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
又LAG(lagagain)

Hi, I am lagagain. I very like Information Technology. More about me, you can go to http://about.lagagain.com/.