Python detect direct method call - python

I have following code:
a = A()
a.foo(123)
A.foo(a, 123)
How can I detect which line caused foo() execution: 2 or 3? Thank you for your answers.

Preface: There are very few use cases where the difference between these is actually important. Having different behavior based on whether a method is called directly on an instance or by explicitly passing the instance to the method accessed through the class would likely violate the Principle of least astonishment
This solution uses the fact that we can tell whether a descriptor was accessed through an instance or through a class by whether the instance parameter is None or not.
from __future__ import annotations
from functools import partial
from typing import Optional, Type
class Method:
def __init__(self, func):
self.func = func
def __get__(self, instance: Optional[B], owner: Type[B]):
via_instance = instance is not None
if via_instance:
return partial(self.func, instance, via_instance=via_instance)
else:
return partial(self.func, via_instance=via_instance)
class B:
#Method
def foo(self, bar, via_instance):
if via_instance:
return 'via instance'
return 'via class'
Test:
>>> b = B()
>>> b.foo(123)
'via instance'
>>> B.foo(b, 123)
'via class'
It may still be technically possible to work around this detection, but this approach is not as hacky/brittle as the one below that uses inspect.
Alternate Solution
Note: This solution over-complicates the problem. This is extremely hacky, and there are many other cases that this does not cover. This guesses based on the defined parameters of this question. It is not definitive.
import ast
import inspect
from ast import Assign, Call, Expr
class A:
def foo(self, bar):
code = inspect.stack()[1].code_context[0]
parsed = ast.parse(code).body[0]
if isinstance(parsed, Assign):
parsed = parsed.value
if isinstance(parsed, Expr):
parsed = parsed.value
if not isinstance(parsed, Call):
raise TypeError(f'Unexpected type={type(parsed)} for {parsed=}')
if len(parsed.args) == 1:
return 'via instance'
return 'via class'
Test:
>>> a = A()
>>> a.foo(123)
'via instance'
>>> A.foo(a, 123)
'via class'
There are many other ways that the method could be called, and this approach is not guaranteed to catch all of them. Some examples of other ways :
super().foo(123) in a subclass
foo = partial(A.foo, bar=123); foo(a)
foo = partial(A.foo, a); foo(123)
args = (a, 123); A.foo(*args)
etc...

Related

In Python can isinstance() be used to detect a class method?

