instance variables - python

I was wondering if it is possible to create a function foo in python so that
def calulate (self, input):
input = #some stuff
def foo2(self):
self.calculate(self.var1)
self.calculate(self.var2)
or do you have to do this
def calculation(self):
output=#some stuff
return output
def foovar1(self):
self.var1=self.calculation()
self.var2=self.calculation()
I really don't want to have to do this because it would mean creating many more functions

In Python, you can mutate function arguments, but you can't rebind them in the caller's scope directly. You could pass the instance member name:
def foo(self, inputname):
setattr(self, inputname, #some stuff)
def foo2(self):
self.foo('var1')
self.foo('var2')
Alternately, if self.var1 is a mutable object e.g. a list you could write:
def foo (self, input):
input[:] = #some stuff
def foo2(self):
self.foo(self.var1)
self.foo(self.var2)
This works because you're mutating the list object (by assigning to a full slice) rather than rebinding it (a bare =).

Another solution could be to have a specially crafted container.
class Container(object):
def __init__(self, value=None):
self.value = value
and then use it in another class:
def foo(self, container):
container.value = ...
def foo2(self):
self.foo(self.var1)
self.foo(self.var2)

Related

Python #cls.decorator

I want to create a python decorator that adds a certain function to a list of functions of that class that will, sometimes, be processed. Example code:
class A:
# every subclass should define _list
#classmethod
def decorator(cls, f):
# cls = B
cls._flist.append(f)
return f
#classmethod
def processFunctions(cls):
for f in cls._flist:
...
class B(A):
_flist = []
#B.decorator # Obviously not possible because cls is not defined (yet)
def foo(self):
print("Inside foo")
Is it possible to replicate this behaviour? The class (cls) should be passed when decorating the function, so I can't use the usual approach of creating a wrapper function that "unpacks" cls and the other arguments.
Ok, I think I've worked something out.
You need an instance of A, but as a class variable inside B.
Then each method will need an instance:
class A:
def __init__(self):
self._flist = []
def decorator(self, f):
self._flist.append(f)
return f
def processFunctions(self, other):
for f in self._flist:
f(other)
class B:
a=A()
#a.decorator
def foo(self):
print("Inside foo")
def processFunctions(self):
B.a.processFunctions(self)
b = B()
b.processFunctions()
Output
Inside foo
The following way is based on the implementation behavior of locals() in CPython but there is PEP 558 to make it documented standard behavior:
class A:
# every subclass should define _list
#staticmethod
def decorator(loc):
def registrator(f):
loc['_flist'].append(f)
return f
return registrator
#classmethod
def processFunctions(cls):
for f in cls._flist:
...
class B(A):
_flist = []
#decorator(locals())
def foo(self):
print("Inside foo")
Another approach, like the one the package ABC uses is making the decorator add a flag to the function, and then go through the functions of this class that have that flag activated.
class A:
#staticmethod
def decorator(f):
def wraps(f)
f.__processable__ = True
return f
return wraps
def processFunctions(self):
for d in dir(self):
try:
f = getattr(self, d).__func__
if f.__processable__:
f() # Or whatever we want to do with the function
# Instead of try/except we could use a bunch of nested ifs
except AttributeError:
pass

How to automatically "register" methods in a python class as a list class variable?

When defining a Python class, I'd like to use decorators to register some of its methods into a class variable list. Here's an example of incorrect python that outlines what I'm looking for:
class MyClass:
dangerous_methods = []
#classmethod
def dangerous_method(cls, func):
cls.dangerous_methods.append(func)
return func
#MyClass.dangerous_method
def incinerate(self):
pass
def watch_tv(self):
pass
#MyClass.dangerous_method
def stab(self):
pass
def print_dangerous_methods(self):
print(self.dangerous_methods)
obj = MyClass()
obj.print_dangerous_methods()
with the expected output being
[<function MyClass.incinerate at 0x000001A42A629280>, <function MyClass.stab at 0x000001A42A629281>]
Is it possible to do this without torturing Python too much?
All you really want to do is to set dangerous on the methods. Remember that python functions and methods are first-class objects, you can set arbitrary attributes on them.
def print_dangerous_methods(cls):
""" yes, you could also return a list """
for name in dir(cls):
f = getattr(cls, name)
if callable(f) and getattr(f, "dangerous", False):
print(name)
def dangerous(func):
setattr(func, "dangerous", True)
return func
class MyClass:
#dangerous
def incinerate(self):
print("incinerate")
def watch_tv(self):
pass
#dangerous
def stab(self):
return "you've been stabbed"
class_born_dangerous = print_dangerous_methods
print("\non instance")
obj = MyClass()
print_dangerous_methods(obj)
print("\non class")
print_dangerous_methods(MyClass)
print("\nand yes, they work")
obj.incinerate()
print (obj.stab())
print("\nas a classmethod")
obj.class_born_dangerous()
output:
on instance
incinerate
stab
on class
incinerate
stab
and yes, they work
incinerate
you've been stabbed
as a classmethod
incinerate
stab
If you want to generalize this approach and set arbitrary attributes, you need to set up a parametrized decorator:
def annotate_func(**kwds):
"""set arbitrary attributes"""
def actual_decorator(func):
for k, v in kwds.items():
setattr(func, k, v)
return func
return actual_decorator
which you would use as follows:
#annotate_func(dangerous=1,range=1000)
def shoot(self, times):
for i in range(0, times):
print("bang!")
This is one way to implement that:
class MyClass:
def __init__(self):
self.dangerous_methods = []
def dangerous_method(func):
def inner(self):
self.dangerous_methods.append(func)
return func(self)
return inner
#dangerous_method
def incinerate(self):
print('Incinerate called!')
pass
def watch_tv(self):
print('Watch_tv called!')
pass
#dangerous_method
def stab(self):
print('Stab called!')
pass
def print_dangerous_methods(self):
print(self.dangerous_methods)
obj = MyClass()
obj.incinerate()
# Incinerate called!
obj.watch_tv()
# Watch_tv called!
obj.stab()
# Stab called!
obj.incinerate()
# Incinerate called!
obj.print_dangerous_methods()
# [<function MyClass.incinerate at 0x0000029C11666EE8>, <function MyClass.stab at 0x0000029C11666B88>, <function MyClass.incinerate at 0x0000029C11666EE8>]
Just note that in this way, functions are being added to the list ONLY once they've called and there is a risk that a function being added to the list multiple times. However, if you know that there are some functions in mind that you want to add to the list and they're constants, you can simply add them while the object is being constructed:
class MyClass:
def __init__(self):
self.dangerous_methods = [self.incinerate, self.stab]
def incinerate(self):
print('Incinerate called!')
pass
def watch_tv(self):
print('Watch_tv called!')
pass
def stab(self):
print('Stab called!')
pass
def print_dangerous_methods(self):
print(self.dangerous_methods)
obj = MyClass()
obj.print_dangerous_methods()
# [<bound method MyClass.incinerate of <__main__.MyClass object at 0x0000029C11388F08>>, <bound method MyClass.stab of <__main__.MyClass object at 0x0000029C11388F08>>]
The following snippet does exactly what you described.
Note that print_dangerous_methods is declared as a class method, because that’s what it really is (it applies to the class, not to a certain instance). That means you can call it even without creating an instance.
class MyClass:
def dangerous_method(meth):
meth.is_dangerous = True
return meth
#dangerous_method
def incinerate(self):
pass
def watch_tv(self):
pass
#dangerous_method
def stab(self):
pass
#classmethod
def print_dangerous_methods(cls):
print ([
meth for meth in [
getattr(cls, methname) for methname in dir(cls)
]
if getattr(meth, "is_dangerous", False)
])
MyClass.print_dangerous_methods()

decorating methods causes method to pass in objects [duplicate]

This question already has answers here:
Python: Bind an Unbound Method?
(5 answers)
Closed 2 years ago.
Problem Description
I want to use a decorator to define a class method, but this requires me to manually give the 'self' object when I shouldn't have to provide that.
def func_wrapper(func):
def call_func(self):
print(self.a)
func()
return call_func
def func():
print('hello')
class test:
def __init__(self, func):
self.a = 0
self.call_func = func_wrapper(func)
mytest = test(func)
#mytest.call_func() #why does this not work?
mytest.call_func(mytest) #this works
I want to be able to mytest.call_func() but this doesn't work, presumably because call_func is bound to the func_wrapper and not mytest. If I manually pass in the object, e.g. mytest.call_func(mytest) this will work, but I don't want to have to manually pass in the object - this creates inconsistent call signatures if one inherited the test class and wrote their own call_func method, because then the method would be properly bound to the class.
Solution Attempts
def func_wrapper2(func, obj):
def call_func():
print(obj.a)
func()
return call_func
class test:
def __init__(self, func):
self.a = 0
self.call_func = func_wrapper2(func, self)
Here is a solution which lets me test.call_func() as desired, but here func_wrapper is not a true decorator as it requires to be passed in the object as well.
Looking on the web I found this blog https://medium.com/#vadimpushtaev/decorator-inside-python-class-1e74d23107f6 which talks about this issue and recommends to define the decorator either in a nested class, or a helper class. However their solution doesn't seem to work and I am getting type errors from passing the wrong number of inputs.
class test2:
class test2helper:
#classmethod
def func_wrapper(func):
print(self.a)
func()
def __init__(self):
self.a = 0
#test2helper.func_wrapper
def call_func(self):
print('hello')
So what is the proper way to use decorators with class methods? Every way to do it seems to cause different issues with how the self is being handled. I am going to use the func_wrapper2 design unless there is a better way to do this.
You are missing one level:
class test2:
class test2helper:
#classmethod
def decorator(cls, func): # this must return a function!
def func_wrapper(self): # ... namely this one, the "wrapper"
print(self.a) # ... where you have access to the instance
func(self) # ... upon which the method is called
return func_wrapper
def __init__(self):
self.a = 0
#test2helper.decorator
def call_func(self):
print('hello')
>>> t = test2()
>>> t.call_func()
0
hello
Or, if you want to go with the earlier attempt without nested class:
def decorator(func): # you are decorating an unbound function!
def func_wrapper(obj):
print(obj.a)
func(obj) # which has to be passed all the arguments
return func_wrapper
class test:
def __init__(self):
self.a = 0
#decorator
def call_func(self):
print('hello')
You can define a class decorator to do what you want:
def class_decorator(cls):
def call_func(self):
print(self.a)
return func()
setattr(cls, 'call_func', call_func)
return cls
def func():
print('hello')
#class_decorator
class Test:
def __init__(self, func):
self.a = 0
mytest = Test(func)
mytest.call_func() # This now works.
Output:
0
hello

How to access class variable in decorator function

Is it possible to create a decorator function without argument that is able to access class variables. I found similar questions but they always refer to instance variables and not class variables and the variables are generally only accessed when the decorated method is called.
I want to reference the class variable at class definition not after instantiation.
Other solutions such as creating a Meta class come to mind, but I only want to use one class and a decorator without argument.
I am able to implement the required functionality without the use of decorators the following way with the desired results.
class B:
b=3
resetFuns=[]
def __init__(self,x):
self.x=x
self.y=x+self.b
def foo(self):
self.y=self.x+self.b
resetFuns.append(foo)
def reset(self):
for f in self.resetFuns:
f(self)
test=B(4)
print(test.y)
B.b=9
print(test.y)
test.reset()
print(test.y)
7
7
13
But I want to use a decorator similar to this.
class A:
b=3
resetFuns=[] ##class variable I want to access
def __init__(self,x):
self.x=x
self.y=x+self.b
def resetDecorator(func):
resetFuns.append(func) ##can't reference resetFuns like this
return func
#resetDecorator
def foo(self):
self.y=self.x+self.b
def reset(self):
for f in resetFuns:
f(self)
Something like:
def resetDecoratorCreator(resetFuns):
def resetDecorator(func):
resetFuns.append(func)
return func
return resetDecorator
class B:
b=3
resetFuns=[]
resetDecorator = resetDecoratorCreator(resetFuns)
def __init__(self,x):
self.x=x
self.y=x+self.b
#resetDecorator
def foo(self):
self.y=self.x+self.b
def reset(self):
for f in self.resetFuns:
f(self)
will get you what you're looking for.

Implementing Python persistent properties

In a class, I want to define N persistent properties. I can implement them as follow:
#property
def prop1(self):
return self.__prop1
#prop1.setter
def prop1(self, value):
self.__prop1 = value
persistenceManagement()
#property
def prop2(self):
return self.__prop2
#prop2.setter
def prop2(self, value):
self.__prop2 = value
persistenceManagement()
[...]
#property
def propN(self):
return self.__propN
#propN.setter
def propN(self, value):
self.__propN = value
persistenceManagement()
Of course, the only different thing between these blocks is the property name (prop1, prop2, ..., propN). persistenceManagement() is a function that has to be called when the value of one of these property changes.
Since these blocks of code are identical except for a single information (i.e., the property name), I suppose there must be some way to replace each of these blocks by single lines declaring the existence of a persistent property with a given name. Something like
def someMagicalPatternFunction(...):
[...]
someMagicalPatternFunction("prop1")
someMagicalPatternFunction("prop2")
[...]
someMagicalPatternFunction("propN")
...or maybe some decorating trick that I cannot see at the moment. Is someone has an idea how this could be done?
Properties are just descriptor classes and you can create your own and use them:
class MyDescriptor(object):
def __init__(self, name, func):
self.func = func
self.attr_name = '__' + name
def __get__(self, instance, owner):
return getattr(self, self.attr_name)
def __set__(self, instance, value):
setattr(self, self.attr_name, value)
self.func(self.attr_name)
def postprocess(attr_name):
print 'postprocess called after setting', attr_name
class Example(object):
prop1 = MyDescriptor('prop1', postprocess)
prop2 = MyDescriptor('prop2', postprocess)
obj = Example()
obj.prop1 = 'answer' # prints 'postprocess called after setting __prop1'
obj.prop2 = 42 # prints 'postprocess called after setting __prop2'
Optionally you can make it a little easier to use with something like this:
def my_property(name, postprocess=postprocess):
return MyDescriptor(name, postprocess)
class Example(object):
prop1 = my_property('prop1')
prop2 = my_property('prop2')
If you like the decorator # syntax, you could do it this way (which also alleviates having to type the name of the property twice) -- however the dummy functions it requires seem a little weird...
def my_property(method):
name = method.__name__
return MyDescriptor(name, postprocess)
class Example(object):
#my_property
def prop1(self): pass
#my_property
def prop2(self): pass
The property class (yes it's a class) is just one possible implementation of the descriptor protocol (which is fully documented here: http://docs.python.org/2/howto/descriptor.html). Just write your own custom descriptor and you'll be done.

Categories

Resources