2

In the toolz project, is there anyway to treat an objects method similarly to a function, so i can better compose, curry, etc. ?
by better i mean readability, and similar performance

Heres a trivial example:

# given a list strings (names),
l = ["Harry"  ,
    "Sally  "    ,
    " bEn " ,
    " feDDy "  ]

# Lets pretend I want to apply a few simple string methods on each item in the
# list (This is just an example), and maybe replace as it's multi-airity.

# Traditional python list comprehension:
print([x.strip().lower().title().replace('H','T') for x in l ])

['Tarry', 'Sally', 'Ben', 'Feddy']

# my attempt, at toolz, same question with compose, curry,
# functools.partial.

from toolz.functoolz import pipe, thread_last
thread_last(l,
            (map , str.strip),
            (map , str.lower),
            (map , str.title),
            (map , lambda x: x.replace('H','T')), # any better way to do this?
            # I wish i had function/method `str.replace(__init_value__, 'H', 'T')` where the
            # `__init_value` is what I guess would go to the str constructor?
            list,
            print)

I don't like all extra lambda... and I couldn't imagine that would be ok for performance. Any tips on how to make this better with toolz?

With the operators module i can make most operators less painful and omit lambdas for things like addition, subtraction, etc.

Is there anything similar for method calls in recent versions of python?

joefromct
  • 1,506
  • 13
  • 33
  • Well, you can just use `str.strip`, `str.lower` etc directly, no need for lambda. All methods still exist as attributes that are function objects in the class namespace. – juanpa.arrivillaga Dec 15 '17 at 22:18
  • What about if i wanted to do a `''.join()` on the name list? I think what i'm wishing for is something like a function such as `str.join(__init_, x)` or something... where the function/method accepts what would be instantiated as the class identity. – joefromct Dec 15 '17 at 22:45
  • FYI, updated with a `replace` function, maybe that shows the discomfort with usage when it gets a bit more complex for the method call. – joefromct Dec 15 '17 at 22:49

1 Answers1

5

Note that x.replace(y, z) is indeed str.replace(x, y, z). You can use a partial is a particular replacement is used often.

Same applies to the rest of the methods: if you access a method via class, it's unbound, and the first argument (self) is a normal argument of a function. No magic around it. (Instance methods are partially applied, locking their self value to the instance.)

So, I'd hazard thread_last(l, (map, pipe(str.strip, str.lower, str.title)) to apply three functions to each string element.

(If you're into FP in Python, take a look at http://coconut-lang.org/)

9000
  • 39,899
  • 9
  • 66
  • 104
  • so thats what `self` has done all this time... thanks. I guess I just figured it did some other magic similarly to a constructor or something in other OO languages. – joefromct Dec 20 '17 at 05:01
  • 2
    the magic that a constructor (or, rather, `__new__`) does is, among other things, something like `instance.foo = partial(cls.foo, instance)` for each method. you can override your class and instance creation using the `__metaclass__` protocol; read about it, it's fun, and uncovers most of the inner "magic". – 9000 Dec 20 '17 at 15:36