How to determine if an object is a class method? Isn't it best practice to use isinstance(), and how does one make that work?
class Foo:
class_var = 0
#classmethod
def bar(cls):
cls.class_var += 1
print("class variable value:", cls.class_var)
def wrapper(wrapped: classmethod):
"""
Call the wrapped method.
:param wrapped (classmethod, required)
"""
wrapped()
Foo.bar()
wrapper(Foo.bar)
print("the type is:", type(Foo.bar))
print("instance check success:", isinstance(Foo.bar, classmethod))
Output:
class variable value: 1
class variable value: 2
the type is: <class 'method'>
instance check success: False
Process finished with exit code 0
If you just want to tell class methods apart from regular methods and static methods, then you can check this with inspect.ismethod(f).
class A:
def method(self): pass
#classmethod
def class_method(cls): pass
#staticmethod
def static_method(): pass
In the REPL:
>>> from inspect import ismethod
>>> ismethod(A.method)
False
>>> ismethod(A.class_method)
True
>>> ismethod(A.static_method)
False
If you prefer to do this with isinstance, then that's possible using typing.types.MethodType:
>>> from typing import types
>>> isinstance(A.method, types.MethodType)
False
>>> isinstance(A.class_method, types.MethodType)
True
>>> isinstance(A.static_method, types.MethodType)
False
Note that these tests will incorrectly identify e.g. A().method because really we're just testing for a bound method as opposed to an unbound function. So the above solutions only work assuming that you are checking A.something where A is a class and something is either a regular method, a class method or a static method.
As you know Python fills the first parameter of the classmethods with a reference to the class itself and it doesn't matter if you call that method from the class or the instance of the class. A method object is a function which has an object bound to it.
That object can be retrieved by .__self__ attribute. So you can simply check that if the .__self__ attribute is a class or not. If it is a class , it's class is type.
One way of doing it:
class Foo:
#classmethod
def fn1(cls):
pass
def fn2(self):
pass
def is_classmethod(m):
first_parameter = getattr(m, '__self__', None)
if not first_parameter:
return False
type_ = type(first_parameter)
return type_ is type
print(is_classmethod(Foo.fn1))
print(is_classmethod(Foo().fn1))
print("-----------------------------------")
print(is_classmethod(Foo.fn2))
print(is_classmethod(Foo().fn2))
output:
True
True
-----------------------------------
False
False
There is a ismethod function in inspect module that specifically checks that if the object is a bound method. You can use this as well before checking for the type of the first parameter.
NOTE: There is a caveat with the above solution, I'll mention it at the end.
Solution number 2:
Your isinstance solution didn't work because classmethod is a descriptor. If you want to get the actual classmethod instance, you should check the Foo's namespace and get the methods from there.
class Foo:
#classmethod
def fn1(cls):
pass
def fn2(self):
pass
def is_classmethod(cls, m):
return isinstance(cls.__dict__[m.__name__], classmethod)
print(is_classmethod(Foo, Foo.fn1))
print(is_classmethod(Foo, Foo().fn1))
print("-----------------------------------")
print(is_classmethod(Foo, Foo.fn2))
print(is_classmethod(Foo, Foo().fn2))
Solution number 1 caveat: For example if you have a simple MethodType object whose bound object is a different class like int here, this solution isn't going to work. Because remember we just checked that if the first parameter is of type type:
from types import MethodType
class Foo:
def fn2(self):
pass
fn2 = MethodType(fn2, int)
#classmethod
def fn1(cls):
pass
Now only solution number 2 works.

Python: Check if a method uses #staticmethod [duplicate]

assume following class definition:
class A:
def f(self):
return 'this is f'
#staticmethod
def g():
return 'this is g'
a = A()
So f is a normal method and g is a static method.
Now, how can I check if the funcion objects a.f and a.g are static or not? Is there a "isstatic" funcion in Python?
I have to know this because I have lists containing many different function (method) objects, and to call them I have to know if they are expecting "self" as a parameter or not.
Lets experiment a bit:
>>> import types
>>> class A:
... def f(self):
... return 'this is f'
... #staticmethod
... def g():
... return 'this is g'
...
>>> a = A()
>>> a.f
<bound method A.f of <__main__.A instance at 0x800f21320>>
>>> a.g
<function g at 0x800eb28c0>
>>> isinstance(a.g, types.FunctionType)
True
>>> isinstance(a.f, types.FunctionType)
False
So it looks like you can use types.FunctionType to distinguish static methods.
Your approach seems a bit flawed to me, but you can check class attributes:
(in Python 2.7):
>>> type(A.f)
<type 'instancemethod'>
>>> type(A.g)
<type 'function'>
or instance attributes in Python 3.x
>>> a = A()
>>> type(a.f)
<type 'method'>
>>> type(a.g)
<type 'function'>
To supplement the answers here, in Python 3 the best way is like so:
import inspect
class Test:
#staticmethod
def test(): pass
isstatic = isinstance(inspect.getattr_static(Test, "test"), staticmethod)
We use getattr_static rather than getattr, since getattr will retrieve the bound method or function, not the staticmethod class object. You can do a similar check for classmethod types and property's (e.g. attributes defined using the #property decorator)
Note that even though it is a staticmethod, don't assume it was defined inside the class. The method source may have originated from another class. To get the true source, you can look at the underlying function's qualified name and module. For example:
class A:
#staticmethod:
def test(): pass
class B: pass
B.test = inspect.getattr_static(A, "test")
print("true source: ", B.test.__qualname__)
Technically, any method can be used as "static" methods, so long as they are called on the class itself, so just keep that in mind. For example, this will work perfectly fine:
class Test:
def test():
print("works!")
Test.test()
That example will not work with instances of Test, since the method will be bound to the instance and called as Test.test(self) instead.
Instance and class methods can be used as static methods as well in some cases, so long as the first arg is handled properly.
class Test:
def test(self):
print("works!")
Test.test(None)
Perhaps another rare case is a staticmethod that is also bound to a class or instance. For example:
class Test:
#classmethod
def test(cls): pass
Test.static_test = staticmethod(Test.test)
Though technically it is a staticmethod, it is really behaving like a classmethod. So in your introspection, you may consider checking the __self__ (recursively on __func__) to see if the method is bound to a class or instance.
I happens to have a module to solve this. And it's Python2/3 compatible solution. And it allows to test with method inherit from parent class.
Plus, this module can also test:
regular attribute
property style method
regular method
staticmethod
classmethod
For example:
class Base(object):
attribute = "attribute"
#property
def property_method(self):
return "property_method"
def regular_method(self):
return "regular_method"
#staticmethod
def static_method():
return "static_method"
#classmethod
def class_method(cls):
return "class_method"
class MyClass(Base):
pass
Here's the solution for staticmethod only. But I recommend to use the module posted here.
import inspect
def is_static_method(klass, attr, value=None):
"""Test if a value of a class is static method.
example::
class MyClass(object):
#staticmethod
def method():
...
:param klass: the class
:param attr: attribute name
:param value: attribute value
"""
if value is None:
value = getattr(klass, attr)
assert getattr(klass, attr) == value
for cls in inspect.getmro(klass):
if inspect.isroutine(value):
if attr in cls.__dict__:
bound_value = cls.__dict__[attr]
if isinstance(bound_value, staticmethod):
return True
return False
Why bother? You can just call g like you call f:
a = A()
a.f()
a.g()

