Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Primitive call #461

Merged
merged 11 commits into from Mar 13, 2019
Merged

Primitive call #461

merged 11 commits into from Mar 13, 2019

Conversation

@CharlesBradshaw
Copy link
Contributor

CharlesBradshaw commented Mar 12, 2019

We don't want to call get_function in the init.

We could store the output of self.get_function() and check if that exists every time in the call function.

def __call__(self,data):
    if not hasattr(self,method):
        self.method = self.get_function()
    return self.method(data)

That goes against the pythonic "it's Easier to Ask for Forgiveness than Permission" (EAFP) in this case we're using "Look Before You Leap" (LBYL). To fix this we can use a try except instead.

def __call__(self,data):
    try:
        return self.method(data)
    except AttributeError:
        self.method = self.get_function()
        return self.method(data)

We already know when we need to call get_function , and it's on the first time __call__ is run. So instead of using the try except function we can call get_function in the __call__ function, and then redefine __call__ to be the output of get_function This way there are no unnecessary checks

def __call__(self,data):
    self.__call__ = self.get_function()
    return self.__call__(data)

This approach doesn't work because __call__ is a special method. When a class instance, for example primitive gets called like primitive(data), python under the hood runs type(primitive).__call__(primitive,data) instead of primitive.__call__data

We can get around this by using a non special method as an intermediate.

def __call__(self,*args,**kwargs):
    self._temp_call(*args,**kwargs)

def _temp_call(self, *args, **kwargs):
    self._temp_call = self.get_function().__get__(self)
    return self._temp_call(*args,**kwargs)

This way the second time _temp_call has been called, it's set to the output of get_function.

Note that the self.get_function() has __get__(self) also. This is because to add a function to an instance of a class, and not the class itself, you have to bind the instance to the function, aka add self as the first parameter always. I don't fully understand how this works, but it's done using __get__(x)

Given that we can't overwrite call, and that it isn't standard to add/update the methods of an instance, it feels like the if statement, or the try except would be the better solution

Fixes #460

@CharlesBradshaw CharlesBradshaw requested a review from kmax12 Mar 12, 2019
@CharlesBradshaw CharlesBradshaw self-assigned this Mar 12, 2019
@codecov

This comment has been minimized.

Copy link

codecov bot commented Mar 12, 2019

Codecov Report

Merging #461 into master will increase coverage by 0.02%.
The diff coverage is 100%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master     #461      +/-   ##
==========================================
+ Coverage   96.46%   96.48%   +0.02%     
==========================================
  Files          98       99       +1     
  Lines        8623     8675      +52     
==========================================
+ Hits         8318     8370      +52     
  Misses        305      305
Impacted Files Coverage Δ
...tools/tests/primitive_tests/test_primitive_base.py 100% <100%> (ø)
featuretools/primitives/base/primitive_base.py 100% <100%> (ø) ⬆️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 6e7b919...de8b4d7. Read the comment docs.

@CharlesBradshaw CharlesBradshaw merged commit a86b6d8 into master Mar 13, 2019
4 checks passed
4 checks passed
codecov/patch 100% of diff hit (target 96.46%)
Details
codecov/project 96.48% (+0.02%) compared to 6e7b919
Details
license/cla Contributor License Agreement is signed.
Details
test_all_python_versions Workflow: test_all_python_versions
Details
@CharlesBradshaw CharlesBradshaw deleted the primitive_call branch Mar 13, 2019
@rwedge rwedge mentioned this pull request Mar 29, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
2 participants
You can’t perform that action at this time.