4

How could I disable a python in-built function?

For example, I note that it is possible to reassign or overwrite len() (like len = None), but it is not possible to reassign list.__len__() , which raises:

TypeError: can't set attributes of built-in/extension type 'list'

However, even if reassignment were possible it seems easy to override. In this example, del len or from builtins import len would restore the original functionality of len().

The reason I ask is that on Codewars sometimes people want to set a coding challenge for a user to complete while forbidding the use of certain in-built functions. A trivial example could be determining the length of a list without using the length function.

On reflection, thanks to the comments I have already received and this related question, I now realize that a full-proof solution is very hard, but I'd still be interested in a pragmatic solution that could be useful in this context.

Thank you

Community
  • 1
  • 1
Chris_Rands
  • 38,994
  • 14
  • 83
  • 119
  • 4
    The global name `__len__` and an object's attribute named `__len__` are two completely different things. – chepner Sep 06 '16 at 18:31
  • 4
    `__len__` is an attribute of the `list` type, while your example assigns a new variable to the global namespace. The right namespace would be `list.__len__ = None`, but you can't easily do that with types implemented in C. – TigerhawkT3 Sep 06 '16 at 18:32
  • If you wanted to overwrite the object attribute `__len__` you would have to do so for every object – meetaig Sep 06 '16 at 18:32
  • 1
    @DeepSpace: Try it; you'll find that doesn't work. – user2357112 Sep 06 '16 at 18:33
  • Further, `__len__` may be a read-only attribute for built-in types (it certainly is for `list`), and if it isn't, some the lookup for special methods is done by class, not instance. – chepner Sep 06 '16 at 18:33
  • Thanks all for the comments. I note that `list.__len__ = None` raises a `TypeError` and I've edited my question to reflect this – Chris_Rands Sep 06 '16 at 18:40
  • So... what do you have against being able to get the length of a list? (Why do you want this to stop working globally, anyway?) – Two-Bit Alchemist Sep 06 '16 at 18:45
  • @Two-BitAlchemist I try to explain that in the last paragraph of my question – Chris_Rands Sep 06 '16 at 18:47
  • You could use ast to parse the source and look for the use of `len` `.__len__()` etc.. – Padraic Cunningham Sep 06 '16 at 19:00
  • Guys who downvoted my answer, please check edit please: http://stackoverflow.com/questions/39355608/disable-python-in-built-function/39355678#39355678 . Thanks. – turkus Sep 06 '16 at 19:05
  • @Chris_Rands Fair enough. So is the ideal answer for you a way to limit yourself in answering such questions, or a theoretical implementation to prevent cheating on such questions that would be exposed to end users on the web? If so, how would you feel about parsing their source code and editing it before compiling? – Two-Bit Alchemist Sep 06 '16 at 19:34
  • 1
    You could try [forbiddenfruit](https://github.com/clarete/forbiddenfruit). I'm not having much luck on it with my anaconda installation but it looks promising. – Trevor Merrifield Sep 06 '16 at 20:07
  • @Two-BitAlchemist Yes ideally a way of preventing cheating, but thanks to the comments I understand better now how non-trivial this is – Chris_Rands Sep 06 '16 at 20:37

1 Answers1

2

Preface: given the various comment conversations... It should be noted that none of these things are sufficient protection for running un-trusted code, and to be absolutely safe, you need a different interpreter with sandboxing specifically built in. Here is a previous answer discussing that

Given the example of writing a code wars question.. I would sub-class list, string, etc. with custom classes that disable the __len__ function, then override the respective constructors with your own custom class.. make sure to provide the test case inputs as instances of the new class, as you cannot override the literal string/list constructors as they are linked to the interpreter directly..

for example:

oldList = list
class myList(list):
    def __len__(self):
        raise AttributeError("'len' has been disabled for list objects")
list = myList
Community
  • 1
  • 1
Aaron
  • 10,133
  • 1
  • 24
  • 40
  • downvoted just for the fun of it or is someone going to explain why this is a bad solution to Chris' problem? – Aaron Sep 06 '16 at 19:00
  • I think they gave you downvote because of the same reason I've got before edited my question, reason was: OP asks not how to replace, but how to remove ``__len__``. – turkus Sep 06 '16 at 19:02
  • @PadraicCunningham Like I already said... you can't override literal constructors, but if this is for code wars, you simply provide the people answering the questions an instance of the custom class as an input. They can't provide literal constructors for every possible input value within the body of the function.. – Aaron Sep 06 '16 at 19:05
  • They could just overwrite the class with their own implementation, there are numerous ways to get around it – Padraic Cunningham Sep 06 '16 at 19:09
  • 1
    Also, with this approach the user can `del list` to regain access to the original. As a workaround you can assign `__builtins__.list = myList` but that still won't solve the problem @PadraicCunningham mentioned – Trevor Merrifield Sep 06 '16 at 19:10
  • @PadraicCunningham If you simalarly disable `super()` as well, it would be relatively difficult to duplicate the class, at which point it seems it would be out of scope of the target application. I agree if one were to try to use this method for sandboxing for security reasons it would not be enough, but this is a much more casual application. – Aaron Sep 06 '16 at 19:14
  • `tuple(MyList([1,2,3])).__len__()` – Padraic Cunningham Sep 06 '16 at 19:15
  • No matter what you do it is going to be very simple to get around it, subclassing does not come close to actually doing what the OP is asking. – Padraic Cunningham Sep 06 '16 at 19:27
  • 2
    @Aaron Clearly they're not going to be happy unless you write a fully functional variant of CPython implementing the requested behavior :P – Two-Bit Alchemist Sep 06 '16 at 19:27
  • @Two-BitAlchemist, the first comment on the -6 answer *This doesn't disable anything; it just overrides an inherited method. It just shifts the problem from "How do I disable len?" to "How do I force the use of CustomList in place of list* as their initial answer was basically this. – Padraic Cunningham Sep 06 '16 at 19:29
  • @Two-BitAlchemist actually [this](http://stackoverflow.com/a/3068475/3220135) post pretty much suggests doing just that xD – Aaron Sep 06 '16 at 19:31