Getting NameError when calling function in constructor - python

I ran the code below, by calling the function in the constructor
First --
>>> class PrintName:
... def __init__(self, value):
... self._value = value
... printName(self._value)
... def printName(self, value):
... for c in value:
... print c
...
>>> o = PrintName('Chaitanya')
C
h
a
i
t
a
n
y
a
Once again I run this and I get this
>>> class PrintName:
... def __init__(self, value):
... self._value = value
... printName(self._value)
... def printName(self, value):
... for c in value:
... print c
...
>>> o = PrintName('Hello')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 4, in __init__
NameError: global name 'printName' is not defined
Can I not call a function in the constructor? and whay a deviation in the execution of similar code?
Note: I forgot to call a function local to the class, by using self (ex: self.printName()). Apologize for the post.

You need to call self.printName since your function is a method belonging to the PrintName class.
Or, since your printname function doesn't need to rely on object state, you could just make it a module level function.
class PrintName:
def __init__(self, value):
self._value = value
printName(self._value)
def printName(value):
for c in value:
print c

Instead of
printName(self._value)
you wanted
self.printName(self._value)
It probably worked the first time because you had another function printName in a parent scope.

What you want is self.printName(self._value) in __init__, not just printName(self._value).

I know this is an old question, but I just wanted to add that you can also call the function using the Class name and passing self as the first argument.
Not sure why you'd want to though, as I think it might make things less clear.
class PrintName:
def __init__(self, value):
self._value = value
PrintName.printName(self, self._value)
def printName(self, value):
for c in value:
print(c)
See Chapter 9 of the python manuals for more info:
9.3.4. Method Objects
Actually, you may have guessed the answer: the special thing about methods is that the object is passed as the first argument of the function. In our example, the call x.f() is exactly equivalent to MyClass.f(x). In general, calling a method with a list of n arguments is equivalent to calling the corresponding function with an argument list that is created by inserting the method’s object before the first argument.

Related

Why calling a function inside a Python class __init__ can be both Attribute and Method?

I am quite confused with the method and attribute of a Python class. Suppose we have a Python class like this:
# case 1
class Person:
def __init__(self, first, last):
self.first = first
self.last = last
self.fun()
def fun(self):
value = self.first + '---' + self.last
self.fun = value
return value
person_1 = Person('A', 'B')
person_1.fun
---> "A---B"
As we can see, in case_1 we initialize an instance person_1. And we can get the result we want by calling fun as an attribute. However, if we change our code to the following, fun becomes a method instead.(case_2)
# case 2
class Person:
def __init__(self, first, last):
self.first = first
self.last = last
self.fun()
def fun(self):
value = self.first + '---' + self.last
return value
person_1 = Person('A', 'B')
person_1.fun
---> <bound method Person.fun of <__main__.Person object at 0x7fd4f79168d0>>
We still contain the init process in the class. But now fun becomes a method but not an attribute. (case_2)
If we remove the self.fun() in init but keep the self.fun = value, it is still a method. (case_3)
# case 3
class Person:
def __init__(self, first, last):
self.first = first
self.last = last
def fun(self):
value = self.first + '---' + self.last
self.fun = value
return value
person_1 = Person('A', 'B')
person_1.fun
---> <bound method Person.fun of <__main__.Person object at 0x7fd4f797f390>>
Would you mind giving me some instructions about why this happens? And what is the proper way to use the function as an attribute inside a Python Class? Thank you so much in advance!
In case 1, your constructor calls fun() which has a line inside of it to overwrite itself with an attribute value. This is confusing and not a good thing to do because it is confusing.
In case 2, your fun method does not include the line to overwrite itself so it doesn't get overwritten.
In case 3, you never actually call your fun method so it never has a chance to overwrite itself. If you called it with person_1.fun() i.e. with parentheses, then it would execute and overwrite itself and from that point on, person_1.fun would be an attribute value.
Remember that in python, a function/method ONLY executes if it is called with parentheses. If you don't express it with parentheses, then the result of evaluation is not the output of the function, but instead the expression produces a reference to the function itself, which can be put in another variable or in a data structure and called later.
To illustrate this:
>>> def my_func():
... print('got called')
... return 42
...
>>> x = my_func #no parentheses, x becomes an alias to my_func
>>> y = my_func() #parentheses means actually execute
got called
>>> y
42
>>> x
<function my_func at 0x765e8afdc0>
>>> x() #x is a reference to my_func and can be called itself
got called
42
>>>
Aha, I think I figure it out!
In case 1, we simply run the function fun() when we init the instance. And because it defines the attribute self.fun = value inside the fun(), hence fun can be used as an attribute. (It cannot be used as the method anymore, because it has been replaced as an attribute.)
In case 2, we only call and run this function. But fun is not been defined as an attribute inside the class. That's why it remains as a method.
In case 3, fun is a method, but in this method, we define an attribute fun. Hence we can first init an instance, then run the function fun. After that, the attribute fun is added to this instance, and then we can call it as person_1.fun.

