Created
May 9, 2019 14:22
-
-
Save jpsutton/3d7a3eabf353d38811b960e3ed517aa1 to your computer and use it in GitHub Desktop.
Decorate a method to provide it similar "private" semantics as other languages (e.g., C++)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from functools import wraps | |
import inspect | |
# This defines a decorator that can be used on an instance method, to stop it from being inherited by child classes | |
class _private_method(object): | |
def __init__(self, decorated): | |
self._decorated = decorated | |
def __set_name__(self, owner, name): | |
@wraps(self._decorated) | |
def wrap_func(self, *args, **kwargs): | |
caller_frame = inspect.currentframe().f_back | |
# Indicates that the caller is not even inside an object (assumes developer is sane; uses the name 'self') | |
if 'self' not in caller_frame.f_locals: | |
raise RuntimeError("Unable to access private method '%s'" % wrap_func.__funcname__) | |
caller_func = getattr(caller_frame.f_locals['self'], caller_frame.f_code.co_name) | |
# Check to see if the calling function is a member of __orig_class__ | |
if not getattr(caller_func, "__orig_class__", None) or caller_func.__orig_class__ != wrap_func.__orig_class__: | |
raise RuntimeError("Unable to access private method '%s'" % wrap_func.__funcname__) | |
return wrap_func.__orig_func__(self, *args, **kwargs) | |
# Set some attributes on wrap_func so that wrap_func can test various things | |
wrap_func.__funcname__ = name | |
wrap_func.__orig_func__ = self._decorated | |
wrap_func.__orig_class__ = owner | |
# Mark each member function in this class with the original class name, so we can test it inside wrap_func | |
for attr_name in dir(owner): | |
attr = getattr(owner, attr_name) | |
if inspect.isfunction(attr): | |
attr.__orig_class__ = owner | |
setattr(owner, name, wrap_func) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment