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
。但是有更干净的方式吗?
编辑:现在有几个非常好的答案,每个答案根据具体情况提供一些有用的东西。我最终使用了我的答案中描述的内容,但我认为其他答案对于根据问题主题来到这里的人来说非常有帮助。所以,我现在不接受任何一个。
答案 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
不适用于列表。
对于属性,您可以检索属性对象的fget
,fset
和fdel
,它们是实现获取,检索和删除属性管理的属性的函数: / p>
example_bar_member = Example.bar.fget
print example_bar_member(example_object) # prints 2
我们没有为此属性实现setter或deleter,因此fset
和fdel
为None
。这些也是特定类型的;例如,如果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;指针,但那是蟒蛇。