Python override __str__ outside of class definition

Say I have a module that I've imported that works fine but doesn't provide a good __str__ method and I want to add one.
In some hybrid language:
from foo import Foo
Foo.prototype._str__ = function myNIcePrintFunction(){
}
How do I do this please in Python please?
You can first define a function, and then monkey-patch it.
Like:
def foostr(self):
return 'A foo str'
Foo.__str__ = foostr
Or with a lambda expression:
Foo.__str__ = lambda self: 'Another foo str'
There is however a small difference in the fact that this method will have a different Foo.__str__.__name__, etc. But the str(..) builtin function will work as expected. As #chepner says, we can use the wrap function from functools to preserve most meta-data:
from functools import wraps
def foostr(self):
return 'A foo str'
Foo.__str__ = wraps(Foo.__str__)(foostr)
But then Foo.__str__.__qualname__ will for example result in 'superfoo.__str__' (with superfoo the first class in the method resolution order (MRO) of Foo that implemented __str__).
For example:
>>> class Foo:
... pass
...
>>> str(Foo())
'<__main__.Foo object at 0x7f807046e668>'
>>> Foo.__str__ = lambda self: 'another Foo str'
>>> str(Foo())
'another Foo str'
If you have access to the implementation of the Foo class, it is however better to just define a __str__ function in the class, and not monkey patch it later in the process.
You can override any class function like this, while maintaining the original functionalities:
class a():
pass
def monkey(fn):
def newfn(self,*args, **kw):
print('hijacked!')
return fn(self,*args, **kw)
return newfn
a.__str__ = monkey(a.__str__)
b = a()
print(str(b))
>>> hijacked!
>>> <__main__.a object at 0x7f61f19faa58>

Proper way of using properties with try and except

I have classes that have attributes set with #property decorator. They function as getter and setter using try and except clauses inside them. If attribute is not set, it gets data from database and uses it to instatiate objects from other classes. I tried to keep the example short, but the code used to instantiate attribute objects is a little different with each attribute. What they have in common is the try-except at the beginning.
class SubClass(TopClass):
#property
def thing(self):
try:
return self._thing
except AttributeError:
# We don't have any thing yet
pass
thing = get_some_thing_from_db('thing')
if not thing:
raise AttributeError()
self._thing = TheThing(thing)
return self._thing
#property
def another_thing(self):
try:
return self._another_thing
except AttributeError:
# We don't have things like this yet
pass
another_thing = get_some_thing_from_db('another')
if not another_thing:
raise AttributeError()
self._another_thing = AnotherThing(another_thing)
return self._another_thing
...etc...
#property
def one_more_thing(self):
try:
return self._one_more_thing
except AttributeError:
# We don't have this thing yet
pass
one_thing = get_some_thing_from_db('one')
if not one_thing:
raise AttributeError()
self._one_more_thing = OneThing(one_thing)
return self._one_more_thing
My question: is this a proper (e.g. pythonic) way of doing stuff? To me it seems a bit awkward to add the try-except-segment on top of everything. On the other hand it keeps the code short. Or is there a better way of defining attributes?
So long as you are using at least Python 3.2, use the functools.lru_cache() decorator.
import functools
class SubClass(TopClass):
#property
#functools.lru_cache()
def thing(self):
thing = get_some_thing_from_db('thing')
if not thing:
raise AttributeError()
return TheThing(thing)
A quick runnable example:
>>> import functools
>>> class C:
#property
#functools.lru_cache()
def foo(self):
print("Called foo")
return 42
>>> c = C()
>>> c.foo
Called foo
42
>>> c.foo
42
If you have a lot of these you can combine the decorators:
>>> def lazy_property(f):
return property(functools.lru_cache()(f))
>>> class C:
#lazy_property
def foo(self):
print("Called foo")
return 42
>>> c = C()
>>> c.foo
Called foo
42
>>> c.foo
42
If you are still on an older version of Python there's a fully featured backport of lru_cache on ActiveState although as in this case you're not passing any parameters when you call it you could probably replace it with something much simpler.
#YAmikep asks how to access the cache_info() method of lru_cache. It's a little bit messy, but you can still access it through the property object:
>>> C.foo.fget.cache_info()
CacheInfo(hits=0, misses=1, maxsize=128, currsize=1)

How do I get list of methods in a Python class?

