回答
我希望在創建一個類Python,我可以添加和刪除屬性和方法。
import types
class SpecialClass(object):
@classmethod
def removeVariable(cls, name):
return delattr(cls, name)
@classmethod
def addMethod(cls, func):
return setattr(cls, func.__name__, types.MethodType(func, cls))
def hello(self, n):
print n
instance = SpecialClass()
SpecialClass.addMethod(hello)
>>> SpecialClass.hello(5)
5
>>> instance.hello(6)
6
>>> SpecialClass.removeVariable("hello")
>>> instance.hello(7)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'SpecialClass' object has no attribute 'hello'
>>> SpecialClass.hello(8)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: type object 'SpecialClass' has no attribute 'hello'
此示例顯示將方法添加到類和實例之間的差異。
>>> class Dog():
... def __init__(self, name):
... self.name = name
...
>>> skip = Dog('Skip')
>>> spot = Dog('Spot')
>>> def talk(self):
... print 'Hi, my name is ' + self.name
...
>>> Dog.talk = talk # add method to class
>>> skip.talk()
Hi, my name is Skip
>>> spot.talk()
Hi, my name is Spot
>>> del Dog.talk # remove method from class
>>> skip.talk() # won't work anymore
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: Dog instance has no attribute 'talk'
>>> import types
>>> f = types.MethodType(talk, skip, Dog)
>>> skip.talk = f # add method to specific instance
>>> skip.talk()
Hi, my name is Skip
>>> spot.talk() # won't work, since we only modified skip
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: Dog instance has no attribute 'talk'
請注意,您只能對* classes *,而不是* instances *執行此操作。如果你做puppy.talk =說話,說話不會是一種「約束方法」,也就是說,它不會得到隱含的「自我」論證。 – 2009-06-07 22:48:04
爲了增強Paul的評論:如果您想要對實例方法進行monkeypatch:「import types; f = types.MethodType(talk,puppy,Dog); puppy.talk = f」 – 2009-06-07 23:09:52
A到使用types.MethodType
可能有趣的選擇:
>>> f = types.MethodType(talk, puppy, Dog)
>>> puppy.talk = f # add method to specific instance
將利用一個事實,即功能descriptors:
>>> puppy.talk = talk.__get__(puppy, Dog)
我想在Python中創建一個類,我可以添加和刪除屬性和方法。我怎樣才能做到這一點?
您可以添加和刪除屬性和方法,任何類,他們會提供給所有類的實例:
>>> def method1(self):
pass
>>> def method1(self):
print "method1"
>>> def method2(self):
print "method2"
>>> class C():
pass
>>> c = C()
>>> c.method()
Traceback (most recent call last):
File "<pyshell#62>", line 1, in <module>
c.method()
AttributeError: C instance has no attribute 'method'
>>> C.method = method1
>>> c.method()
method1
>>> C.method = method2
>>> c.method()
method2
>>> del C.method
>>> c.method()
Traceback (most recent call last):
File "<pyshell#68>", line 1, in <module>
c.method()
AttributeError: C instance has no attribute 'method'
>>> C.attribute = "foo"
>>> c.attribute
'foo'
>>> c.attribute = "bar"
>>> c.attribute
'bar'
另一種選擇,如果你需要更換類是批發修改類屬性:
>>> class A(object):
... def foo(self):
... print 'A'
...
>>> class B(object):
... def foo(self):
... print 'Bar'
...
>>> a = A()
>>> a.foo()
A
>>> a.__class__ = B
>>> a.foo()
Bar
簡單:
f1 = lambda:0 #method for instances
f2 = lambda _:0 #method for class
class C: pass #class
c1,c2 = C(),C() #instances
print dir(c1),dir(c2)
#add to the Instances
c1.func = f1
c1.any = 1.23
print dir(c1),dir(c2)
print c1.func(),c1.any
del c1.func,c1.any
#add to the Class
C.func = f2
C.any = 1.23
print dir(c1),dir(c2)
print c1.func(),c1.any
print c2.func(),c2.any
導致:
['__doc__', '__module__'] ['__doc__', '__module__']
['__doc__', '__module__', 'any', 'func'] ['__doc__', '__module__']
0 1.23
['__doc__', '__module__', 'any', 'func'] ['__doc__', '__module__', 'any', 'func']
0 1.23
0 1.23
你可以直接分配給類(通過訪問原始的類名或通過__class__
):
class a : pass
ob=a()
ob.__class__.blah=lambda self,k: (3, self,k)
ob.blah(5)
ob2=a()
ob2.blah(7)
將打印
(3, <__main__.a instance at 0x7f18e3c345f0>, 5)
(3, <__main__.a instance at 0x7f18e3c344d0>, 7)
該類本身是否需要修改?或者僅僅是爲了替換object.method()在運行時的某個特定位置做什麼?
我問,因爲我回避了實際修改類的問題,在我的框架中使用了getattribute和我的Base繼承對象上的運行時裝飾器。
基地對象檢索到的方法getattribute包裝在一個Runtime_Decorator中,該Runtime_Decorator分析要應用的裝飾器/猴子修補程序的方法調用關鍵字參數。
這使您能夠利用語法object.method(monkey_patch =「mypatch」),object。方法(decorator =「mydecorator」),甚至是object.method(decorators = my_decorator_list)。
這適用於任何單獨的方法調用(我沒有使用魔術方法),在沒有實際修改任何類/實例屬性的情況下,可以使用任意的,甚至是外來的方法來打補丁,並且將透明地工作在從Base (只要它們不覆蓋getattribute當然)。
import trace
def monkey_patched(self, *args, **kwargs):
print self, "Tried to call a method, but it was monkey patched instead"
return "and now for something completely different"
class Base(object):
def __init__(self):
super(Base, self).__init__()
def testmethod(self):
print "%s test method" % self
def __getattribute__(self, attribute):
value = super(Base, self).__getattribute__(attribute)
if "__" not in attribute and callable(value):
value = Runtime_Decorator(value)
return value
class Runtime_Decorator(object):
def __init__(self, function):
self.function = function
def __call__(self, *args, **kwargs):
if kwargs.has_key("monkey_patch"):
module_name, patch_name = self._resolve_string(kwargs.pop("monkey_patch"))
module = self._get_module(module_name)
monkey_patch = getattr(module, patch_name)
return monkey_patch(self.function.im_self, *args, **kwargs)
if kwargs.has_key('decorator'):
decorator_type = str(kwargs['decorator'])
module_name, decorator_name = self._resolve_string(decorator_type)
decorator = self._get_decorator(decorator_name, module_name)
wrapped_function = decorator(self.function)
del kwargs['decorator']
return wrapped_function(*args, **kwargs)
elif kwargs.has_key('decorators'):
decorators = []
for item in kwargs['decorators']:
module_name, decorator_name = self._resolve_string(item)
decorator = self._get_decorator(decorator_name, module_name)
decorators.append(decorator)
wrapped_function = self.function
for item in reversed(decorators):
wrapped_function = item(wrapped_function)
del kwargs['decorators']
return wrapped_function(*args, **kwargs)
else:
return self.function(*args, **kwargs)
def _resolve_string(self, string):
try: # attempt to split the string into a module and attribute
module_name, decorator_name = string.split(".")
except ValueError: # there was no ".", it's just a single attribute
module_name = "__main__"
decorator_name = string
finally:
return module_name, decorator_name
def _get_module(self, module_name):
try: # attempt to load the module if it exists already
module = modules[module_name]
except KeyError: # import it if it doesn't
module = __import__(module_name)
finally:
return module
def _get_decorator(self, decorator_name, module_name):
module = self._get_module(module_name)
try: # attempt to procure the decorator class
decorator_wrap = getattr(module, decorator_name)
except AttributeError: # decorator not found in module
print("failed to locate decorators %s for function %s." %\
(kwargs["decorator"], self.function))
else:
return decorator_wrap # instantiate the class with self.function
class Tracer(object):
def __init__(self, function):
self.function = function
def __call__(self, *args, **kwargs):
tracer = trace.Trace(trace=1)
tracer.runfunc(self.function, *args, **kwargs)
b = Base()
b.testmethod(monkey_patch="monkey_patched")
b.testmethod(decorator="Tracer")
#b.testmethod(monkey_patch="external_module.my_patch")
這樣做的缺點的方法是的getAttribute鉤所有訪問屬性,所以的檢查和方法潛在的包裝甚至未方法+不會被利用特徵的屬性發生有問題的特定電話。而使用getattribute本質上有點複雜。
這個開銷在我的經驗/我的目的中的實際影響可以忽略不計,而且我的機器運行雙核賽揚。之前的實現我在對象init上使用內省方法,然後將Runtime_Decorator綁定到方法。做這樣的事情消除了利用getattribute並減少了前面提到的開銷......但是,它也打破了醃菜(也許不是蒔蘿),並且不那麼動態,那麼這種方法。
我實際遇到的「在野外」使用這種技術的唯一用例是定時和跟蹤裝飾器。然而,它開啓的可能性非常廣泛。
如果你有一個先前存在的類不能從另一個基類繼承(或者利用它自己的類定義或者它的基類中的技術),那麼整個事情根本就不適用於你的問題不幸。
我不認爲在運行時設置/刪除類中的不可調用屬性是非常具有挑戰性的嗎?除非你想要從修改後的類繼承的類自動反映它們自身的變化......雖然這聽起來似乎是一個完整的「不可能的蠕蟲」。
- 1. 在運行時更改視圖屬性的正確方法
- 2. 在C#4.0的運行時附加屬性和方法?
- 3. 在運行時如何在運行時更改屬性值
- 4. 在運行時更改log4j屬性
- 5. JTable屬性在運行時更改
- 6. Flex在運行時更改css屬性
- 7. 查看模型屬性在運行時改變驗證規則
- 8. 如何在屬性更改angular2-nativescript後運行方法?
- 9. 是否可以在運行時修改屬性的屬性?
- 10. 如何在運行時更改所選值屬性/屬性?
- 11. 在運行時改變方向
- 12. c#反射改變屬性的方法
- 13. Visual Basic ActiveX控件無法在運行時訪問屬性和方法
- 14. 如何在運行時將屬性添加到方法?
- 15. 在運行時按UITableView屬性分組項目的方法嗎?
- 16. 在運行時替換屬性設置器方法
- 17. C#在運行時更改類方法
- 18. 在運行期間將新方法和屬性注入類
- 19. knockoutjs在運行時改變
- 20. 在運行時改變
- 21. EF7在運行時改變
- 22. Python - 類的屬性,方法和參數
- 23. 如何在更改類變量時運行方法?
- 24. 運行時無法訪問RowSpan屬性?
- 25. 在視圖模型執行方法時改變性質
- 26. Java的構造和運行時修改對象屬性
- 27. 雙向樣資源的屬性和運行時對象屬性
- 28. 在C#中更改一個屬性爲只讀在運行時
- 29. 修改註釋在運行時的屬性值在Java
- 30. JavaFX CSS在運行時改變自定義樣式類的屬性
重複? http://stackoverflow.com/questions/972/adding-a-method-to-an-existing-object – 2009-06-07 22:46:31
你想知道如何在Python中做鴨子衝孔? http://en.wikipedia.org/wiki/Duck_punching – baudtack 2009-06-08 02:04:05
upvoted for asked not to ask why – oulenz 2017-11-05 21:21:48