例如,我正在创建一个定义pygame矩形的类。
pdb.set_trace()
代码中是否有任何方法可以获取调用类以调用self.pos的变量的名称。这样我就可以删除.pos
class rect():
def __init__(self,x,y,w,h):
self.pos = pygame.Rect(x,y,w,h)
r = rect(10,10,10,10)
r.pos.move(10,10)
答案 0 :(得分:3)
这是基本组成/授权。此处的规范方法是将委托人设为私有(在Python中:用单个下划线加前缀它的名称-这只是一个约定,但它是非常强大的约定),并编写公共方法来委托操作,即:
# naming convention: class names should be CamelCase
class Rect():
def __init__(self, x, y, w, h):
# naming convention: the single leading underscore
# denotes an implementation attribute or method
self._pos = pygame.Rect(x, y, w, h)
# explicit delegation
def move(self, x, y):
self._pos.move(x, y)
r = Rect(10,10,10,10)
r.move(10,10)
现在,如果您有数十种委托方法,Python还提供了自动委托的钩子:the __getattr__(self, name)
magic method:
class Rect():
def __init__(self, x, y, w, h):
self._pos = pygame.Rect(x, y, w, h)
# implicit delegation:
def __getattr__(self, name):
try:
return getattr(self._pos, name)
except AttributeError:
# here we hide the fact we're delegating to another object
raise AttributeError(
"'{}'.object has no attribute '{}'".format(
type(self).__name__, name
))
r = Rect(10,10,10,10)
r.move(10,10)
这种自动委托的缺点是:1 /它可以提供对某些您不想公开的委托人属性的访问; 2 /委托检查既不显式可见也不可以通过检查发现; 3 /您得到一些额外的开销。
第一个问题可以通过保留要允许访问的代理人属性白名单来解决。遗憾的是,第二点没有简单的解决方案,第三点根本没有解决方案,因此最好还是进行显式委派(至少对于重要部分),而对通用代理类等保持自动委派。>
注意:如果这是代码中的重复模式,您仍然可以使用自定义描述符或自定义元类或类装饰器来设置一些“半自动”委派系统,即(自定义描述符示例): / p>
class delegate_to():
def __init__(self, delegatee, attr=None):
self._delegatee = delegatee
self._attr = attr
self._name = None
self._owner = None
def __set_name__(self, owner, name):
self._owner = owner
self._name = name
if self._attr is None:
self._attr = name
def _raise(self):
msg = "'{}' object has no attribute '{}'".format(
self._owner.__name__,
self._attr
)
raise AttributeError(msg)
def __get__(self, obj=None, cls=None):
if obj is None:
return self
delegatee = getattr(obj, self._delegatee)
try:
return getattr(delegatee, self._attr)
except AttributeError:
self._raise(obj, cls)
def __set__(self, value):
raise AttributeError("Attribute is read-only")
def __repr__(self):
return "<Delegatee {} ({}) object for {}>".format(
self._name, self._attr, self._owner.__name__
)
# exemple use :
class Delegatee():
def __init__(self, x, y):
self.x = x
self.y = y
def move_to(self, x, y):
self.x = x
self.y = y
def move_by(self, x, y):
self.x += x
self.y += y
@property
def position(self):
return self.x, self.y
class Composite():
def __init__(self, x, y):
self._delegatee = Delegatee(x, y)
move_to = delegate_to("_delegatee")
move_by = delegate_to("_delegatee")
position = delegate_to("_delegatee")
您还可以使用将创建delegate_to
描述符的类装饰器进一步自动化:
class delegator():
def __init__(self, delegatee, *names):
if not names:
raise ValueError("needs one or more name to delegate")
self.delegatee = delegatee
self.names = names
def create_delegator(self, owner, name, attrname=None):
if not attrname:
attrname = name
delegator = delegate_to(self.delegatee, attrname)
delegator.__set_name__(owner, name)
return delegator
def __call__(self, cls):
for name in self.names:
if isinstance(name, tuple):
name, attr = name
else:
attr = name
delegator = self.create_delegator(name, attr)
setattr(cls, name, delegator)
return cls
@delegator("_delegatee", "move_to", "move_by", ("pos", "position"))
class Composite2():
def __init__(self, x, y):
self._delegatee = Delegatee(x, y)
现在,对于基本上很简单的内容来说,有很多代码和间接级别,因此只有在您确实有很多 lot 可以建立的代表团时才有意义-从经验上看,最简单的代码,它越容易阅读,理解,测试和调试(python zen:“简单胜于复杂”),从长远来看,“智能”解决方案通常会成为PITA(在这里,做到了,现在我知道了)更好)。