checking if a method is defined on the class
Use this:
C.instance_methods(false).include?(:a)
C.instance_methods(false).include?(:b)
C.instance_methods(false).include?(:c)
The method instance_methods
return an Array of methods that an instance of this class would have. Passing false
as first parameter returns only methods of this class, not methods of super classes.
So C.instance_methods(false)
returns the list of methods defined by C
.
Then you just have to check if that method is in the returned Array (this is what the include?
calls do).
See docs
Check if a method is defined in the base or derived class
You don't need any fancy inspection to do this:
>>> x = child_class_2()
>>> x.test
<function base_class.test at 0x7fea1a07f7b8>
>>> y = child_class()
>>> y.test
<function child_class.test at 0x7fea1a07f950>
The printed name comes from the __qualname__
attribute of the function by default:
>>> x.test.__qualname__
base_class.test
>>> y.test.__qualname__
child_class.test
A hacky way to get the name of the class is
x.test.__qualname__[:-len(x.test.__name__) - 1]
What is the fastest way to check if a class has a function defined?
Yes, use getattr()
to get the attribute, and callable()
to verify it is a method:
invert_op = getattr(self, "invert_op", None)
if callable(invert_op):
invert_op(self.path.parent_op)
Note that getattr()
normally throws exception when the attribute doesn't exist. However, if you specify a default value (None
, in this case), it will return that instead.
Check if method defined on mixee class?
I come with another answer to your post, now using prepend
instead of include
(only for ruby 2.x). The first is including at the top of the ancestry chain, since the second goes after the class.
Let see how it works at the irb console:
~/rails/learn/ruby (main) > module A
~/rails/learn/ruby (main) | def cancel!
~/rails/learn/ruby (main) | puts 'cancel from m:A'
~/rails/learn/ruby (main) | super if defined? super
~/rails/learn/ruby (main) | end
~/rails/learn/ruby (main) | end
=> :cancel!
~/rails/learn/ruby (main) > class C
~/rails/learn/ruby (main) | prepend A
~/rails/learn/ruby (main) | def cancel!
~/rails/learn/ruby (main) | puts 'cancel from c:C'
~/rails/learn/ruby (main) | end
~/rails/learn/ruby (main) | end
=> :cancel!
~/rails/learn/ruby (main) > C.ancestors
=> [
[0] #<Class:0x000000035421f0>::A,
[1] #<Class:0x000000035421f0>::C < Object,
[2] Object < BasicObject,
[3] PP::ObjectMixin,
[4] Kernel,
[5] BasicObject
]
~/rails/learn/ruby (main) > C.new.cancel!
cancel from m:A
cancel from c:C
=> nil
~/rails/learn/ruby (main) > class D
~/rails/learn/ruby (main) | include A
~/rails/learn/ruby (main) | def cancel!
~/rails/learn/ruby (main) | puts 'cancel from c:D'
~/rails/learn/ruby (main) | super if defined? super
~/rails/learn/ruby (main) | end
~/rails/learn/ruby (main) | end
=> :cancel!
~/rails/learn/ruby (main) > D.ancestors
=> [
[0] #<Class:0x000000035421f0>::D < Object,
[1] #<Class:0x000000035421f0>::A,
[2] Object < BasicObject,
[3] PP::ObjectMixin,
[4] Kernel,
[5] BasicObject
]
~/rails/learn/ruby (main) > D.new.cancel!
cancel from c:D
cancel from m:A
=> nil
I hope it helps with your issue.
Find class in which a method is defined
If you need this in Python 3.x, please see my other answer—the closure cell __class__
is all you need.
If you need to do this in CPython 2.6-2.7, RickyA's answer is close, but it doesn't work, because it relies on the fact that this method is not overriding any other method of the same name. Try adding a Foo.do_it
method in his answer, and it will print out Foo
, not SomeClass
The way to solve that is to find the method whose code object is identical to the current frame's code object:
def do_it(self):
mro = inspect.getmro(self.__class__)
method_code = inspect.currentframe().f_code
method_name = method_code.co_name
for base in reversed(mro):
try:
if getattr(base, method_name).func_code is method_code:
print(base.__name__)
break
except AttributeError:
pass
(Note that the AttributeError
could be raised either by base
not having something named do_it
, or by base
having something named do_it
that isn't a function, and therefore doesn't have a func_code
. But we don't care which; either way, base
is not the match we're looking for.)
This may work in other Python 2.6+ implementations. Python does not require frame objects to exist, and if they don't, inspect.currentframe()
will return None
. And I'm pretty sure it doesn't require code objects to exist either, which means func_code
could be None
.
Meanwhile, if you want to use this in both 2.7+ and 3.0+, change that func_code
to __code__
, but that will break compatibility with earlier 2.x.
If you need CPython 2.5 or earlier, you can just replace the inpsect
calls with the implementation-specific CPython attributes:
def do_it(self):
mro = self.__class__.mro()
method_code = sys._getframe().f_code
method_name = method_code.co_name
for base in reversed(mro):
try:
if getattr(base, method_name).func_code is method_code:
print(base.__name__)
break
except AttributeError:
pass
Note that this use of mro()
will not work on classic classes; if you really want to handle those (which you really shouldn't want to…), you'll have to write your own mro
function that just walks the hierarchy old-school… or just copy it from the 2.6 inspect
source.
This will only work in Python 2.x implementations that bend over backward to be CPython-compatible… but that includes at least PyPy. inspect
should be more portable, but then if an implementation is going to define frame
and code
objects with the same attributes as CPython's so it can support all of inspect
, there's not much good reason not to make them attributes and provide sys._getframe
in the first place…
How can I test if a method is defined in a Perl 6 class?
You should not be comparing types by name.
my \Foo = anon class Foo {}
my \Bar = anon class Foo {}
say Foo.^name eq Bar.^name; # True
say Foo eqv Bar; # False
In fact is
checks for object identity if you give it a type object as the second argument.
is Bar.^lookup( 'Str' ).package, Bar, 'Bar defines Str'
You could always add a subroutine to add clarity.
sub defines-method (
Mu:U $class,
Str:D $method,
Str:D $desc = "$class.^name() defines $method"
) {
is $class.^lookup( $method ).?package, $class, $desc
}
defines-method Foo, 'Str';
You could alias it to an operator
sub &infix:<defines-method> = &defines-method;
Bar defines-method 'Str';
(Note that I used .?package
in case .^lookup
doesn't return anything.)
.^lookup
gives you the Method object that will be called; so I don't know why you are talking about it giving you them in a different order when there is only one value returned. If there are multi methods it returns the proto method (possibly implicitly created).
If you want the individual multi methods you would call .candidates
on it.
(There is also .^find_method
, and off the top of my head I don't remember the difference)
I believe you are thinking of .can
which gives you the Method objects in the order they would be called if you used .*Str
or .+Str
, which is the same as the method resolution order. Which means it would only change if you change the inheritance tree.
> class Bar is Str { method Str { 'Hello' } }
> quietly .perl.say for Bar.+Str;
"Hello"
""
""
> .perl.say for Bar.new.+Str
"Hello"
""
"Bar<80122504>"
> quietly .(Bar).perl.say for Bar.can('Str')
"Hello"
""
""
> .(Bar.new).perl.say for Bar.can('Str')
"Hello"
""
"Bar<86744200>"
Related Topics
Should I Use Class Method or Instance Method, and Why
Regex with Named Capture Groups Getting All Matches in Ruby
How to Create Database from Schema.Rb Without Initializing Rails
Ruby - Bundle Install/Update Too Slow
Asserting That a Particular Exception Is Thrown in Cucumber
Runtime Changing Model with Mongodb/Mongoid
Carrierwave Crop Specific Version
Creating an Md5 Hash of a Number, String, Array, or Hash in Ruby
Carrierwave: Create the Same, Unique Filename for All Versioned Files
How to Monitor Uptime of 20 Websites (Ping or Http) in Node.Js/Ror
Difference Between Add_Dependency and Add_Runtime_Dependency
How to Make a Rake Task Run After All Other Tasks? (I.E. a Rake Afterbuild Task)
Ruby - Adding a Directory to $Load_Path - What Does It Do