In Python when we define class all its members including variables and methods also becomes attributes of that class. In following example MyClass1.a and MyClass1.mydef1 are attributes of class MyClass1.
class MyClass1:
a = 10
def mydef1(self):
return 0
ins1 = MyClass1() # create instance
print(MyClass1.a) # access class attribute which is class variable
print(MyClass1.mydef1) # No idea what to do with it so just printing
print(ins1.mydef1) # No idea what to do with it so just printing
Output
10
<function MyClass1.mydef1 at 0x0000000002122EA0>
<bound method MyClass1.mydef1 of <__main__.MyClass1 object at 0x000000000212D0F0>>
Here attribute a is a variable and it can be used like any other variable.
But mydef1 is a method, if it is not invoked and just used like MyClass1.mydef1 or ins1.mydef1, it returns object for that method(correct me if I am wrong).
So my question is, what can we do with the Class/instance methods without invoking it? Are there any use cases for it or is it just good to know thing?
An attribute of a class that happens to be a function becomes a method for instances or that class:
inst.foo(params, ...)
is internally translated into:
cls.foo(inst, params, ...)
That means that what is actually invoked is the attribute from the class of the instance, and the instance itself is prepended to the argument list. It is just Python syntax to invoke methods on objects.
In your example the correct uses would be:
print(MyClass1.mydef1(ins1)) # prints 0
print(ins1.mydef1()) # also prints 0
Well instance methods can be called with the appropriate parameters of course:
print(ins1.mydef1()) # no parameters, so empty parenthesis, this call should print "0" in your example instead of the method description
If you use it without the parenthesis, you are playing with reference to the function, I don't think you can have any use of it, except checking the list of methods available in a class or something like that.
Related
In JavaScript, we can do the following to any object or function
const myFn = () => {};
Object.defineProperties(myFn, {
property: {
get: () => console.log('property accessed')
}
});
This will allow for a #property like syntax by defining a getter function for the property property.
myFn.property
// property accessed
Is there anything similar for functions in Python?
I know we can't use property since it's not a new-style class, and assigning a lambda with setattr will not work since it'll be a function.
Basically what I want to achieve is that whenever my_fn.property is to return a new instance of another class on each call.
What I currently have with setattr is this
setattr(my_fn, 'property', OtherClass())
My hopes are to design an API that looks like this my_fn.property.some_other_function().
I would prefer using a function as my_fn and not an instance of a class, even though I realize that it might be easier to implement.
Below is the gist of what I'm trying to achieve
def my_fn():
pass
my_fn = property('property', lambda: OtherClass())
my_fn.property
// will be a new instance of OtherClass on each call
It's not possible to do exactly what you want. The descriptor protocol that powers the property built-in is only invoked when:
The descriptor is defined on a class
The descriptor's name is accessed on an instance of said class
Problem is, the class behind functions defined in Python (aptly named function, exposed directly as types.FunctionType or indirectly by calling type() on any function defined at the Python layer) is a single shared, immutable class, so you can't add descriptors to it (and even if you could, they'd become attributes of every Python level function, not just one particular function).
The closest you can get to what you're attempting would be to define a callable class (defining __call__) that defines the descriptor you're interested in as well. Make a single instance of that class (you can throw away the class itself at this point) and it will behave as you expect. Make __call__ a staticmethod, and you'll avoid changing the signature to boot.
For example, the behavior you want could be achieved with:
class my_fn:
# Note: Using the name "property" for a property has issues if you define
# other properties later in the class; this is just for illustration
#property
def property(self):
return OtherClass()
#staticmethod
def __call__(...whatever args apply; no need for self...):
... function behavior goes here ...
my_fn = my_fn() # Replace class with instance of class that behaves like a function
Now you can call the "function" (really a functor, to use C++ parlance):
my_fn(...)
or access the property, getting a brand new OtherClass each time:
>>> type(my_fn.property) is type(my_fn.property)
True
>>> my_fn.property is my_fn.property
False
No, this isn't what you asked for (you seem set on having a plain function do this for you), but you're asking for a very JavaScript specific thing which doesn't exist in Python.
What you want is not currently possible, because the property would have to be set on the function type to be invoked correctly. And you are not allowed to monkeypatch the function type:
>>> type(my_fn).property = 'anything else'
TypeError: can't set attributes of built-in/extension type 'function'
The solution: use a callable class instead.
Note: What you want may become possible in Python 3.8 if PEP 575 is accepted.
This question already has answers here:
Why does setattr fail on a bound method
(2 answers)
Closed 9 years ago.
I'm wondering if it is possible to use setattr to set an attribute to a method within a class like so because when I try I get an error which is going to be shown after the code:
class Test:
def getString(self, var):
setattr(self.getString, "string", var)
return self.getString
test = Test()
test.getString("myString").string
Which errors AttributeError: 'method' object has no attribute 'string' so I tried it without putting .string and just tried test.getString("myString") Same error, but then I tried it without the using the class just like this
def getString(var):
setattr(getString, "string", var)
return getString
getString("myString").string
It returned "myString" like I wanted it to, so how would I do this within a class and why does it work outside of one but inside of one?
type( test.getString ) is builtins.method and from the documentations ( methods ),
since method attributes are actually stored on the underlying function
object (meth.__func__), setting method attributes on bound methods is
disallowed. Attempting to set an attribute on a method results in an
AttributeError being raised.
There are (at least) two possible solutions depending on which behaviour you are looking for. One is to set the attribute on the class method:
class Test:
def getString(self, var):
setattr(Test.getString, "string", var)
return self.getString
test = Test()
test.getString("myString").string # > "myString"
test2 = Test()
test2.getString.string # > this is also "myString"
and the other is to use function objects:
class Test:
class getStringClass:
def __call__ ( self, var ):
setattr( self, "string", var )
return self
def __init__( self ):
self.getString = Test.getStringClass( )
test = Test( )
test.getString( "myString" ).string # > "myString"
test2 = Test()
test2.getString.string # > this is error, because it does not
# have the attribute 'string' yet
Functions are like most other objects in that you can freely add attributes to them. Methods, on the other hand... conceptually they're just functions, but they behave slightly differently (implicity pass self) and therefore are implemented with a bit of extra glue around functions.
Every time self.getString is evaluated, a new (bound) method object is created, which is a thin wrapper around the underlying function (which you can access as Test.getString). These method objects don't allow adding attributes, and even if they did, your code would not work because it juggles multiple distinct method objects (though they all wrap the same function).
You can't make this work with bound methods. Since you presumably want the string to be attached to the Test object (indirectly, by being attached to its method), you can make it an attribute of Test. You could even create your own object that behaves like a method but allows attributes (you'd have to explicitly add it in __init__), but honestly there's probably a better way that keeps data and methods separated. If, on the other hand, you want to attach this attribute to the underlying function (which would mean it's shared by all Test instances), you can just set the attribute on Test.getString.
So, I found a way but it's not really how I wanted to do it personally. If anyone does find another way to do the following code feel free to comment on how to do it.
class Test:
def getString(self, string):
setattr(self,"newString",self)
self.newString.string = string
return self.newString
Like I said, I don't feel like I accomplished anything by doing it that way, but it works for what I need and if you do find another way comment below.
Consider this example of a strategy pattern in Python (adapted from the example here). In this case the alternate strategy is a function.
class StrategyExample(object):
def __init__(self, strategy=None) :
if strategy:
self.execute = strategy
def execute(*args):
# I know that the first argument for a method
# must be 'self'. This is just for the sake of
# demonstration
print locals()
#alternate strategy is a function
def alt_strategy(*args):
print locals()
Here are the results for the default strategy.
>>> s0 = StrategyExample()
>>> print s0
<__main__.StrategyExample object at 0x100460d90>
>>> s0.execute()
{'args': (<__main__.StrategyExample object at 0x100460d90>,)}
In the above example s0.execute is a method (not a plain vanilla function) and hence the first argument in args, as expected, is self.
Here are the results for the alternate strategy.
>>> s1 = StrategyExample(alt_strategy)
>>> s1.execute()
{'args': ()}
In this case s1.execute is a plain vanilla function and as expected, does not receive self. Hence args is empty. Wait a minute! How did this happen?
Both the method and the function were called in the same fashion. How does a method automatically get self as the first argument? And when a method is replaced by a plain vanilla function how does it not get the self as the first argument?
The only difference that I was able to find was when I examined the attributes of default strategy and alternate strategy.
>>> print dir(s0.execute)
['__cmp__', '__func__', '__self__', ...]
>>> print dir(s1.execute)
# does not have __self__ attribute
Does the presence of __self__ attribute on s0.execute (the method), but lack of it on s1.execute (the function) somehow account for this difference in behavior? How does this all work internally?
You can read the full explanation here in the python reference, under "User defined methods". A shorter and easier explanation can be found in the python tutorial's description of method objects:
If you still don’t understand how methods work, a look at the implementation can perhaps clarify matters. When an instance attribute is referenced that isn’t a data attribute, its class is searched. If the name denotes a valid class attribute that is a function object, a method object is created by packing (pointers to) the instance object and the function object just found together in an abstract object: this is the method object. When the method object is called with an argument list, a new argument list is constructed from the instance object and the argument list, and the function object is called with this new argument list.
Basically, what happens in your example is this:
a function assigned to a class (as happens when you declare a method inside the class body) is... a method.
When you access that method through the class, eg. StrategyExample.execute you get an "unbound method": it doesn't "know" to which instance it "belongs", so if you want to use that on an instance, you would need to provide the instance as the first argument yourself, eg. StrategyExample.execute(s0)
When you access the method through the instance, eg. self.execute or s0.execute, you get a "bound method": it "knows" which object it "belongs" to, and will get called with the instance as the first argument.
a function that you assign to an instance attribute directly however, as in self.execute = strategy or even s0.execute = strategy is... just a plain function (contrary to a method, it doesn't pass via the class)
To get your example to work the same in both cases:
either you turn the function into a "real" method: you can do this with types.MethodType:
self.execute = types.MethodType(strategy, self, StrategyExample)
(you more or less tell the class that when execute is asked for this particular instance, it should turn strategy into a bound method)
or - if your strategy doesn't really need access to the instance - you go the other way around and turn the original execute method into a static method (making it a normal function again: it won't get called with the instance as the first argument, so s0.execute() will do exactly the same as StrategyExample.execute()):
#staticmethod
def execute(*args):
print locals()
You need to assign an unbound method (i.e. with a self parameter) to the class or a bound method to the object.
Via the descriptor mechanism, you can make your own bound methods, it's also why it works when you assign the (unbound) function to a class:
my_instance = MyClass()
MyClass.my_method = my_method
When calling my_instance.my_method(), the lookup will not find an entry on my_instance, which is why it will at a later point end up doing this: MyClass.my_method.__get__(my_instance, MyClass) - this is the descriptor protocol. This will return a new method that is bound to my_instance, which you then execute using the () operator after the property.
This will share method among all instances of MyClass, no matter when they were created. However, they could have "hidden" the method before you assigned that property.
If you only want specific objects to have that method, just create a bound method manually:
my_instance.my_method = my_method.__get__(my_instance, MyClass)
For more detail about descriptors (a guide), see here.
The method is a wrapper for the function, and calls the function with the instance as the first argument. Yes, it contains a __self__ attribute (also im_self in Python prior to 3.x) that keeps track of which instance it is attached to. However, adding that attribute to a plain function won't make it a method; you need to add the wrapper. Here is how (although you may want to use MethodType from the types module to get the constructor, rather than using type(some_obj.some_method).
The function wrapped, by the way, is accessible through the __func__ (or im_func) attribute of the method.
When you do self.execute = strategy you set the attribute to a plain method:
>>> s = StrategyExample()
>>> s.execute
<bound method StrategyExample.execute of <__main__.StrategyExample object at 0x1dbbb50>>
>>> s2 = StrategyExample(alt_strategy)
>>> s2.execute
<function alt_strategy at 0x1dc1848>
A bound method is a callable object that calls a function passing an instance as the first argument in addition to passing through all arguments it was called with.
See: Python: Bind an Unbound Method?
For the error:
TypeError: takes exactly 1 argument (2 given)
With the following class method:
def extractAll(tag):
...
and calling it:
e.extractAll("th")
The error seems very odd when I'm giving it 1 argument, the method should take only 1 argument, but it's saying I'm not giving it 1 argument....I know the problem can be fixed by adding self into the method prototype but I wanted to know the reasoning behind the error.
Am I getting it because the act of calling it via e.extractAll("th") also passes in self as an argument? And if so, by removing the self in the call, would I be making it some kind of class method that can be called like Extractor.extractAll("th")?
The call
e.extractAll("th")
for a regular method extractAll() is indeed equivalent to
Extractor.extractAll(e, "th")
These two calls are treated the same in all regards, including the error messages you get.
If you don't need to pass the instance to a method, you can use a staticmethod:
#staticmethod
def extractAll(tag):
...
which can be called as e.extractAll("th"). But I wonder why this is a method on a class at all if you don't need to access any instance.
If a non-static method is member of a class, you have to define it like that:
def Method(self, atributes..)
So, I suppose your 'e' is instance of some class with implemented method that tries to execute and has too much arguments.
Am I getting it because the act of calling it via e.extractAll("th") also passes in self as an argument?
Yes, that's precisely it. If you like, the first parameter is the object name, e that you are calling it with.
And if so, by removing the self in the call, would I be making it some kind of class method that can be called like Extractor.extractAll("th")?
Not quite. A classmethod needs the #classmethod decorator, and that accepts the class as the first paramater (usually referenced as cls). The only sort of method that is given no automatic parameter at all is known as a staticmethod, and that again needs a decorator (unsurprisingly, it's #staticmethod). A classmethod is used when it's an operation that needs to refer to the class itself: perhaps instantiating objects of the class; a staticmethod is used when the code belongs in the class logically, but requires no access to class or instance.
But yes, both staticmethods and classmethods can be called by referencing the classname as you describe: Extractor.extractAll("th").
Yes, when you invoke e.extractAll(foo), Python munges that into extractAll(e, foo).
From http://docs.python.org/tutorial/classes.html
the special thing about methods is
that the object is passed as the first
argument of the function. In our
example, the call x.f() is exactly
equivalent to MyClass.f(x). In
general, calling a method with a list
of n arguments is equivalent to
calling the corresponding function
with an argument list that is created
by inserting the method’s object
before the first argument.
Emphasis added.
Summary (Some examples of how to define methods in classes in python)
#!/usr/bin/env python # (if running from bash)
class Class1(object):
def A(self, arg1):
print arg1
# this method requires an instance of Class1
# can access self.variable_name, and other methods in Class1
#classmethod
def B(cls, arg1):
cls.C(arg1)
# can access methods B and C in Class1
#staticmethod
def C(arg1):
print arg1
# can access methods B and C in Class1
# (i.e. via Class1.B(...) and Class1.C(...))
Example
my_obj=Class1()
my_obj.A("1")
# Class1.A("2") # TypeError: method A() must be called with Class1 instance
my_obj.B("3")
Class1.B("4")
my_obj.C("5")
Class1.C("6")`
try using:
def extractAll(self,tag):
attention to self
I'm trying to get the name of all methods in my class.
When testing how the inspect module works, i extraced one of my methods by obj = MyClass.__dict__['mymethodname'].
But now inspect.ismethod(obj) returns False while inspect.isfunction(obj) returns True, and i don't understand why. Is there some strange way of marking methods as methods that i am not aware of? I thought it was just that it is defined in the class and takes self as its first argument.
You are seeing some effects of the behind-the-scenes machinery of Python.
When you write f = MyClass.__dict__['mymethodname'], you get the raw implementation of "mymethodname", which is a plain function. To call it, you need to pass in an additional parameter, class instance.
When you write f = MyClass.mymethodname (note the absence of parentheses after mymethodname), you get an unbound method of class MyClass, which is an instance of MethodType that wraps the raw function you obtained above. To call it, you need to pass in an additional parameter, class instance.
When you write f = MyClass().mymethodname (note that i've created an object of class MyClass before taking its method), you get a bound method of an instance of class MyClass. You do not need to pass an additional class instance to it, since it's already stored inside it.
To get wrapped method (bound or unbound) by its name given as a string, use getattr, as noted by gnibbler. For example:
unbound_mth = getattr(MyClass, "mymethodname")
or
bound_mth = getattr(an_instance_of_MyClass, "mymethodname")
Use the source
def ismethod(object):
"""Return true if the object is an instance method.
Instance method objects provide these attributes:
__doc__ documentation string
__name__ name with which this method was defined
__func__ function object containing implementation of method
__self__ instance to which this method is bound"""
return isinstance(object, types.MethodType)
The first argument being self is just by convention. By accessing the method by name from the class's dict, you are bypassing the binding, so it appears to be a function rather than a method
If you want to access the method by name use
getattr(MyClass, 'mymethodname')
Well, do you mean that obj.mymethod is a method (with implicitly passed self) while Klass.__dict__['mymethod'] is a function?
Basically Klass.__dict__['mymethod'] is the "raw" function, which can be turned to a method by something called descriptors. This means that every function on a class can be both a normal function and a method, depending on how you access them. This is how the class system works in Python and quite normal.
If you want methods, you can't go though __dict__ (which you never should anyways). To get all methods you should do inspect.getmembers(Klass_or_Instance, inspect.ismethod)
You can read the details here, the explanation about this is under "User-defined methods".
From a comment made on #THC4k's answer, it looks like the OP wants to discriminate between built-in methods and methods defined in pure Python code. User defined methods are of types.MethodType, but built-in methods are not.
You can get the various types like so:
import inspect
import types
is_user_defined_method = inspect.ismethod
def is_builtin_method(arg):
return isinstance(arg, (type(str.find), type('foo'.find)))
def is_user_or_builtin_method(arg):
MethodType = types.MethodType
return isinstance(arg, (type(str.find), type('foo'.find), MethodType))
class MyDict(dict):
def puddle(self): pass
for obj in (MyDict, MyDict()):
for test_func in (is_user_defined_method, is_builtin_method,
is_user_or_builtin_method):
print [attr
for attr in dir(obj)
if test_func(getattr(obj, attr)) and attr.startswith('p')]
which prints:
['puddle']
['pop', 'popitem']
['pop', 'popitem', 'puddle']
['puddle']
['pop', 'popitem']
['pop', 'popitem', 'puddle']
You could use dir to get the name of available methods/attributes/etc, then iterate through them to see which ones are methods. Like this:
[ mthd for mthd in dir(FooClass) if inspect.ismethod(myFooInstance.__getattribute__(mthd)) ]
I'm expecting there to be a cleaner solution, but this could be something you could use if nobody else comes up with one. I'd like if I didn't have to use an instance of the class to use getattribute.