您不一定需要在创建类时创建 getter/setter 方法。您还可以根据需要创建可调用对象:
class MyClass(object):
# get/set properties for this class: {'Name':length}
__properties = {'LoadFee':20, 'Currency':3}
def __init__(self):
self._Currency = '01 34'
self._LoadFee = 'lorem ipsum dolor sit amet consecuti'
def __getattr__(self, name):
basename = name[3:]
attrname = '_'+basename
if basename in self.__properties:
if name.startswith('Get'):
return lambda : getattr(self, attrname)[:self.__properties[basename]].strip()
elif name.startswith('Set'):
return lambda value: setattr(self, attrname, value)
raise AttributeError(name)
m = MyClass()
print m.GetCurrency()
print m.GetLoadFee()
尽管这种方法很容易理解并且不使用任何元编程巫术,但它很慢并且无法自省。
您可以通过在调用它们时“具体化”方法来加快速度,即,instancemethod
在访问类实例的属性时将一个附加到类。
# MethodType is not actually necessary because
# everything it does can be done with normal Python
# but it will make our dynamic methods look as "normal"
# and not-dynamic as possible to introspection
from types import MethodType
class MyClass(object):
# get/set properties for this class: {'Name':length}
__properties = {'LoadFee':20, 'Currency':3}
def __init__(self, **args):
props = self.__properties
emptystr = ''
for k in props:
setattr(self, '_'+k, args.get(k, emptystr))
def __getattr__(self, name):
print '__getattr__(%s)' % name
# we can cache accesses by "reifying" our getters/setters as they are accessed
cls = self.__class__
basename = name[3:]
attrname = '_'+basename
# nested lambdas are just for delayed evaluation
# they cache property size lookup--assumes __properties is class-constant!
def getsize():
return cls.__properties[basename]
methodfactories = {
'Get': lambda size: lambda self: getattr(self, attrname)[:size].strip(),
'Set': lambda size: lambda self, value: setattr(self, attrname, value),
}
try:
print ' creating', name
callable = methodfactories[name[:3]](getsize())
except (KeyError, AttributeError) as e:
raise AttributeError("'{}' object has no attribute '{}'".format(cls.__name__, name))
callable.__name__ = name #cosmetics
unboundmethod = MethodType(callable, None, cls)
setattr(cls, name, unboundmethod) # add unbound method to the class
# magically get bound method on the instance!
# this works because MethodType creates a descriptor that
# returns a bound callable in an instance context
# and an unbound one in a class context
return getattr(self, name) # not an infinite loop!
如果您随后运行以下代码:
m = MyClass(Currency='01', LoadFee='lorem ipsum dolor sit')
n = MyClass(Currency='02', LoadFee='amet consecuti')
try:
# AttributeError because it hasn't been used by an instance
MyClass.GetCurrency
except AttributeError, e:
print ' 7:', e
print ' 8:', m.GetCurrency()
print ' 9:', MyClass.GetCurrency
print '10:', m.GetCurrency
print '11:', n.GetCurrency
print '12:', m.GetCurrency is n.GetCurrency
print '13:', n.GetCurrency()
print '14:', m.GetLoadFee()
print '15:', m.__dict__ # no per-instance callable!
您将得到以下结果:
7: type object 'MyClass' has no attribute 'GetCurrency'
8: __getattr__(GetCurrency)
creating GetCurrency
01
9: <unbound method MyClass.GetCurrency>
10: <bound method MyClass.GetCurrency of <__main__.MyClass object at 0x106f87b90>>
11: <bound method MyClass.GetCurrency of <__main__.MyClass object at 0x106f87f10>>
12: False
13: 02
14: __getattr__(GetLoadFee)
creating GetLoadFee
lorem ipsum dolor si
15: {'_Currency': '01', '_LoadFee': 'lorem ipsum dolor sit'}
请注意,只有在任何实例第一次访问特殊属性时才会调用getattr 。之后,从我们动态创建并附加到实例类的绑定方法返回。在第一次访问属性之后,类和实例将与我们以“正常”方式创建的方法几乎没有区别,并且将具有完全相同的运行时速度。instancemethod