Default variable referencing own class in python - python

I'm trying to write something like:
class MyClass(object):
#staticmethod
def test(x, y, z=None):
if not z:
z = external_function(MyClass)
Is it possible in python to rewrite it to something like:
class MyClass(object):
#staticmethod
def test(x, y, z=external_function(MyClass)):
pass
(The second code does not work as it is referencing MyClass which is not defined at this point)

It is not possible to rewrite the code that way. The closest you can do is something like:
class MyClass:
pass
def test(x, y, z=external_function(MyClass):
pass
MyClass.test = staticmethod(test)
del test
Note that this assumes Python 3; in Python 2, you may need to fiddle around with the new module. But though this is possible, the intention of the code is very non-obvious. It is better to stick to if z is None, or to refactor your code to not need this.

It's not possible, since whatever is in the argument definition of any method, be it a static method or a normal method, is parsed and executed at class creation time, before the class object that you try to use has been created. Defaults are also evaluated at this time, as the code below demonstrates.
def say_hi():
print "Getting default value"
class MyClass(object):
print "Creating class"
#staticmethod
def test(a=say_hi()):
print "test called"
MyClass.test()
MyClass.test()
Output:
Creating class
Getting default value
test called
test called

Related

How can I search a python script for use of a class method before running?

I would like to be able to scan a python script for uses of a class method before running the script itself. For example, given the following script, get all uses of the "foo" method for class "A" and the arguments passed to the method
class A():
def foo(self, val):
return val + 1
class B():
def foo(self, val):
return val - 1
a = A()
b = B()
a_val = a.foo(1)
b_val = b.foo(1)
This is an overly simple example, but the goal here is to use something more than regex to search for a foo() pattern so that items like b.foo(1) are not returned. I've looked at the ast and symtable modules, but they don't seem to have the functionality I'm after. I realize this may be a difficult/impossible problem due to python being an interpreted language, but it seems like someone else had to have had this problem before
This cannot be done with static code analysis because owner of the method is determined in runtime. For example I could add on to your example:
b = a
b.foo(0)
Here b.foo(0) is in fact an invocation of the class A's foo method. And static code analysis can't know this, because this depends on runtime.
Which means that what you're asking for reduces to the halting problem. There is no way to do what you're asking for with a guaranteed (or even probabilistically more accurate than chance) correct answer.
This sounds like an XY Problem, but alas. You can use the inspect module to inspect classes and functions on runtime:
import inspect
class Foo:
def bar(self, val):
return val + 1
def baz(self, number):
return number
functions = inspect.getmembers(Foo(), predicate=inspect.ismethod)
for name, function in functions:
sig = inspect.signature(function)
print(f'Function "{name}" has a params {sig}')
Outputs:
Function "bar" has a params (val)
Function "baz" has a params (number)

Reuse docstring from a method in a class in python

So I have a method in a class and I have another separate function (i.e., outside the class) that want to reuse the docstring of that method. I tried something like __doc__ = <Class Name>.<Method Name>.__doc__ under the separate function but that does not work. Thus, is there a way to do so?
__doc__ needs to be assigned as a property of the new function, like this:
class C:
def foo(self):
'docstring'
def bar():
pass
bar.__doc__ = C.foo.__doc__ # NOT __doc__ = ...
assert bar.__doc__ == 'docstring'
Even this is a case, I'd use a manual copy of a docstring. Class or function could be moved around or separated to different projects. Moreso, reading a function below goesn't give me any idea what it's doing.
Please, consult with PEP-8, PEP-257 and PEP-20 for more information why this behavior is discoraged.
def myfunc():
...
myfunc.__doc__ = other_obj.__doc__

Refer to parent's class method without parent's class name

I hope you are doing great. This questions is really about getting rid of the reference to base class.
Basically I want to collect all methods of a child class methods at the class level instead of the instance level, using a parent classmethod. However, I was told that the base class name is really long.
The first piece works but is really annoying because of the long name. Even in the clean version I have to do A.eat everytime.
I promise people won't define another method "eat" in any child like B. Can I actually get rid of the base class reference so that I can use #eat?
class IDontWantToDoThisButNameHasToBeThisLong(object):
a = []
#classmethod
def eat(cls, func):
cls.a.append(func)
class B(IDontWantToDoThisButNameHasToBeThisLong):
#IDontWantToDoThisButNameHasToBeThisLong.eat
def apple( self, x ):
print x
IDontWantToDoThisButNameHasToBeThisLong.eat( lambda x: x+1 )
x = B()
IDontWantToDoThisButNameHasToBeThisLong.a[0](x, 1)
print IDontWantToDoThisButNameHasToBeThisLong.a[1](1)
Clean version:
class A(object):
a = []
#classmethod
def eat(cls, func):
cls.a.append(func)
class B(A):
#A.eat
def apple( self, x ):
print x
A.eat( lambda x: x+1 )
x = B()
A.a[0](x, 1)
print A.a[1](1)
Sincerely,
The class IDontWantToDoThisButNameHasToBeThisLong is really just an object. In python, most thingsa are an object, so we can assign just about anything to a variable, including a class.
What you could do here is something like the following
class IDontWantToDoThisButNameHasToBeThisLong(object):
a = []
#classmethod
def eat(cls, func):
cls.a.append(func)
A = IDontWantToDoThisButNameHasToBeThisLong
class B(A):
#A.eat
def apple( self, x ):
print x
A.eat( lambda x: x+1 )
x = B()
IDontWantToDoThisButNameHasToBeThisLong.a[0](x, 1)
A.a[0](x, 1)
print IDontWantToDoThisButNameHasToBeThisLong.a[1](1)
There's no perfect solution for what you want to do, but there are a few different approaches that might be good enough.
To start with the simplest, you could give your long class a shorter name before using class method in the child classes:
class IDontWantToDoThisButNameHasToBeThisLong(object):
...
A = IDontWantToDoThisButNameHasToBeThisLong
# later code can use A.whatever()
Another option would be to move the decorator out of the class with the long name, so that your later code would refer to it directly as a global, rather than a class method. This would require it to be slightly redesigned (which might break things if you ever intend for there to be multiple different a lists that are accessed through the same decorator called via different classes):
class IDontWantToDoThisButNameHasToBeThisLong(object):
a = []
def eat(func):
IDontWantToDoThisButNameHasToBeThisLong.a.append(func) # only need to use the name once
return func # I suspect you want this too (a decorator should return a callable)
# later code can use #eat as a decorator, without referring to the long class name
A hybrid of those two approaches might be to leave the existing class method definition intact, but to create another global name for the bound method that's easier to access:
eat = IDontWantToDoThisButNameHasToBeThisLong.eat
A final possible approach would be to use fancier programming with metaclasses, or (if you're using Python 3.6) __init_subclass__ or similar, to achieve the goal you have in mind without needing to use a class method as a decorator. I'm not going to include code for that, since the best way to do this probably depends on more details of your design than what you've show in your example.

Dealing with class inheritance in python

Can someone explain why I'm getting the error:
global name 'helloWorld' is not defined
when executing the following:
class A:
def helloWorld():
print 'hello world'
class B(A):
def displayHelloWorld(self):
helloWorld()
class Main:
def main:
b = B()
b.displayHelloWorld()
I'm used to java where class B would obviously have a copy of class A's method "helloWorld" and thus this code would run fine when executing main. This however appears to think class B doesn't have any method called "helloWorld"
Missing the self before the helloWorld(). The self keyword means that this an instance function or variable. When class B inherits class A, all the functions in class A can now be accessed with the self.classAfunction() as if they were implemented in class B.
class A():
def helloWorld(self): # <= missing a self here too
print 'hello world'
class B(A):
def displayHelloWorld(self):
self.helloWorld()
class Main():
def main(self):
b = B()
b.displayHelloWorld()
You need to indicate that the method is from that class (self.):
class B(A):
def displayHelloWorld(self):
self.helloWorld()
Python differs in this from Java. You have to specify this explicitly in Python whereas Java accepts implicitly as well.
I don't know what is the version of python used in this example but it seems that syntax looks like python3. (except print statement which looks like python2.x)
Lets suppose that this is python3
I would say that helloWorld is class method of class A and It should be called as class attribute. As soon as this function is in class namespace It can be accessed outside this class only using owner class.
A.helloWorld()
or
B.helloWorld()
or
self.__class__.helloWorld()
You can't call it as bound method in this case because self argument will be passed and as soon as your function doesn't expect it it will fail.
there is possibility that helloWorld is method of A and self parameter is just missed
in this case this method can be called as follow:
self.helloWorld()
or
A.helloWorld(self)

Understanding Python classes

I am trying to learn about python classes, but I don't understand something. Why does this simple example not return "6"? It returns <function TEST.f at 0x00000000029ED378> instead. I have also tried TEST.f() but then he tells me that the argument self is missing. Shouldn't self only exist inside the class and python fills it in automatically?
#! coding=utf-8
class TEST:
def __init__(self):
self.x = 6
def f(self):
return(self.x)
print(TEST.f)
You need to create an instance of the class.
test = TEST()
print test.x()
But you also need to call the method and the variable different things.
class TEST:
def __init__(self):
self._x = 6
def x(self):
return(self._x)
Otherwise you're redefining the value of x.
There are two ways to make your code work:
As aychedee said, create a TEST instance, and invoke method f from
the instance:
>>> TEST().f()
6
Another way is to create a TEST instance t, and pass it the
method f:
>>> t = TEST()
>>> TEST.f(t)
6
Remember the self argument of your method f? Basically, this is to explicitly pass the TEST instance t to method f.
You need to create an instance just as shown.
test = Test()
test.f()

Categories

Resources