How to use a function outside a class as a property inside a class?

I'm having some problems. How we can define a function outside of a function that can be used in a class property? Also, how we can insert the self parameter into the function signature? I would like to visualize it like this:
>>> def a(self, x): #I thought maybe class will give "self" to this property function
... print(self)
...
>>> class aa:
... def __init__(self):
... pass
... #a
... def p():
... print('in it')
...
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 4, in aa
TypeError: a() missing 1 required positional argument: 'x'
I want to define a function outside but to use inside of a class. Like a class's method as a property. How can I do this?
It's not really clear what you want your out-of-class function to do. There are a bunch of possibilities, but you may not know the terminology yet to describe it to us.
Here's the three I think are most likely:
You may want your function to be a decorator. That means you can apply it to a method with #decorator syntax to other functions, including methods in a class.
For this to work, your function needs to be written to accept a function object as its only argument. Whatever it returns is what will replace the function or method it was being called on, so usually you want to return a callable, but you could instead return a descriptor like property does. Try something like this:
def decorator(func):
def wrapper(self, *args, **kwargs):
print("in the wrapper")
result = func(self, *args, **kwargs)
print("wrapper is done")
return result
return wrapper
class Foo:
#decorator
def foo(self, x):
print("in foo(), x is", x)
f = Foo()
f.foo(1) # prints three messages
When you call the foo method, you're actually going to be calling the wrapper method that the decorator returned after it was applied to the original method (func). Because of how we wrote the wrapper, it will call func so the original method prints out its message too.
You may want to use property (a descriptor type) to call your out-of-class function. This is a less common way of using property than applying it as a decorator on a method, but it's not impossible. You could even have two different functions, one to be called when requesting the attribute, the other than will be called when setting it (but I'll demonstrate with just the getter):
def getter(obj):
print("in the getter")
return 1
class Foo2:
foo = property(getter)
f2 = Foo2()
print(f2.foo) # prints a message from the getter function first, then prints 1
Note that you can't use #decorator syntax when building a property this way. That is only legal syntax immediately before a function definition, and we're not defining any functions that way inside our class.
You may just want to copy a function defined outside of the class into it, without any decorator or property nonsense. This is the easiest one to do, it's just a simple assignment:
def func(self, x):
print("x is", x)
class Foo3:
method = func # just assign the global to a name in the class body
func = func # you can even use the same name if you don't mind confusing people
f3 = Foo3()
f3.method(1)
f3.func(2)
If you want to create a property that uses a function defined outside your class, it would be something like this:
def myfunc(self):
return self._p
class Foo:
def __init__(self, p):
self._p = p
p = property(myfunc)
f = Foo("Alpha")
f.p # gives "Alpha"
property accepts a function as its (first) argument. The function should have self as a parameter, and should return the value that you want the property to evaluate to.

lambda function in class header

I am trying to create nan value for integer. the design i am thinking about is the following.
I need to create and isnan lambda function in the class definition header but it returns an error
import numpy as np
class Integer(object):
type = int
nan = -1
isnan = lambda val: val==-1
def __new__(cls, value):
return cls.type(value)
class Float(object):
type = float
isnan = lambda val: np.isnan(val)
def __new__(cls, value):
return cls.type(value)
but it returns an error
>> Integer.isnan(1)
>> Traceback (most recent call last):
>> File "<stdin>", line 1, in <module>
>>TypeError: unbound method <lambda>() must be called with Integer instance as first argument (got int instance instead)
The issue is that your isnan functions are being treated as instance methods by Python. Even though you're using them "unbound", Python 2 still does a type check to ensure that the first argument to a method is an instance of the class (e.g. self). In Python 3, unbound methods have been discarded, and your code would work just fine.
You can work around this by passing the lambda function through staticmethod:
isnan = staticmethod(lambda val: val == -1)
Or you could use a regular function definition, with staticmethod as a decorator:
#staticmethod
def isnan(value):
return val == -1
Note that if you made your classes inherit from their type value, you could call isnan as an actual instance method:
class Integer(int):
# no __new__ needed
def isnan(self):
return self == -1
This would let you call Integer(5).isnan(), rather than what you do in your current code.
One final suggestion: Don't use type as a variable name, since it is already the name of the built-in type class. It's not as bad using it as a class attribute as it would be as a variable (where it would shadow the built-in), but it can still be confusing.
You need to make it a static method. Two choices:
class Integer(object):
type = int
nan = -1
#staticmethod
def isnan(v):
return v == -1
isnan_lambda = staticmethod(lambda v: v == -1)
def __new__(cls, value):
return cls.type(value)
print Integer.isnan(5)
print Integer.isnan(5)

