Python class variable changed a function into a method, why? - python

Why does Python turn a free function into an unbound method upon assignment to a class variable?
def make_func(s):
def func(x):
return '%s-%d' % (s, x)
return func
class Foo(object):
foofunc = make_func('foo')
So this works as expected: (returns "dog-1")
make_func('dog')(1)
But this fails with:
Foo.foofunc(1)
TypeError: unbound method func() must be called with Foo instance as first argument (got int instance instead)
Upon closer inspection, Python turned the "inner" function func inside make_func into a method, but since there's no self, this method will never work. Why does Python do this?
>>> import inspect
>>> inspect.getmembers(Foo, inspect.ismethod)
[('foofunc', <unbound method Foo.func>)]

Python can't tell "how" you assigned a method to a class attribute. There is no difference between this:
class Foo(object):
def meth():
pass
and this
def func():
pass
class Foo(object):
meth = func
In both cases, the result is that a function object is assigned to a class attribute named 'meth'. Python can't tell whether you assigned it by defining the function inside the class, or by "manually" assigning it using meth = func. It can only see the "end result", which is an attribute whose value is a function. Either way, once the function is in the class, it is converted to a method via the normal process that notices functions in class definitions and makes them into methods.

class Foo(object):
foofunc = make_func('foo')
foofunc is a class variable, not a method (for which you need the 'def'). And you initialize it with the result of make_func(...), so it won't change again.
If you want to call Foo.foofunc, you need to assign foofunc = make_func without a parameter.

Related

Can you use a static method as default parameter in __init__ in python classes?

I am writing a class for a neural network and I want to give it some form of customization, so that you can choose different cost functions and regularizations. For this I want to set them as default parameters in the __init__() method.
But when I pass MyClass.static_method in my example, the Interpreter then tells me that MyClass is not (yet) defined. Why is this and is there a nicer workaround than mine?
You can of course just set the static method as a default parameter, but then other problems arise. For example, if I want to access the functions name (which I actually want), I cannot use __name__ rightaway. I know how to do it another way, by accessing static_method.__func__.__name__. But this seems clumsy and as you get a staticmethod object, seems like its not intended to be used this way.
class MyClass:
#staticmethod
def static_method():
do_something()
def __init__(self, func=MyClass.static_method, func2=static_method):
self.name = func.__name__ #Does not work
self.name2 = func2.__func__.__name__ #Should work
I did expect for the MyClass.static_method to work, but the class does not seem to exist then. So, one last time, why?
The reason you're having problems with your static method usage as a default argument is due to a combination of two issues.
The first issue is that the default argument needs to be well defined when the def statement is run, not only when the function is called. That's because the default argument gets built into the function object, rather than being recalculated each time the function runs (this is the same reason why a mutable default argument like an empty list is often an error). Anyway, this is why you can't use MyClass.static_method as the default argument, since MyClass isn't defined yet when the function is being defined (the class object is only made after all its contents have been created).
The next issue is that a staticmethod object doesn't have all the same attributes and methods as a regular function. Normally this doesn't matter, as when you access it through a class object (e.g. MyClass.static_method once MyClass exists) or through an instance (e.g. self.static_method), it will be callable and have a __name__. But that's because you get the underlying function in those situations, rather than the staticmethod object itself. The staticmethod object itself is a descriptor, but not a callable.
So neither of these functions will work correctly:
class MyClass:
#staticmethod
def static_method():
pass
def foo(self, func=MyClass.static_method): # won't work because MyClass doesn't exist yet
pass
def bar(self, func=static_method): # this declaration will work (if you comment out foo)
name = func.__name__ # but this doesn't work when the bar() is called
func() # nor this, as func is the staticmethod object
What does work would be to use the actual function underlying the staticmethod object as the default:
def baz(self, func=static_method.__func__): # this works!
name = func.__name__
func()
This also works when you pass in some other function (or bound method), unlike the version of your code that used name = func.__func__.__name__.
DEFAULT = object()
class MyClass:
#staticmethod
def static_method():
do_something()
def __init__(self, func=DEFAULT, func2=DEFAULT):
self.name = self.static_method.__name__ if func is DEFAULT else func.__name__
self.name2 = self.static_method.__func__.__name__ if func2 is DEFAULT else func2.__func__.__name__
I guess??

Do we really need #staticmethod decorator in python to declare static method

