Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python equivalent of C++ member pointer

What would be the equivalent of a C++ member pointer in Python? Basically, I would like to be able to replicate similar behavior in Python:

// Pointer to a member of MyClass
int (MyClass::*ptMember)(int) = &MyClass::member; 

// Call member on some instance, e.g. inside a function to 
// which the member pointer was passed 
instance.*ptMember(3)

Follow up question, what if the member is a property instead of a method? Is it possible to store/pass a "pointer" to a property without specifying the instance?

One way would obviously be to pass a string and use eval. But is there a cleaner way?

EDIT: There are now several really good answers, each having something useful to offer depending on the context. I ended up using what is described in my answer, but I think that other answers will be very helpful for whoever comes here based on the topic of the question. So, I am not accepting any single one for now.

like image 953
Andrzej Pronobis Avatar asked Jun 20 '15 02:06

Andrzej Pronobis


People also ask

Does Python have pointers like C?

No, we don't have any kind of Pointer in Python language. The objects are passed to function by reference. The mechanism used in Python is exactly like passing pointers by the value in C. We have Python variables which is not a pointer.

What can I use instead of pointers in Python?

Using Mutable Types as Pointers list is not the only mutable type. Another common approach to mimicking pointers in Python is to use a dict . In this example, the counters dictionary is used to keep track of the number of function calls.

Do pointers exist in Python?

Let's see the following example of the pointer in C programming language. Besides being useful, pointers are not used in Python. In this topic, we will discuss Python's object model and learn why pointers in Python doesn't exist.

Why are there no pointers in Python?

It's important to understand variables in Python are effectively pointers in practical use. The equal “=” assignment operator automatically creates an effective pointer - unless it is a basic type (called an immutable): int, float, str, bool are basic types, and these are not pointers of any description.


2 Answers

Assuming a Python class:

class MyClass:
    def __init__(self):
        self.x = 42

    def fn(self):
        return self.x

The equivalent of a C++ pointer-to-memberfunction is then this:

fn = MyClass.fn

You can take a method from a class (MyClass.fn above) and it becomes a plain function! The only difference between function and method is that the first parameter is customarily called self! So you can call this using an instance like in C++:

o = MyClass()
print(fn(o)) # prints 42

However, an often more interesting thing is the fact that you can also take the "address" of a bound member function, which doesn't work in C++:

o = MyClass()
bfn = o.fn
print(bfn()) # prints 42, too

Concerning the follow-up with the properties, there are plenty answers here already that address this issue, provided it still is one.

like image 78
Ulrich Eckhardt Avatar answered Sep 24 '22 14:09

Ulrich Eckhardt


The closest fit would probably be operator.attrgetter:

from operator import attrgetter
foo_member = attrgetter('foo')
bar_member = attrgetter('bar')
baz_member = attrgetter('baz')

class Example(object):
    def __init__(self):
        self.foo = 1

    @property
    def bar(self):
        return 2

    def baz(self):
        return 3

example_object = Example()
print foo_member(example_object) # prints 1
print bar_member(example_object) # prints 2
print baz_member(example_object)() # prints 3

attrgetter goes through the exact same mechanism normal dotted access goes through, so it works for anything at all you'd access with a dot. Instance fields, methods, module members, dynamically computed attributes, whatever. It doesn't matter what the type of the object is, either; for example, attrgetter('count') can retrieve the count attribute of a list, tuple, string, or anything else with a count attribute.


For certain types of attribute, there may be more specific member-pointer-like things. For example, for instance methods, you can retrieve the unbound method:

unbound_baz_method = Example.baz
print unbound_baz_method(example_object) # prints 3

This is either the specific function that implements the method, or a very thin wrapper around the function, depending on your Python version. It's type-specific; list.count won't work for tuples, and tuple.count won't work for lists.

For properties, you can retrieve the property object's fget, fset, and fdel, which are the functions that implement getting, retrieving, and deleting the attribute the property manages:

example_bar_member = Example.bar.fget
print example_bar_member(example_object) # prints 2

We didn't implement a setter or deleter for this property, so the fset and fdel are None. These are also type-specific; for example, if example_bar_member handled lists correctly, example_bar_member([]) would raise an AttributeError rather than returning 2, since lists don't have a bar attribute.

like image 43
user2357112 supports Monica Avatar answered Sep 20 '22 14:09

user2357112 supports Monica