Issue with monkeypatching methods and references

I was wondering if anyone could explain and offer a solution to this issue:
$ cat object-override-methods.py
class A:
def foo(self):
return 1
class B:
def foo(self):
return 1
for klass in A, B:
orig_foo = klass.foo
def foo(self):
return orig_foo(self) * 2
klass.foo = foo
A().foo()
B().foo()
$ python object-override-methods.py
Traceback (most recent call last):
File "object-override-methods.py", line 15, in <module>
A().foo()
File "object-override-methods.py", line 12, in foo
return orig_foo(self) * 2
TypeError: unbound method foo() must be called with B instance as first argument (got A instance instead)
Thanks in advance.
orig_foo is a global variable which changes value with each pass through the loop. After the loop is done, orig_foo refers to B.foo.
The inner functions foo (one or each pass through the loop) both use the global value for orig_foo when they are called. So they both call B.foo(self).
When calling an "unbound method" like orig_foo, Python2 checks that the first argument is an instance of the appropriate class. A().foo() does not pass this check. (Interestingly, this check was removed in Python3, so there would be no TypeError raised, and this bug may become harder to find.)
To fix this, you must bind the value of orig_foo to the appropriate klass.
You can do that by making orig_foo a local variable of foo. One way to do that is to make orig_foo an argument of foo with a default value. Python binds default values at the time a function is defined. So orig_foo=orig_foo binds the local variable orig_foo to the current value of the klass.foo:
for klass in A, B:
orig_foo = klass.foo
def foo(self, orig_foo=orig_foo):
return orig_foo(self) * 2
klass.foo = foo
Because orig_foo is defined at global scope, you're trampling on its value each time round the loop. That trampled value is then shared by each of your new foo methods.
A simple fix is to move the code into a function, like this:
def rebind_foo(klass):
orig_foo = klass.foo
def foo(self):
return orig_foo(self) * 2
klass.foo = foo
for klass in A, B:
rebind_foo(klass)
That ensures that each new foo method gets its own value of orig_foo.

Setting Property via a String

I'm trying to set a Python class property outside of the class via the setattr(self, item, value) function.
class MyClass:
def getMyProperty(self):
return self.__my_property
def setMyProperty(self, value):
if value is None:
value = ''
self.__my_property = value
my_property = property( getMyProperty, setMyProperty )
And in another script, I create an instance and want to specify the property and let the property mutator handle the simple validation.
myClass = MyClass()
new_value = None
# notice the property in quotes
setattr(myClass, 'my_property', new_value)
The problem is that it doesn't appear to be calling the setMyProperty(self, value) mutator. For a quick test to verify that it doesn't get called, I change the mutator to:
def setMyProperty(self, value):
raise ValueError('WTF! Why are you not being called?')
if value is None:
value = ''
self.__my_property = value
I'm fairly new to Python, and perhaps there's another way to do what I'm trying to do, but can someone explain why the mutator isn't being called when setattr(self, item, value) is called?
Is there another way to set a property via a string? I need the validation inside the mutator to be executed when setting the property value.
Works for me:
>>> class MyClass(object):
... def get(self): return 10
... def setprop(self, val): raise ValueError("hax%s"%str(val))
... prop = property(get, setprop)
...
>>> i = MyClass()
>>> i.prop =4
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in setprop
ValueError: hax4
>>> i.prop
10
>>> setattr(i, 'prop', 12)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in setprop
ValueError: hax12
The code you pasted seems to do the same as mine, except that my class inherits from object, but that's cause I'm running Python 2.6 and I thought that in 2.7 all classes automatically inherit from object. Try that, though, and see if it helps.
To make it even clearer: try just doing myClass.my_property = 4. Does that raise an exception? If not then it's an issue with inheriting from object - properties only work for new-style classes, i.e. classes that inherit from object.

Categories

Resources