I have two functions in my (first!) Python program that only differ by the class that must be instanciated.
def f(id):
c = ClassA(id)
...
return ...
def g(id):
c = ClassB(id)
...
return ...
To avoid repeated code, I would like to be able to write a single function that would somehow accept the class to instanciate as a parameter.
def f(id):
return f_helper(id, ... ClassA ...)
def g(id):
return f_helper(id, ... ClassB ...)
def f_helper(id, the_class):
c = ... the_class ... (id)
...
return ...
I'm pretty sure this is possible, but did not find how...
That works exactly as you have it (minus the ...s):
>>> class foo:
pass
>>> def make_it(cls):
return cls()
>>> make_it(foo)
<__main__.foo instance at 0x011D9B48>
This can be modified to take in/pass params to the class constructor as well if you like, but the idea is perfectly fine. Classes are first-class objects in Python.
You pretty much got it right, just drop the dots. Classes are first-class values, you can just refer to them, as to any object. f would be return f_helper(id, ClassA) and g would be return f_helper(id, ClassB).
You can pass a callable to a function; a class itself is a callable, the returned object being an instance of said class.
def f_helper(id, the_class):
c = the_class(id)
# ...
return # ...
Related
I have two classes which are responsible for some calculations. In first class I have calculateStatisticalFeatures static method which calculate come stuff and returns a DataFrame for me. In other class I would like to do almost the same but add one more calculation basing on the same new input data from second class. I found something like decorators but somehow I was not able to use it.
Method in first class:
#staticmethod
def calculateStatisticsFeatures(self, inputData) -> pd.DataFrame:
#some calculations
features = pd.DataFrame(np.array([[skewn, kurt, entropyVal, meanCalc]]), columns=['skewness', 'kurtosis','entropy', 'meanCalc'])
return features
I was trying to use decorator like this to extend my first class method in second class but I can't paste the data.
#firstClass.calculateStatisticalFeatures(self.inputData)
def TestDecor(self):
# new calculation
Is it somehow possible to add this calculations to second class? Thank you in advance :)
Maybe this is what you want?
>>> import functools
>>>
>>> class A():
... #staticmethod
... def test(func):
... #functools.wraps(func)
... def wrapper(*args, **kw):
... # features = pd.DataFrame(np.array([[skewn, kurt, entropyVal, meanCalc]]), columns=['skewness', 'kurtosis','entropy', 'meanCalc'])
... print(kw.get("inputData"))
... return func(*args, **kw)
... return wrapper
...
>>> class B(A):
... #A.test
... def testb(self, **kw):
... print('test')
...
>>>
>>> B().testb(inputData="inputData")
inputData
test
I removed the staticmethod and just inherited second class. I was not aware that in Python we can inherit from classes in one class.
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()
I have one parent class P and several child classes. The parent class contains the method doSomething(x) defined only as:
def doSomething(self, x):
pass
Now, some of P's subclasses may have implemented this method, and some have not. Is there any way I can check if doSomething(x) is going to do nothing but pass, at runtime (e.g. if it is implemented, execute it, if not, skip it)?
There is no need to do anything here other than just calling doMethod() on the instance. Calling a no-op method is not so costly that detecting when a child class has implemented an override is going to save you anything.
So your number 1 option is to just call the method, and don't worry about it being an empty method. That's what pass is for, to give you an easy parent class method that does nothing.
Next, you state
Parent class contains method doSomething(x)
You can use this to detect if you have that method still; the underlying function for the bound method is going to be the same object:
hook = instance.doSomething
if hook.__func__ is ParentClass.doSomething:
# they didn't override the method, so nothing needs to be done.
Again, I'm not sure why anyone would want to do that, because that test is not going to save you anything over just using instance.doSomething().
Next, a function that consists solely of the statement pass will be compiled to the same bytecode, always; it's the same bytecode as return None. Compare the bytecode if you must know if a function is empty:
_RETURN_NONE = (lambda: None).__code__.co_code
def is_pass(f):
return f.__code__.co_code == _RETURN_NONE
This can be applied to any function or method that, in essence, only ever returns None and does nothing else.
Demo:
>>> class P:
... def doSomething(self, x):
... pass
...
>>> class Child1(P):
... def doSomething(self, x):
... print("We are doing something with {!r}!".format(x))
...
>>> class Child2(P):
... pass
...
>>> instance1 = Child1()
>>> instance2 = Child2()
>>> instance1.doSomething(42)
We are doing something with 42!
>>> instance2.doSomething(42)
>>> instance1.doSomething.__func__ is P.doSomething
False
>>> instance2.doSomething.__func__ is P.doSomething
True
>>> is_pass(instance1.doSomething)
False
>>> is_pass(instance2.doSomething)
True
>>> def unrelated_function():
... return 42
...
>>> def another_unrelated_function():
... pass
...
>>> is_pass(unrelated_function)
False
>>> is_pass(another_unrelated_function)
True
Note how is_pass() works on any function that uses pass.
Since your parent method is defined as
def doSomething(x):
pass
It does nothing - it is cheaper to just call it instead of verifying if it has been overriden or not. It will be automatically "skipped" because it does nothing in first place.
That said, if you really want to test for it, you can do something like this
if type(some_instance).doSomething is ParentClass.doSomething:
print('Not overriden')
else:
print('Function has been overriden, call it'):
some_instance.doSomething()
In the book learning python 5th edition (o'reilly Mark Lutz)page912)
class PrivateExc(Exception): pass # More on exceptions in Part VII
class Privacy:
def __setattr__(self, attrname, value): # On self.attrname = value
if attrname in self.privates:
raise PrivateExc(attrname, self) # Make, raise user-define except
else:
self.__dict__[attrname] = value # Avoid loops by using dict key
class Test1(Privacy):
privates = ['age']
class Test2(Privacy):
privates = ['name', 'pay']
def __init__(self):
self.__dict__['name'] = 'Tom' # To do better, see Chapter 39!
Maybe it is wrong in the 5th lineraise PrivateExc(attrname, self) ,
the self argument will be set as position 1st.
Will be the line changed into raise PrivateExc(self,attrname)?Why not?
Actually it doesn't matter.
Subclassing from Exception without any additional constructor doesn't restrict what you can pass as arguments to the exception class. And you can pass them in any order you want.
The arguments passed to the PrivateExc class just get stored in the instance as the instance attribute .args
Example:
>>> class MyError(Exception):
... """MyError"""
...
>>> e = MyError("foo", "bar")
>>> e.args
('foo', 'bar')
>>> e
MyError('foo', 'bar')
What this basically means in the book you're reading is;
If you were to catch the exception PrivateExc you'd do something like this:
try:
...
except PrivateExc as error:
attrname, obj = error.args
...
When you are calling a method like this:
#!/bin/python
myinstance.some_method(a,b,c)
... then this is dispatched to some_method as: some_method(myinstance, a, b, c)
The instance through which the method was invoked is passed as your first argument. This is completely different than C++ and Java ... which use an implicit "this" reference ... a pointer valid from within your method's scope but not passed to it as an argument.
I hope that answers your question, thought the code example does nothing to clarify what you're attempting to do.
I think you are just confused about parameters in function definition and function calling.
In a class, a method(instance method) has a non-optional parameter in the first position, usually named self, in the definition, like this:
class Foo:
def foo(self, another_param):
pass
And the self references the instance that you call foo function with. If you have code like this:
f=Foo()
f.foo("test")
self references the f and another_param references the "test" string in the above code.
And then in the foo function, you can use self just like other parameters.
Suppose you have a Print function like this:
def Print(x):
print "Param:", x
Then you can make you Foo class like this:
class Foo:
def foo(self, another_param):
Print(another_param) # I think this will not confuse you
Or this:
class Foo:
def foo(self, another_param):
Print(self) # Now, you may understand this, self is just a param in function calling, like another_param
And now, change the Print function to PrivateExc(you can think it a function to create a PrivateExc instance here), you may understand it either.
Hope these examples can help you understand you question.
I've been stuck on this for a long time (like literally weeks), I've completed everything else in the code but this. I've also researched a lot but can't get anywhere near the solution. The only reason I waited a week to come here is because I wanted to solve this myself, but now, I give up!
Now, suppose I have the following code:
class test:
def meth1(self, obj):
self.hello = {}
return self.hello.obj()
def meth2(self):
test.meth1(self, 'keys')
Now, when I create an instance and try to call the method meth2like this:
x = test()
x.meth2()
It gives me an error for obvious reasons. How can I get it do what I want-- pass an argument to a function and use that argument as an object of another object?
Looks like you want getattr():
def meth1(self, obj):
self.hello = {}
return getattr(self.hello, obj)()
getattr(a, b) is equivalent to a.b (where b in the second case is the string that the b of the first case holds). In this case, a is self.hello and b is obj. From your snippet, it looks like you want to call the obj attribute as opposed to returning it directly, which is why we have a () at the end.
>>> class test:
... def meth1(self, obj):
... self.hello = {}
... return getattr(self.hello, obj)()
... def meth2(self):
... return test.meth1(self, 'keys')
...
>>> x = test()
>>> x.meth2()
[]