Python相当于C ++成员指针

时间:2015-06-20 02:25:14

标签: python pointers member

Python中C ++成员指针的等价物是什么?基本上,我希望能够在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)

跟进问题,如果该成员是属性而不是方法怎么办?是否可以在不指定实例的情况下将“指针”存储/传递给属性?

显然,一种方法是传递字符串并使用eval。但是有更干净的方式吗?

编辑:现在有几个非常好的答案,每个答案根据具体情况提供一些有用的东西。我最终使用了我的答案中描述的内容,但我认为其他答案对于根据问题主题来到这里的人来说非常有帮助。所以,我现在不接受任何一个。

5 个答案:

答案 0 :(得分:6)

假设有一个Python类:

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

    def fn(self):
        return self.x

C ++指向成员函数的等价物是这样的:

fn = MyClass.fn

您可以使用C ++中的实例来调用它:

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

然而,一个更有趣的事情是你也可以采取"地址"绑定成员函数,它在C ++中不起作用:

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

关于这些属性的后续行动,这里有很多解决这个问题的答案,前提是它仍然是一个。

答案 1 :(得分:5)

最贴合的可能是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通过正常的点线访问完全相同的机制,所以它适用于你用点访问的任何东西。实例字段,方法,模块成员,动态计算属性等等。无论物体的类型是什么都无关紧要;例如,attrgetter('count')可以检索列表,元组,字符串或具有count属性的任何其他内容的count属性。

对于某些类型的属性,可能会有更多特定的成员指针式事物。例如,对于示例方法,您可以检索未绑定的方法:

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

这是实现该方法的特定函数,或者是函数的非常薄的包装器,具体取决于您的Python版本。它是特定类型的; list.count不适用于元组,tuple.count不适用于列表。

对于属性,您可以检索属性对象的fgetfsetfdel,它们是实现获取,检索和删除属性管理的属性的函数: / p>

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

我们没有为此属性实现setter或deleter,因此fsetfdelNone。这些也是特定类型的;例如,如果example_bar_member处理列表正确,example_bar_member([])会引发AttributeError而不是返回2,因为列表没有bar属性。< / p>

答案 2 :(得分:2)

我对字符串方法不满意并做了一些测试。这似乎工作得很好,避免传递字符串:

import types

# Our test class
class Class:

    def __init__(self, val):
        self._val = val

    def method(self):
        return self._val

    @property
    def prop(self):
        return self._val

# Get the member pointer equivalents
m = Class.method
p = Class.prop

# Create an instance
c1 = Class(1)

# Bind the method and property getter to the instance
m1 = types.MethodType(m, c1)
p1 = types.MethodType(p.fget, c1)

# Use
m1()  # Returns 1
p1()  # Returns 1

# Alternatively, the instance can be passed to the function as self
m(c1)  # Returns 1
p.fget(c1)  # Returns 1

答案 3 :(得分:1)

我不是C ++程序员,所以也许我在这里缺少方法指针的一些细节,但听起来你只想要引用一个在类中定义的函数。 (这些在Python 2中类型为instancemethod,但在Python 3中只是类型function。)

语法略有不同 - 不是像object.reference(args)那样调用它,而是将其称为函数:reference(object, args)object将成为self参数的参数---几乎是编译器为你做的。

尽管有更多类似C的语法,但我认为它仍然可以满足您的需求......至少在应用于您的示例中的可调用成员时。但是不会帮助一个不可调用的实例字段:它们在__init__运行之后才会存在。

以下是演示:

#!/usr/bin/env python3


import math


class Vector(object):

    def __init__(self, x, y):
        self.x = x
        self.y = y
        return

    def __str__(self):
        return '(' + str(self.x) + ', ' + str(self.y) + ')'

    def __repr__(self):
        return self.__class__.__name__ + str(self)

    def magnitude(self):
        return math.sqrt(self.x ** 2 + self.y ** 2)


def print_dict_getter_demo():
    print('Demo of member references on a Python dict:')
    dict_getter = dict.get
    d = {'a': 1, 'b': 2, 'c': 3, 'z': 26}
    print('Dictionary d      :  ' + str(d))
    print("d.get('a')        :  " + str(d.get('a')))
    print("Ref to get 'a'    :  " + str(dict_getter(d, 'a')))
    print("Ref to get 'BOGUS':  " + str(dict_getter(d, 'BOGUS')))
    print('Ref to get default:  ' + str(dict_getter(d, 'BOGUS', 'not None')))
    return


def print_vector_magnitude_demo():
    print('Demo of member references on a user-defined Vector:')
    vector_magnitude = Vector.magnitude
    v = Vector(3, 4)
    print('Vector v        :  ' + str(v))
    print('v.magnitude()   :  ' + str(v.magnitude()))
    print('Ref to magnitude:  ' + str(vector_magnitude(v)))
    return

def print_vector_sorting_demo():
    print('Demo of sorting Vectors using a member reference:')
    vector_magnitude = Vector.magnitude
    v0 = Vector(0, 0)
    v1 = Vector(1, 1)
    v5 = Vector(-3, -4)
    v20 = Vector(-12, 16)
    vector_list = [v20, v0, v5, v1]
    print('Unsorted:  ' + str(vector_list))
    sorted_vector_list = sorted(vector_list, key=vector_magnitude)
    print('Sorted:    ' + str(sorted_vector_list))
    return


def main():
    print_dict_getter_demo()
    print()
    print_vector_magnitude_demo()
    print()
    print_vector_sorting_demo()
    return


if '__main__' == __name__:
    main()

使用Python 3运行时,会产生:

Demo of member references on a Python dict:
Dictionary d      :  {'a': 1, 'c': 3, 'b': 2, 'z': 26}
d.get('a')        :  1
Ref to get 'a'    :  1
Ref to get 'BOGUS':  None
Ref to get default:  not None

Demo of member references on a user-defined Vector:
Vector v        :  (3, 4)
v.magnitude()   :  5.0
Ref to magnitude:  5.0

Demo of sorting Vectors using a member reference:
Unsorted:  [Vector(-12, 16), Vector(0, 0), Vector(-3, -4), Vector(1, 1)]
Sorted:    [Vector(0, 0), Vector(1, 1), Vector(-3, -4), Vector(-12, 16)]

如您所见,它适用于内置类和用户定义的类。

修改

上面的巨大演示基于一个假设:你有一个对类的引用,并且你的目标是“坚持”一个类的方法,用于该类的任何实例出现的某个时候后面。

如果您已经有对实例的引用,那就更简单了:

d = {'a': 1, 'b': 2, 'c': 3, 'z': 26}
d_getter = d.get
d_getter('z')  # returns 26

这与上面基本相同,只是在从function转换为method已将“锁定”到self的参数后,所以您不需要提供它。

答案 4 :(得分:0)

我在python中使用的方法是使用public class UserEvent { public DateTime EnrolTime { get; set; } public string UserId { get; set; } [ForeignKey("UserId")] public virtual AspNetUser User { get; set; } public int EventId { get; set; } [ForeignKey("EventId")] public virtual Event Event { get; set; } } 。如果你有一个属性的名称,它可以是c ++指向成员的模拟,你可以调用__getattribute__来获取名称存储在x中的属性。它的字符串和字符串而不是偏移和&amp;指针,但那是蟒蛇。