How to get class name when there is attribute attached? [duplicate] - python

This question already has answers here:
Get class that defined method
(8 answers)
Closed 8 years ago.
For example,
I want to return 'ClassName' from the following:
ClassName().MethodName
When I try:
ClassName().MethodName.__class__.__name__
>>instancemethod
or when I try:
ClassName().MethodName.__name__
>>MethodName
Perhaps this isn't possible, so would there be a way to turn ClassName().MethodName to ClassName(), so I could then run this, which is what I want:
ClassName().__class__.__name__
>> ClassName

The information you want is in the im_class attribute of the bound method object:
>>> class Foo():
... def bar():
... pass
...
>>> m = Foo().bar
>>> m.im_class
<class __main__.Foo at 0x1073bda78>

Like so:
class Foo(object):
def MethodName():
pass
print type(Foo()).__name__
# Foo
Or,
foo=Foo()
print type(foo).__name__
# Foo
(Note -- that only works on new style classes, not legacy classes. It obviously only works if you know what to call to instantiate the class)
If all you have is reference to a method, you can use inspect (Thx Alex Martelli):
import inspect
def get_class_from_method(meth):
for cls in inspect.getmro(meth.im_class):
if meth.__name__ in cls.__dict__: return cls
return None
>>> mn=Foo().MethodName
>>> get_class_from_method(mn).__name__
Foo
Or, for a user defined method, you can do:
>>> mn.im_class.__name__
Foo

Related

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()

How can we override the constructor while still using the `class` keyword? [duplicate]

This question already has an answer here:
__metaclass__ in Python 3
(1 answer)
Closed 3 years ago.
Two notable ways to create a class are shown below:
class Klass:
pass
Klass = type("Klass", tuple(), dict())
I would like to override the constructor (__call__) while still using the class keyword instead of doing something else, like directly calling type. I really do want to override (__call__), not __init__
My failed attempts are shown below:
Attempt 1
class Foo:
#classmethod
def __call__(*args):
print("arr har")
return super(type(args[0]), args[0]).__call__(*args)
instance = Foo()
# did not print "arr har"
Attempt 2
class BarMeta(type):
def __call__(*args):
print("hello world")
return super(type(args[0]), args[0]).__call__(*args[1:])
Attempt 2A
class Bar:
__metaclass__ = BarMeta
instance = Bar()
# did not print "hello world"
Attempt 2B
Baz = BarMeta("Baz", tuple(), dict())
instance = Baz()
# Did print "hello world," but we weren't able to use the `class` keyword to create `Baz`
All credit does to Aran-Fey, who posted the answer as a comment, instead of as an answer:
class BarMeta(type):
def __call__(*args):
print("hello world")
return super(type(args[0]), args[0]).__call__(*args[1:])
class Bar(metaclass=BarMeta):
pass
instance = Bar()

Creating properties dynamically that point to an attribute's properties [duplicate]

This question already has answers here:
What do lambda function closures capture?
(7 answers)
Closed 6 months ago.
I want to make properties from an attribute of my class accessible directly through the instance of the class (without inheriting from it). So basically if I have:
class A:
#property
def foo(self):
print("foo")
#property
def bar(self):
print("bar")
class B:
def __init__(self):
self._a = A()
Instead of doing b._a.bar I want to be able to do b.bar. Based on this answer here, I tried the following in class B:
class B:
def __init__(self):
self._a = A()
attrs = [attr for attr in dir(self._a)
if not callable(self._a.__getattribute__(attr))
and not attr.startswith("__")]
for attr in attrs:
setattr(self.__class__, attr,
property(lambda s: s._a.__getattribute__(attr)))
But when instantiating and testing it out, I get one of those weird python moments:
>>> b = B()
foo
bar
>>> b.foo
bar
>>> b.bar
bar
Why are both 'foo' and 'bar' printed out when creating the instance ?
How does the 'foo' property point to the same getter as 'bar' ?
bar and foo are printed when you create the instance because doing _a.__getattribute__("foo") and _a.foo will both call the property object to get a value.
Both of the attributes you set up in B use lambdas to get the correct property from A. This is a common mistake when calling lambdas. Because the attr value is inherited from the outside scope, it isn't frozen when the lambda is evaluated. Instead, it is simply the same attr reference as the enclosing scope's attr, and changes accordingly. So all of your lambdas will have the same attr value.
You can define a B.__getattr__ method instead. This method is called when ordinary attribute lookup fails.
class B:
def __init__(self):
self._a = A()
def __getattr__(self, name):
return getattr(self._a, name)
b = B()
b.bar # bar
b.foo # foo

Unbound method in Python [duplicate]

This question already has answers here:
Python newbie having a problem using classes
(2 answers)
Closed 7 years ago.
In this link while explaining classes, for the following sample class
class MyClass:
"""A simple example class"""
i = 12345
def f(self):
return 'hello world'
it is mentioned that
then MyClass.i and MyClass.f are valid attribute references, returning an integer and a function object, respectively
but when I try to print MyClass.f it gives me a error <unbound method MyClass.f>.
So what does MyClass.f returning function object really mean in this context.
It's telling you that the method isn't bound to any instance.
If you did this:
myinstance = MyClass()
myinstance.f() # "hello world"
It would work, or, you can make it static:
class MyClass
#staticmethod
def f()
print "hello world"
MyClass.f()
Would also work
Instance it:
>>> your_class = MyClass()
>>> your_class.f()
'hello world'
It's bound when you instance it:
>>> your_class.f
<bound method MyClass.f of <__main__.MyClass instance at 0x1244ef0>>
It is an instance method. You should use classmethod or staticmethod, like this:
>>> class A():
... #staticmethod
... def f(*args):
... return "hello"
...
>>> A.f
<function f at 0xb744541c>
>>> print A.f
<function f at 0xb744541c>
>>> print A.f()
hello

Instance attribute as default argument [duplicate]

This question already has answers here:
How to pass a default argument value of an instance member to a method?
(6 answers)
Closed 4 years ago.
I use Python 3 and I have small problem with kwargs. Is it possible to use instance attributes as a default argument value? I mean something like this:
class foo:
def __init__(self, a,b):
self.a = a
self.b = b
def setNewA(self, a=self.a):
print(a)
But I've got an error:
NameError: name 'self' is not defined
If I use class name I've got:
AttributeError: type object 'foo' has no attribute 'a'
I know that the other method is to use something like this:
def setNewA(self, a=None):
a = a or self.a
print(a)
But maybe there is some way to do it?
Not sure if this fits your use-case, but how about this?
>>> class foo:
... b = 1
...
... def setNewA(self, a=b):
... print(a)
>>>
>>> f = foo()
>>> f.setNewA()
1
>>> f.setNewA(2)
2

Categories