I am curious about why we need the #staticmethod decorator to declare method as static. I was reading about static methods in Python, and I came to know that static method can be callable without instantiating its class.
So I tried the two examples below, but both do the same:
class StatMethod:
def stat():
print("without Decorator")
class StatMethod_with_decorator:
#staticmethod
def stat():
print("With Decorator")
If I call the stat() method on the class directly, both print/show the values below:
>> StatMethod.stat()
without Decorator
>> StatMethod_with_decorator.stat()
With Decorator
You need the decorator if you intend to try to call the #staticmethod from the instance of the class instead of of the class directly
class Foo():
def bar(x):
return x + 5
>>> f = Foo()
>>> f.bar(4)
Traceback (most recent call last):
File "<pyshell#7>", line 1, in <module>
f.bar(4)
TypeError: bar() takes 1 positional argument but 2 were given
Now if I declare #staticmethod the self argument isn't passed implicitly as the first argument
class Foo():
#staticmethod
def bar(x):
return x + 5
>>> f = Foo()
>>> f.bar(4)
9
The documentation describes some transformations that are done when calling a user defined method:
Note that the transformation from function object to (unbound or
bound) method object happens each time the attribute is retrieved from
the class or instance. In some cases, a fruitful optimization is to
assign the attribute to a local variable and call that local variable.
Also notice that this transformation only happens for user-defined
functions; other callable objects (and all non-callable objects) are
retrieved without transformation. It is also important to note that
user-defined functions which are attributes of a class instance are
not converted to bound methods; this only happens when the function is
an attribute of the class.
For methods marked as staticmethod this is different:
Static method objects provide a way of defeating the transformation of
function objects to method objects described above. A static method
object is a wrapper around any other object, usually a user-defined
method object. When a static method object is retrieved from a class
or a class instance, the object actually returned is the wrapped
object, which is not subject to any further transformation. Static
method objects are not themselves callable, although the objects they
wrap usually are. Static method objects are created by the built-in
staticmethod() constructor.
if function has some parameters, then call non static method would be failed
and static method didn't use the local variables in the class, but the class method will be
Update: In python 3.10 you dont need the decorator any more
Just my simple approach here. Forget the decorators. Use the class directly (Python 3.8):
class MyClass:
def myMethod(self, myValue):
print(myValue)
MyClass.myMethod(None, "hi")
Or both:
MyClass.myMethod(None, "hi from class")
myInstance = myClass()
myInstance.myMethod2("hi from instance")

Difference between #classmethod and a method in python [duplicate]

