I want to create a class property with a decorator that accepts an optional argument. Normally I would write
def MyProperty(func, optional=None):
def getter():
"""magic goes here"""
return func() if not optional else optional(func())
return property(getter)
class MyClass(object):
#MyProperty
def myFunction(foo):
return foo
MyClass().myFunction(5.)
>>> 5.0
This is all fine, but when I now also pass a function along the decorator like this:
class MyClass(object):
#MyProperty(int)
def myFunction(foo):
return foo
and I now call
MyClass().myFunction(5)
>>> TypeError: 'property' object is not callable
while I expect to get int(5) as result.
When you write
#MyProperty(int)
def myFunction(foo)
...
what that means is that MyProperty(int) is called, and whatever that returns is then called with myFunction as an argument. So MyProperty should be a function that returns a function that accepts a function and returns a function.
So you could write your decorator something like this:
def MyProperty(optional=None):
def decorator(func):
def getter(*args, **kwargs):
"""unspecified magic goes here"""
return func(*args, **kwargs) if not optional else optional(func(*args, **kwargs))
return getter
return decorator
So MyProperty(int) returns a function (decorator), and decorator returns whatever you are decorating.
However, when you call it without an argument, you'd still need to call it #MyProperty() instead of #MyProperty, otherwise you miss a stage of unwrapping.
>>> class MyClass:
... #MyProperty()
... def f1(foo):
... return foo
... #MyProperty(int)
... def f2(foo):
... return foo
...
>>> MyClass.f1(1.5)
1.5
>>> MyClass.f2(1.5)
1
I'm not sure about your use of property. Both your functions in the example are just functions inside a class. They don't have a self argument or a cls argument, and you're calling them from the class itself, not from an instance. It's somewhat unclear what you were aiming for.
When I tried this in Python 2 I had to declare the functions as static methods for this to work.
>>> class MyClass(object):
... #staticmethod
... #MyProperty()
... def f1(foo):
... return foo
... #staticmethod
... #MyProperty(int)
... def f2(foo):
... return foo
...
>>> MyClass.f1(0.5)
0.5
>>> MyClass.f2(1.5)
1
Related
If I have an function called foo:
def foo():
return "foo function"
and if seen the fact that it returns a string without even calling the function means __repr__ is defined like you can see in this example:
>>> func
<function func at 0x000001F43B1968B8>
>>> func.__repr__()
'<function func at 0x000001F43B1968B8>'
so now 2 questions raise to my head
is a function a class type?
if so how can I define __repr__ from in the function
a little explanation for both questions:
1:
becuse a if you do this: func. and then ctrl + space in a IDE you see everything what an class also has so then I get the question is a function not a(simple) class?
2:
can I do something like this:
def foo():
def __repr__():
return "lol"
foo.__repr__ = __repr__
return "foo function"
it works in IDLE but it does not change the __repr__ output before you call it so is that possible to change __repr__ before the function has been called?
is a function a class type?
Yes
print(type(foo))
produces
<class 'function'>
is it possible to change __repr__ before the function has been called?
Yes, for example using a decorator:
from functools import wraps
def repr(msg):
def dec(fn):
#wraps(fn)
def new_fn(*args, **kwargs):
return fn(*args, **kwargs)
new_fn.__repr__ = lambda: msg
return new_fn
return dec
#repr("LOL")
def foo():
return "foo function"
print(foo)
print(foo.__repr__())
print(foo())
produces
<function foo at 0x7f556d959ef0>
LOL
foo function
answeres:
answere to question 2: no not using def
answere to question 1: yes you can see an function as a class becuse python is based around classes
option 1(using classes):
becuse this:
class foo():
def __init__(self):
self = "foo"
and this:
class _foo():
def __init__(self):
self.foo = "foo"
def __call__(self):
return self.foo
foo = _foo()
are for the user the same as :
def foo():
return "foo"
so if you really want to have something that looks like a function but with a custom version of __repr__ you just need to make something like this:
class _foo():
def __init__(self):
self.foo = "foo"
def __repr__(self):
return "func(foo)"
def __call__(self):
return self.foo
foo = _foo()
becuse now if you do foo in IDLE after pasting this in you will see this output:
>>> foo
func(foo)
>>>
using a wrapper class:
in this example i am using a class as wrapper:
class func_wrapper():
def __init__(self,func,repr_msg):
self.func = func
self.repr_msg = repr_msg
self = repr_msg
def __call__(self,*args,**kwargs):
return self.func(*args,**kwargs)
def __repr__(self):
return self.repr_msg
def repr(msg):
def dec(fn):
wrapper = func_wrapper(func = fn,repr_msg = msg)
return wrapper
return dec
#repr("LOL")
def foo():
return "foo function"
print(foo)
print(foo.__repr__())
print(foo())
and it this prints:
LOL
LOL
foo function
explaining:
(almost) everything in python is an class try using type(object) you will see with almost every "object" it says it is an class.
so what I am try to say is python is almost based around classes they are everywhere becuse if you try to find a non class from something that is not a build in. Becuse only some buildin functions are not seen as classes
recap:
so to recap my answere:
No you can't use def to have __repr__ been called before the function has been called but you can make a class that really looks like an function and there you can make an class that for the user is just like a function
I'm having some problems. How we can define a function outside of a function that can be used in a class property? Also, how we can insert the self parameter into the function signature? I would like to visualize it like this:
>>> def a(self, x): #I thought maybe class will give "self" to this property function
... print(self)
...
>>> class aa:
... def __init__(self):
... pass
... #a
... def p():
... print('in it')
...
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 4, in aa
TypeError: a() missing 1 required positional argument: 'x'
I want to define a function outside but to use inside of a class. Like a class's method as a property. How can I do this?
It's not really clear what you want your out-of-class function to do. There are a bunch of possibilities, but you may not know the terminology yet to describe it to us.
Here's the three I think are most likely:
You may want your function to be a decorator. That means you can apply it to a method with #decorator syntax to other functions, including methods in a class.
For this to work, your function needs to be written to accept a function object as its only argument. Whatever it returns is what will replace the function or method it was being called on, so usually you want to return a callable, but you could instead return a descriptor like property does. Try something like this:
def decorator(func):
def wrapper(self, *args, **kwargs):
print("in the wrapper")
result = func(self, *args, **kwargs)
print("wrapper is done")
return result
return wrapper
class Foo:
#decorator
def foo(self, x):
print("in foo(), x is", x)
f = Foo()
f.foo(1) # prints three messages
When you call the foo method, you're actually going to be calling the wrapper method that the decorator returned after it was applied to the original method (func). Because of how we wrote the wrapper, it will call func so the original method prints out its message too.
You may want to use property (a descriptor type) to call your out-of-class function. This is a less common way of using property than applying it as a decorator on a method, but it's not impossible. You could even have two different functions, one to be called when requesting the attribute, the other than will be called when setting it (but I'll demonstrate with just the getter):
def getter(obj):
print("in the getter")
return 1
class Foo2:
foo = property(getter)
f2 = Foo2()
print(f2.foo) # prints a message from the getter function first, then prints 1
Note that you can't use #decorator syntax when building a property this way. That is only legal syntax immediately before a function definition, and we're not defining any functions that way inside our class.
You may just want to copy a function defined outside of the class into it, without any decorator or property nonsense. This is the easiest one to do, it's just a simple assignment:
def func(self, x):
print("x is", x)
class Foo3:
method = func # just assign the global to a name in the class body
func = func # you can even use the same name if you don't mind confusing people
f3 = Foo3()
f3.method(1)
f3.func(2)
If you want to create a property that uses a function defined outside your class, it would be something like this:
def myfunc(self):
return self._p
class Foo:
def __init__(self, p):
self._p = p
p = property(myfunc)
f = Foo("Alpha")
f.p # gives "Alpha"
property accepts a function as its (first) argument. The function should have self as a parameter, and should return the value that you want the property to evaluate to.
i have a class and i want to all its methods in a list inside the class, i want it to work even if i have two methods with the same name, my problem is i can't access the class to put the methods there.
lets say i have the decorator
def dec(func):
class = ????
class.methods.append(func)
return func
and i have the class
class A(object):
methods = []
#dec
def a(self):
print 2
#dec
def a(self):
print 3
i want to be able to do
A.methods[0](A())
A.methods[1](A())
(A() becuase those methods need self)
or something like that
I already read a lot of problems like this and it looks like what i want is not really possible since A is not exist when the decorator is called, but maybe there is a way to access its variables since the decorator runs inside it?
The class object itself is only constructed after the body statements (all the statements inside the class <classname>(<bases,>): block have been executed. Decorators on the other hand are executed together with the function they are decorating.
You could just in the list you want methods to be added to, to your decorator:
class A(object):
methods = []
#dec(methods)
def a(self):
print 2
#dec(methods)
def a(self):
print 3
and have the decorator use that list to append your methods:
def dec(methodslist):
def decorator(f):
methodslist.append(f)
return f
return decorator
If you are using Python 3, then another option is for you to use a metaclass with a custom metaclass.__prepare__ class method that uses collections.defaultdict() to collect all attributes into lists first so you can still access them even if named the same. Your decorator then only needs to 'mark' each function object with an extra attribute or something. This is a little more involved.
When you then want to call those functions, you are right that they are not bound and won't have self passed in for you. Either manually pass in self, or bind the manually. Functions are descriptor objects, call their __get__ method to bind them to an instance:
for func in self.methods:
method = func.__get__(self)
method()
Demo:
>>> def dec(methodslist):
... def decorator(f):
... methodslist.append(f)
... return f
... return decorator
...
>>> class A(object):
... methods = []
... #dec(methods)
... def a(self):
... print 2
... #dec(methods)
... def a(self):
... print 3
... def call_all(self):
... for func in self.methods:
... method = func.__get__(self)
... method()
...
>>> A().call_all()
2
3
I would like to create a class which returns an int when initiated, like so:
r = Foo(10)
print r # 1000
I know you can do this by overriding the __new__ method. However I need it to also execute other class functions within the __new__ method, how do I do this?
So far I have:
class Foo(object):
def __new__(cls, i):
cls.i = i
return cls.foo_fun()
def foo_fun(self):
return self.i * 100
print Foo(5)
and the error I get:
Traceback (most recent call last):
return cls.foo_fun()
TypeError: unbound method foo_fun() must be called with Foo instance as first argument (got nothing instead)
You don't have an instance in your __new__ factory method (which is static, really). You don't have a self to call things on. Use another static or class method:
class Foo(object):
def __new__(cls, i):
return cls.foo_fun(i)
#staticmethod
def foo_fun(i):
return i * 100
print Foo(5)
Setting cls.i is not thread-safe as that state is shared between all __new__ calls; you are much better off passing along the value as a parameter to another method.
However, you are abusing classes here; you never create an instance of this class, there is no way to use the class in isinstance() type checks, etc. Just use a factory function:
def foo(i):
return i * 100
If you really meant for this to be a subclass of int, you'll still need to create an actual instance of your class to return:
class Foo(int):
def __new__(cls, i):
i = int(i) # ensure you have an actual integer first
value = cls.foo_fun(i)
return super(Foo, cls).__new__(cls, value)
#staticmethod
def foo_fun(i):
return i * 100
The above inherits from int, handles the case where the argument is not an integer (like"42"`, a string convertible to an integer) and returns an instance of your class.
Demo:
>>> class Foo(int):
... def __new__(cls, i):
... i = int(i) # ensure you have an actual integer first
... value = cls.foo_fun(i)
... return super(Foo, cls).__new__(cls, value)
... #staticmethod
... def foo_fun(i):
... return i * 100
...
>>> f = Foo(42)
>>> f
4200
>>> isinstance(f, Foo)
True
>>> Foo("42") # non-integer input works too
4200
TL;DR How do I find out whether a function was defined using #classmethod or something with the same effect?
My problem
For implementing a class decorator I would like to check if a method takes the class as its first argument, for example as achieved via
#classmethod
def function(cls, ...):
I found a solution to check for #staticmethod via the types module (isinstance(foo, types.UnboundMethodType) is False if the foo is static, see here), but did not find anything on how to do so for #classmethod
Context
What I am trying to do is something along the lines of
def class_decorator(cls):
for member in cls.__dict__:
if (isclassmethod(getattr(cls, member))):
# do something with the method
setattr(cls, member, modified_method)
return cls
and I do not know how to implement what I called isclassmethod in this example
If the object is a method object, and so has a method.__self__ attribute, and that attribute is the class you got the attribute from, then it'll take the class as the first argument. It has been bound to the class.
Note that you already have a bound object at this point, so you don't need to pass in the class again, unless you first extract the original function from method.__func__.
Here is an illustration, the class Foo has a class method bar and a regular method baz, which is not bound when you access it directly on the class:
>>> class Foo:
... #classmethod
... def bar(cls):
... pass
... def baz(self):
... pass
...
>>> Foo.baz
<function Foo.baz at 0x1097d1e18>
>>> Foo.bar
<bound method Foo.bar of <class '__main__.Foo'>>
>>> Foo.bar.__self__
<class '__main__.Foo'>
>>> Foo.bar.__self__ is Foo
True
Calling Foo.bar() automatically passes in Foo.bar.__self__ as the first argument.
If you need to test such methods, use inspect.ismethod(), and if that returns True test the __self__ attribute:
import inspect
if inspect.ismethod(cls.method) and cls.method.__self__ is cls:
# method bound to the class, e.g. a classmethod
This should work for any custom descriptors that work like classmethod does, as well.
If you need to know with certainty that the method was produced by a classmethod object, you'll need to look up the attributes directly in the class namespace (cls.__dict__ or vars(cls)), and do so in each class in the class hierarchy in method resolution order:
def isclassmethod(method):
bound_to = getattr(method, '__self__', None)
if not isinstance(bound_to, type):
# must be bound to a class
return False
name = method.__name__
for cls in bound_to.__mro__:
descriptor = vars(cls).get(name)
if descriptor is not None:
return isinstance(descriptor, classmethod)
return False
and a full test of the above two approaches using a base class and a derived class, with a custom descriptor that binds a function the same way a classmethod would, but is not, itself, a classmethod:
>>> class notclassmethod:
... def __init__(self, f):
... self.f = f
... def __get__(self, _, typ=None):
... return self.f.__get__(typ, typ)
...
>>> class Base:
... #classmethod
... def base_cm(cls): pass
... #notclassmethod
... def base_ncm(cls): pass
... def base_m(self): pass
...
>>> class Derived(Base):
... #classmethod
... def derived_cm(cls): pass
... #notclassmethod
... def derived_ncm(cls): pass
... def derived_m(self): pass
...
>>> inspect.ismethod(Derived.base_cm) and Derived.base_cm.__self__ is Derived
True
>>> inspect.ismethod(Derived.base_ncm) and Derived.base_ncm.__self__ is Derived
True
>>> inspect.ismethod(Derived.base_m) and Derived.base_m.__self__ is Derived
False
>>> inspect.ismethod(Derived.derived_cm) and Derived.derived_cm.__self__ is Derived
True
>>> inspect.ismethod(Derived.derived_ncm) and Derived.derived_ncm.__self__ is Derived
True
>>> inspect.ismethod(Derived.derived_m) and Derived.derived_m.__self__ is Derived
False
>>> isclassmethod(Derived.base_cm)
True
>>> isclassmethod(Derived.base_ncm)
False
>>> isclassmethod(Derived.base_m)
False
>>> isclassmethod(Derived.derived_cm)
True
>>> isclassmethod(Derived.derived_ncm)
False
>>> isclassmethod(Derived.derived_m)
False
The isclassmethod() function correctly distinguishes between the classmethod and notclassmethod descriptors.
Historical note: this answer included references to Python 2, but with Python 2 having reached EOL were removed as no longer relevant.
You should use inspect.ismethod. It works because classmethod binds the function to the class object. See the following code:
>>> class Foo:
... #classmethod
... def bar():
... pass
... def baz():
... pass
...
>>> Foo.bar
<bound method type.bar of <class '__main__.Foo'>>
>>> Foo.baz
<function Foo.baz at 0x0000000002CCC1E0>
>>> type(Foo.bar)
<class 'method'>
>>> type(Foo.baz)
<class 'function'>
>>> import inspect
>>> inspect.ismethod(Foo.bar)
True
>>> inspect.ismethod(Foo.baz)
False
class Foo(object):
#classmethod
def baaz(cls):
print "baaz"
isinstance(Foo.__dict__["baaz"], classmethod)
None of the answers address the problem of identifying whether a method is decorated with class method from an instance of the class. Following code explores the class dict of an instance to distinguish between classmethod from other methods.
class MyClass(object):
#classmethod
def class_method(cls):
pass
def instance_method(self):
pass
#staticmethod
def static_method():
pass
def blas(): pass
t = MyClass()
isinstance(t.__class__.__dict__[t.class_method.__name__], classmethod) # True
isinstance(t.__class__.__dict__[t.static_method.__name__], classmethod) # False
isinstance(t.__class__.__dict__[t.instance_method.__name__], classmethod) # False
isinstance(t.__class__.__dict__[t.blas.__name__], classmethod) # False
This will work for both Python 2 and 3.
This works for me:
def is_classmethod(method):
"""
Is method a classmethod?
"""
return isinstance(getattr(method, '__self__', None), type)
It basically tests if method.__self__ exists and is a class, as in Martijn's answer, but does not require access to the class itself.