I want to iterate through the methods in a class, or handle class or instance objects differently based on the methods present. How do I get a list of class methods?
Also see:
How can I list the methods in a
Python 2.5 module?
Looping over
a Python / IronPython Object
Methods
Finding the methods an
object has
How do I look inside
a Python object?
How Do I
Perform Introspection on an Object in
Python 2.x?
How to get a
complete list of object’s methods and
attributes?
Finding out which
functions are available from a class
instance in python?
An example (listing the methods of the optparse.OptionParser class):
>>> from optparse import OptionParser
>>> import inspect
#python2
>>> inspect.getmembers(OptionParser, predicate=inspect.ismethod)
[([('__init__', <unbound method OptionParser.__init__>),
...
('add_option', <unbound method OptionParser.add_option>),
('add_option_group', <unbound method OptionParser.add_option_group>),
('add_options', <unbound method OptionParser.add_options>),
('check_values', <unbound method OptionParser.check_values>),
('destroy', <unbound method OptionParser.destroy>),
('disable_interspersed_args',
<unbound method OptionParser.disable_interspersed_args>),
('enable_interspersed_args',
<unbound method OptionParser.enable_interspersed_args>),
('error', <unbound method OptionParser.error>),
('exit', <unbound method OptionParser.exit>),
('expand_prog_name', <unbound method OptionParser.expand_prog_name>),
...
]
# python3
>>> inspect.getmembers(OptionParser, predicate=inspect.isfunction)
...
Notice that getmembers returns a list of 2-tuples. The first item is the name of the member, the second item is the value.
You can also pass an instance to getmembers:
>>> parser = OptionParser()
>>> inspect.getmembers(parser, predicate=inspect.ismethod)
...
There is the dir(theobject) method to list all the fields and methods of your object (as a tuple) and the inspect module (as codeape write) to list the fields and methods with their doc (in """).
Because everything (even fields) might be called in Python, I'm not sure there is a built-in function to list only methods. You might want to try if the object you get through dir is callable or not.
Python 3.x answer without external libraries
method_list = [func for func in dir(Foo) if callable(getattr(Foo, func))]
dunder-excluded result:
method_list = [func for func in dir(Foo) if callable(getattr(Foo, func)) and not func.startswith("__")]
Say you want to know all methods associated with list class
Just Type The following
print (dir(list))
Above will give you all methods of list class
Try the property __dict__.
you can also import the FunctionType from types and test it with the class.__dict__:
from types import FunctionType
class Foo:
def bar(self): pass
def baz(self): pass
def methods(cls):
return [x for x, y in cls.__dict__.items() if type(y) == FunctionType]
methods(Foo) # ['bar', 'baz']
You can list all methods in a python class by using the following code
dir(className)
This will return a list of all the names of the methods in the class
Note that you need to consider whether you want methods from base classes which are inherited (but not overridden) included in the result. The dir() and inspect.getmembers() operations do include base class methods, but use of the __dict__ attribute does not.
If your method is a "regular" method and not a staticmethod, classmethod etc.
There is a little hack I came up with -
for k, v in your_class.__dict__.items():
if "function" in str(v):
print(k)
This can be extended to other type of methods by changing "function" in the if condition correspondingly.
Tested in Python 2.7 and Python 3.5.
Try
print(help(ClassName))
It prints out methods of the class
I just keep this there, because top rated answers are not clear.
This is simple test with not usual class based on Enum.
# -*- coding: utf-8 -*-
import sys, inspect
from enum import Enum
class my_enum(Enum):
"""Enum base class my_enum"""
M_ONE = -1
ZERO = 0
ONE = 1
TWO = 2
THREE = 3
def is_natural(self):
return (self.value > 0)
def is_negative(self):
return (self.value < 0)
def is_clean_name(name):
return not name.startswith('_') and not name.endswith('_')
def clean_names(lst):
return [ n for n in lst if is_clean_name(n) ]
def get_items(cls,lst):
try:
res = [ getattr(cls,n) for n in lst ]
except Exception as e:
res = (Exception, type(e), e)
pass
return res
print( sys.version )
dir_res = clean_names( dir(my_enum) )
inspect_res = clean_names( [ x[0] for x in inspect.getmembers(my_enum) ] )
dict_res = clean_names( my_enum.__dict__.keys() )
print( '## names ##' )
print( dir_res )
print( inspect_res )
print( dict_res )
print( '## items ##' )
print( get_items(my_enum,dir_res) )
print( get_items(my_enum,inspect_res) )
print( get_items(my_enum,dict_res) )
And this is output results.
3.7.7 (default, Mar 10 2020, 13:18:53)
[GCC 9.2.1 20200306]
## names ##
['M_ONE', 'ONE', 'THREE', 'TWO', 'ZERO']
['M_ONE', 'ONE', 'THREE', 'TWO', 'ZERO', 'name', 'value']
['is_natural', 'is_negative', 'M_ONE', 'ZERO', 'ONE', 'TWO', 'THREE']
## items ##
[<my_enum.M_ONE: -1>, <my_enum.ONE: 1>, <my_enum.THREE: 3>, <my_enum.TWO: 2>, <my_enum.ZERO: 0>]
(<class 'Exception'>, <class 'AttributeError'>, AttributeError('name'))
[<function my_enum.is_natural at 0xb78a1fa4>, <function my_enum.is_negative at 0xb78ae854>, <my_enum.M_ONE: -1>, <my_enum.ZERO: 0>, <my_enum.ONE: 1>, <my_enum.TWO: 2>, <my_enum.THREE: 3>]
So what we have:
dir provide not complete data
inspect.getmembers provide not complete data and provide internal keys that are not accessible with getattr()
__dict__.keys() provide complete and reliable result
Why are votes so erroneous? And where i'm wrong? And where wrong other people which answers have so low votes?
There's this approach:
[getattr(obj, m) for m in dir(obj) if not m.startswith('__')]
When dealing with a class instance, perhaps it'd be better to return a list with the method references instead of just names¹. If that's your goal, as well as
Using no import
Excluding private methods (e.g. __init__) from the list
It may be of use. You might also want to assure it's callable(getattr(obj, m)), since dir returns all attributes within obj, not just methods.
In a nutshell, for a class like
class Ghost:
def boo(self, who):
return f'Who you gonna call? {who}'
We could check instance retrieval with
>>> g = Ghost()
>>> methods = [getattr(g, m) for m in dir(g) if not m.startswith('__')]
>>> print(methods)
[<bound method Ghost.boo of <__main__.Ghost object at ...>>]
So you can call it right away:
>>> for method in methods:
... print(method('GHOSTBUSTERS'))
...
Who you gonna call? GHOSTBUSTERS
¹ An use case:
I used this for unit testing. Had a class where all methods performed variations of the same process - which led to lengthy tests, each only a tweak away from the others. DRY was a far away dream.
Thought I should have a single test for all methods, so I made the above iteration.
Although I realized I should instead refactor the code itself to be DRY-compliant anyway... this may still serve a random nitpicky soul in the future.
This also works:
In mymodule.py:
def foo(x):
return 'foo'
def bar():
return 'bar'
In another file:
import inspect
import mymodule
method_list = [ func[0] for func in inspect.getmembers(mymodule, predicate=inspect.isroutine) if callable(getattr(mymodule, func[0])) ]
Output:
['foo', 'bar']
From the Python docs:
inspect.isroutine(object)
Return true if the object is a user-defined or built-in function or method.
def find_defining_class(obj, meth_name):
for ty in type(obj).mro():
if meth_name in ty.__dict__:
return ty
So
print find_defining_class(car, 'speedometer')
Think Python page 210
You can use a function which I have created.
def method_finder(classname):
non_magic_class = []
class_methods = dir(classname)
for m in class_methods:
if m.startswith('__'):
continue
else:
non_magic_class.append(m)
return non_magic_class
method_finder(list)
Output:
['append',
'clear',
'copy',
'count',
'extend',
'index',
'insert',
'pop',
'remove',
'reverse',
'sort']
methods = [(func, getattr(o, func)) for func in dir(o) if callable(getattr(o, func))]
gives an identical list as
methods = inspect.getmembers(o, predicate=inspect.ismethod)
does.
I know this is an old post, but just wrote this function and will leave it here is case someone stumbles looking for an answer:
def classMethods(the_class,class_only=False,instance_only=False,exclude_internal=True):
def acceptMethod(tup):
#internal function that analyzes the tuples returned by getmembers tup[1] is the
#actual member object
is_method = inspect.ismethod(tup[1])
if is_method:
bound_to = tup[1].im_self
internal = tup[1].im_func.func_name[:2] == '__' and tup[1].im_func.func_name[-2:] == '__'
if internal and exclude_internal:
include = False
else:
include = (bound_to == the_class and not instance_only) or (bound_to == None and not class_only)
else:
include = False
return include
#uses filter to return results according to internal function and arguments
return filter(acceptMethod,inspect.getmembers(the_class))
use inspect.ismethod and dir and getattr
import inspect
class ClassWithMethods:
def method1(self):
print('method1')
def method2(self):
print('method2')
obj=ClassWithMethods()
method_names = [attr for attr in dir(obj) if inspect.ismethod(getattr(obj,attr))
print(method_names)
output:
[[('method1', <bound method ClassWithMethods.method1 of <__main__.ClassWithMethods object at 0x00000266779AF388>>), ('method2', <bound method ClassWithMethods.method2 of <__main__.ClassWithMethods object at 0x00000266779AF388>>)]]
None of the above worked for me.
I've encountered this problem while writing pytests.
The only work-around I found was to:
1- create another directory and place all my .py files there
2- create a separate directory for my pytests and then importing the classes I'm interested in
This allowed me to get up-to-dated methods within the class - you can change the method names and then use print(dir(class)) to confirm it.
For my use case, I needed to distinguish between class methods, static methods, properties, and instance methods. The inspect module confuses the issue a bit (particularly with class methods and instance methods), so I used vars based on a comment on this SO question. The basic gist is to use vars to get the __dict__ attribute of the class, then filter based on various isinstance checks. For instance methods, I check that it is callable and not a class method. One caveat: this approach of using vars (or __dict__ for that matter) won't work with __slots__. Using Python 3.6.9 (because it's what the Docker image I'm using as my interpreter has):
class MethodAnalyzer:
class_under_test = None
#classmethod
def get_static_methods(cls):
if cls.class_under_test:
return {
k for k, v in vars(cls.class_under_test).items()
if isinstance(v, staticmethod)
}
return {}
#classmethod
def get_class_methods(cls):
if cls.class_under_test:
return {
k for k, v in vars(cls.class_under_test).items()
if isinstance(v, classmethod)
}
return {}
#classmethod
def get_instance_methods(cls):
if cls.class_under_test:
return {
k for k, v in vars(cls.class_under_test).items()
if callable(v) and not isinstance(v, classmethod)
}
return {}
#classmethod
def get_properties(cls):
if cls.class_under_test:
return {
k for k, v in vars(cls.class_under_test).items()
if isinstance(v, property)
}
return {}
To see it in action, I created this little test class:
class Foo:
#staticmethod
def bar(baz):
print(baz)
#property
def bleep(self):
return 'bloop'
#classmethod
def bork(cls):
return cls.__name__
def flank(self):
return 'on your six'
then did:
MethodAnalyzer.class_under_test = Foo
print(MethodAnalyzer.get_instance_methods())
print(MethodAnalyzer.get_class_methods())
print(MethodAnalyzer.get_static_methods())
print(MethodAnalyzer.get_properties())
which output
{'flank'}
{'bork'}
{'bar'}
{'bleep'}
In this example I'm discarding the actual methods, but if you needed to keep them you could just use a dict comprehension instead of a set comprehension:
{
k, v for k, v in vars(cls.class_under_test).items()
if callable(v) and not isinstance(v, classmethod)
}
This is just an observation. "encode" seems to be a method for string objects
str_1 = 'a'
str_1.encode('utf-8')
>>> b'a'
However, if str1 is inspected for methods, an empty list is returned
inspect.getmember(str_1, predicate=inspect.ismethod)
>>> []
So, maybe I am wrong, but the issue seems to be not simple.
To produce a list of methods put the name of the method in a list without the usual parenthesis. Remove the name and attach the parenthesis and that calls the method.
def methodA():
print("# MethodA")
def methodB():
print("# methodB")
a = []
a.append(methodA)
a.append(methodB)
for item in a:
item()
Just like this
pprint.pprint([x for x in dir(list) if not x.startswith("_")])
class CPerson:
def __init__(self, age):
self._age = age
def run(self):
pass
#property
def age(self): return self._age
#staticmethod
def my_static_method(): print("Life is short, you need Python")
#classmethod
def say(cls, msg): return msg
test_class = CPerson
# print(dir(test_class)) # list all the fields and methods of your object
print([(name, t) for name, t in test_class.__dict__.items() if type(t).__name__ == 'function' and not name.startswith('__')])
print([(name, t) for name, t in test_class.__dict__.items() if type(t).__name__ != 'function' and not name.startswith('__')])
output
[('run', <function CPerson.run at 0x0000000002AD3268>)]
[('age', <property object at 0x0000000002368688>), ('my_static_method', <staticmethod object at 0x0000000002ACBD68>), ('say', <classmethod object at 0x0000000002ACF0B8>)]
If you want to list only methods of a python class
import numpy as np
print(np.random.__all__)

Categories