This question already has answers here:
What's an example use case for a Python classmethod?
(7 answers)
Closed 9 years ago.
What is the difference between #classmethod and a 'classic' method in python,
When should I use the #classmethod and when should I use a 'classic' method in python.
Is the classmethod must be an method who is referred to the class (I mean it's only a method who handle the class) ?
And I know what is the difference between a #staticmethod and classic method
Thx
Let's assume you have a class Car which represents the Car entity within your system.
A classmethod is a method that works for the class Car not on one of any of Car's instances. The first parameter to a function decorated with #classmethod, usually called cls, is therefore the class itself. Example:
class Car(object):
colour = 'red'
#classmethod
def blue_cars(cls):
# cls is the Car class
# return all blue cars by looping over cls instances
A function acts on a particular instance of the class; the first parameter usually called self is the instance itself:
def get_colour(self):
return self.colour
To sum up:
use classmethod to implement methods that work on a whole class (and not on particular class instances):
Car.blue_cars()
use instance methods to implement methods that work on a particular instance:
my_car = Car(colour='red')
my_car.get_colour() # should return 'red'
If you define a method inside a class, it is handled in a special way: access to it wraps it in a special object which modifies the calling arguments in order to include self, a reference to the referred object:
class A(object):
def f(self):
pass
a = A()
a.f()
This call to a.f actually asks f (via the descriptor protocol) for an object to really return. This object is then called without arguments and deflects the call to the real f, adding a in front.
So what a.f() really does is calling the original f function with (a) as arguments.
In order to prevent this, we can wrap the function
with a #staticmethod decorator,
with a #classmethod decorator,
with one of other, similiar working, self-made decorators.
#staticmethod turns it into an object which, when asked, changes the argument-passing behaviour so that it matches the intentions about calling the original f:
class A(object):
def method(self):
pass
#staticmethod
def stmethod():
pass
#classmethod
def clmethod(cls):
pass
a = A()
a.method() # the "function inside" gets told about a
A.method() # doesn't work because there is no reference to the needed object
a.clmethod() # the "function inside" gets told about a's class, A
A.clmethod() # works as well, because we only need the classgets told about a's class, A
a.stmethod() # the "function inside" gets told nothing about anything
A.stmethod() # works as well
So #classmethod and #staticmethod have in common that they "don't care about" the concrete object they were called with; the difference is that #staticmethod doesn't want to know anything at all about it, while #classmethod wants to know its class.
So the latter gets the class object the used object is an instance of. Just replace self with cls in this case.
Now, when to use what?
Well, that is easy to handle:
If you have an access to self, you clearly need an instance method.
If you don't access self, but want to know about its class, use #classmethod. This may for example be the case with factory methods. datetime.datetime.now() is such an example: you can call it via its class or via an instance, but it creates a new instance with completely different data. I even used them once for automatically generating subclasses of a given class.
If you need neither self nor cls, you use #staticmethod. This can as well be used for factory methods, if they don't need to care about subclassing.
#classmethod takes the class as first argument while function takes instance of the class
>>> class Test(object):
... def func(self):
... print self
... #classmethod
... def meth(self):
... print self
>>> t = Test()
>>> t.func()
<__main__.Test object at 0x00000000027238D0>
>>> t.meth()
<class '__main__.Test'>
I've used self argument in meth intentionally so it would be very close in syntax to the func. But usually you'd better use cls as argument:
... #classmethod
... def meth(cls):
... print cls

Python and initialization of class variables - how to use class method to initialize members?

I want to initialize class member with use class method but not know how to call it.
Can you suggest some solution - maybe it is very trivial but I can not find solution?
This code will not work - I do not why?
class X(object):
#staticmethod
def __Y():
return 1
CONSTANT = __Y()
x = X()
print x.CONSTANT
This will work but I need use call method to initialize class members.
class X(object):
CONSTANT = 1
x = X()
print x.CONSTANT
Note, I am not want initialize object variables but class variable.
Drop the #staticmethod decorator and the first approach will work as well. You don't need staticmethod just to call a function inside a class statement.
Since that way the function will not be usable when called from class instances, it is an idiom to also remove it after use. In your example:
class X(object):
def __y():
return 1
CONSTANT = __y()
# ... other uses of __y, if any
del __y
To understand why your approach didn't work, consider what staticmethod does. It wraps a normal function into a descriptor object that, when retrieved from the class, produces the original function unchanged, i.e. without the usual "bound method" semantics. (Retrieving a normal def function from an instance or a class would get you a bound method that automagically inserts self as the first argument.)
However, the descriptor returned by staticmethod is itself not callable, its sole function is to produce the callable object when accessed through the class or instance. Proposals to make the staticmethod descriptor callable were rejected because such use of staticmethod is erroneous in the first place.

Implementing bound method using descriptor

My question is related to bound method object, more specifically I am trying to imitate the same behavior that functions (which are essentially descriptors) present.
Let me first put here my understanding of how class_instance.function() works
class D(object):
def dfunc(self):
...
d=D()
d.dfunc() # will call D.__dict__['dfunc'].__get__(d,D)()
# gives a bound method which can be used directly
a=D.__dict__['dfunc'].__get__(d,D)
a() # works as d.D()
Does Python call D.__dict__['dfunc'] (d), in case when type(dfunc) is function and type(d).__dict__['dfunc'].__get__(d, type(d)) if x is a class instance?
Now coming to how I am trying to create a bound object using closure:
class E(object):
def __get__(self,obj,cls):
def returned(*args):
print(obj.__dict__)
return returned
class F(object):
e = E()
y = 9
f = F()
f.fvar = 9 # putting something in instances __dict__
a = f.e # will call the __get__ function of F and return a closure
a() # works and produces instance specific result -> {'fvar': 9}, just like a bound method
Now the main question,
when I did a = D.__dict__['dfunc'].__get__(d,D) type(a) was bound method, but when I implement it type(a) is function; is there a way to return bound object from user-defined descriptor?
Is there any better way to implement a function like descriptor?
Please correct me if I have gotten something fundamentally incorrect in my head.
If you want to return a method instead, you can create one from the function object together with the arguments passed to __get__:
import types
class E(object):
def __get__(self,obj,cls):
def returned(*args):
print(obj.__dict__)
return types.MethodType(returned, obj, cls)
However, it's not totally clear what this gains you. If just returning a function already works, why do you need it to be a "real" method?

Categories

Resources