i2mint / i2

Python Mint creation, manipulation, and use
Apache License 2.0
2 stars 1 forks source link

Transform a function to a method sourcing some arguments from instance (`i2.wrapper` use case) #20

Open thorwhalen opened 2 years ago

thorwhalen commented 2 years ago

I have functions and I'd like to use them to make methods for a class. Some of the method arguments of the instance of this class will not be present in the method (1) but source itself from properties of the instance.

(1) Another form of this might be that the argument is present (in the signature and can be used when calling the method), but the default is sourced by a property.

Example:

from dataclasses import dataclass

def foo(x, y, z): 
    return x + y * z

@dataclass
class Klass:
    x: int
    zoo: int = 2
    ...
    bar = methodize(foo, bind=['x', ('z', zoo)])

c = Klass(x=1, zoo=2)
assert c.bar(y=3) == c.bar(3) == 7 == foo(x=1, y=3, z=2) 

In our example above, the bind argument of methodize can be a dict or an iterable of strings or string pairs, or a string of identifiers separate by spaces. This is so that when the name mappings are trivial (like bind={'x': 'x', 'y': 'y': 'z': 'z'}) we don't have to write that, but can write bind=('x', 'y', 'z') or even bind='x y z' instead.

┆Issue is synchronized with this Asana task by Unito

thorwhalen commented 2 years ago

A form of this already exists in py2http.decorators

image

That one has a few limitations though:

It does have an "ignore excess" functionality (by default though) that could be useful (to bulk-transform many functions at once).

(1)

from tested import validate_codec

assert validate_codec(c.bar) == False
thorwhalen commented 2 years ago

There's also a less than four months old func_to_method_func in i2.wrapper and a make_funcs_binding_class in i2.wrapper using it.

That one is more flexible than py2https methodizer, but also has limitations: Can't bind names (the names of the functions need to be as they will be found in the init. This also means we can only bring these functions together in a class if no same name has two different meanings in different functions, and no same meaning has two different names in different functions.

One way to get out of that situation "externally" is to use i2.wrapper.map_names to carry out the binding need.

If the user expects to do this often, then allowing methodizer functions to handle it would be easier for them.