Python error in class - python

class exampleclass:
def meth01(self, name):
print self.name
obj1 = exampleclass()
obj1.meth01("James")
error message:
Traceback (most recent call last): File "<pyshell#5>", line 1, in
<module>
obj1.meth01("James") File "<pyshell#3>", line 3, in meth01
print self.name AttributeError: exampleclass instance has no attribute 'name'
So what have I done wrong to produce this error, the name is in the parameters And I tried to set what name was so that it could print?

You are printing self.name. This is a member variable of the class, not the input variable of the function meth01. In your function name refers to the input, and self.name refers to a member variable of the class. But you are not setting it.
Do this instead:
class ExampleClass:
def meth01(self, name):
print( name )
To understand what is going on, expand it like this:
class ExampleClass:
def setName(self, name):
self.name = name
def meth01(self, name):
print('Input variable name: ', name)
print('Member variable name: ', self.name)
ec = ExampleClass()
ec.meth01('John') # This line will fail because ec.name hasn't been set yet.
ec.setName('Jane')
ec.meth01('John')
# This will print:
#('Input variable name: ', 'John')
#('Member variable name: ', 'Jane')

You need to make your __init__ method
class exampleclass:
def __init__(self, name):
self.name = name

A variable name is part of the parameter list, but there's no name member value in the example class object itself (yet).
Think of what your code does, step by step. First it instantiates a new exampleclass object.
You then call obj1.meth01("James"). meth01 is passed with the values self = obj1 and name="James"
meth01 then tries to find a value stored as obj1.name, but none exists, since in this case name is local to the method meth01 and is not part of the object obj01 itself.

You need to make a constructor that is used to initialise an object.
Make your __init__ method like this.
class exampleclass:
def __init__(self, name):
self.name = name
NOTE: Declare the constructor as mentioned only.
You can understand self like this:
Self stores the address of the object from which the constructor or method is called.
So self.name=name would result in assigning the data member of the object from which it is called to the variable name which is passed as parameter to the constructor.

Related

How can I make the OOP code print my classes objects name?

I've tried to make an OOP based program in python. I gave it an object to work with and tried to make it print the name, but its not working.
class human:
def __init__(self, name):
print("this is a human")
def name(self, name):
print("this is {}".format(bob.name))
bob = human("bob")
Anyone know what the problem could be?
Beyond the answers you already received (which solve your problem), I'd suggest not having a method that prints the name. Rather, you should have a __str___ dunder method that defines the object's behavior when an instance is printed.
class human:
def __init__(self, name):
self.name = name
def __str__(self):
return self.name
person = human("bob")
print(person)
'bob'
You can also define the object's behavior when the instance name is entered in the console, for instance just running the line
>>> person
You can do it with __repr__:
def __repr__(self):
return f'when entering the instance name in the console: {self.name}'
This will print:
when entering the instance name in the console: bob
This appears more pythonic to me than having a method that simply prints the name.
You're never storing the name on the instance, where would it get the name from? Your __init__ needs to do something along the lines of self.name = name
the name method and attribute are going to conflict, the latter will shadow (hide) the former, and it should look up whatever attribute its using on self
You never assigned the passed name to the object. Try:
class human:
def __init__(self, name):
print("this is a human")
self.name = name
def print_name(self):
print("this is {}".format(self.name))
bob = human("bob")
bob.print_name()
there are couple of things to update in the code:
bob is an instance which is not defined at human class
notice that init, name functions expect external param but you never use it in the function. (in self. = name)
in order to use it:
define a var in the class named 'name' and update you function to:
class human:
_name = ""
def __init__(self, name):
print("this is a human")
self._name = name
def name(self):
print("this is "+ self._name)
bob = human("bob")
bob.name()
bob = human("bob") only init function and you should call bob.name() in order to call the print-name function

Access class variables from another class

I have a simple class A that gets the name from users.
class A:
def __init__(self, name = ''):
self.name = name
Then I want to create a class B that prints out this name. I tried:
class B:
def print_name(printing_name = A.name):
print(printing_name)
Then I call these methods:
m1 = A("x")
B.print_name(m1)
This returns the error
Traceback (most recent call last):
File "so.py", line 5, in <module>
class B:
File "so.py", line 7, in B
def print_name(printing_name = A.name):
AttributeError: class A has no attribute 'name'
I know that I did not assign a class variable in the class A, and thus the name attribute goes with specific instances, not the entire class. However, the name attribute has to connect with every specific instance because it changes from the case to case. Then how should I get this name in class B?
Change your class B to this:
class B:
#staticmethod
def print_name(obj):
print(obj.name)
The print_name method probably should be decorated as a "static method". The property "name" of self is an instance attribute which can not be referred directly from the class itself.
That's correct: name is an instance attribute, not a class attribute. IN this case, m1 has a name, but class A does not. You need to access the name of the input parameter, not attempt to print a class attribute.
You also need to make B.print_name a class function, since you're not calling it from an instance of B.
class B:
#staticmethod
def print_name(inst):
print(inst.name)
Output:
x
Edit: The answers suggesting #staticmethod are ideal if you understand what it does.
class A:
def __init__(self, name = ''):
self.name = name
class B:
def __init__(self):
pass
def print_name(self, var):
print (var.name)
Output:
>>> m1 = A("X")
>>> b = B()
>>> b.print_name(m1)
X
>>>
In this instance A is the name of the class, and you should not give it as the default argument for calling the print_name method. Have a look at keyword arguments for Python, and you will see that what you have written actually means that you have the default value set to the .name property of the class A, which does not exist unless the class is instantiated (i.e. an object is created of the class).
Your B class should read:
class B:
def print_name(printing_object):
print(printing_object.name)

Calling a subclass variable in the parent class __init__()? [duplicate]

If I have the following code:
class Foo(object):
bar = 1
def bah(self):
print(bar)
f = Foo()
f.bah()
It complains
NameError: global name 'bar' is not defined
How can I access class/static variable bar within method bah?
Instead of bar use self.bar or Foo.bar. Assigning to Foo.bar will create a static variable, and assigning to self.bar will create an instance variable.
Define class method:
class Foo(object):
bar = 1
#classmethod
def bah(cls):
print cls.bar
Now if bah() has to be instance method (i.e. have access to self), you can still directly access the class variable.
class Foo(object):
bar = 1
def bah(self):
print self.bar
As with all good examples, you've simplified what you're actually trying to do. This is good, but it is worth noting that python has a lot of flexibility when it comes to class versus instance variables. The same can be said of methods. For a good list of possibilities, I recommend reading Michael Fötsch' new-style classes introduction, especially sections 2 through 6.
One thing that takes a lot of work to remember when getting started is that python is not java. More than just a cliche. In java, an entire class is compiled, making the namespace resolution real simple: any variables declared outside a method (anywhere) are instance (or, if static, class) variables and are implicitly accessible within methods.
With python, the grand rule of thumb is that there are three namespaces that are searched, in order, for variables:
The function/method
The current module
Builtins
{begin pedagogy}
There are limited exceptions to this. The main one that occurs to me is that, when a class definition is being loaded, the class definition is its own implicit namespace. But this lasts only as long as the module is being loaded, and is entirely bypassed when within a method. Thus:
>>> class A(object):
foo = 'foo'
bar = foo
>>> A.foo
'foo'
>>> A.bar
'foo'
but:
>>> class B(object):
foo = 'foo'
def get_foo():
return foo
bar = get_foo()
Traceback (most recent call last):
File "<pyshell#11>", line 1, in <module>
class B(object):
File "<pyshell#11>", line 5, in B
bar = get_foo()
File "<pyshell#11>", line 4, in get_foo
return foo
NameError: global name 'foo' is not defined
{end pedagogy}
In the end, the thing to remember is that you do have access to any of the variables you want to access, but probably not implicitly. If your goals are simple and straightforward, then going for Foo.bar or self.bar will probably be sufficient. If your example is getting more complicated, or you want to do fancy things like inheritance (you can inherit static/class methods!), or the idea of referring to the name of your class within the class itself seems wrong to you, check out the intro I linked.
class Foo(object):
bar = 1
def bah(self):
print Foo.bar
f = Foo()
f.bah()
bar is your static variable and you can access it using Foo.bar.
Basically, you need to qualify your static variable with Class name.
You can access class variables by object and directly by class name from the outside or inside of class and basically, you should access class variables directly by class name because if there are the same name class and instance variables, the same name instance variable is prioritized while the same name instance variable is ignored when accessed by object. So, using class name is safer than using object to access class variables.
For example, you can access the class variable by object and directly by class name from the outside of the class as shown below:
class Person:
name = "John" # Class variable
obj = Person()
print(obj.name) # By object
print(Person.name) # By class name
Output:
John
John
But, if you add the same name instance variable as the class variable by object:
class Person:
name = "John" # Class variable
obj = Person()
obj.name = "Tom" # Adds the same name instance variable as class variable
print(obj.name) # By object
print(Person.name) # By class name
Or, if you add the same name instance variable as the class variable by self in __init__():
class Person:
name = "John" # Class variable
def __init__(self, name):
self.name = name # Adds the same name instance variable as class variable
obj = Person("Tom")
print(obj.name) # By object
print(Person.name) # By class name
The same name instance variable is prioritized when accessed by object:
Tom # By object
John # By class name
And, you can also access the class variable by self and directly by class name from the inside of the instance method as shown below:
class Person:
name = "John" # Class variable
def test(self): # Instance method
print(self.name) # By "self"
print(Person.name) # By class name
obj = Person()
obj.test()
Output:
John
John
But, if you add the same name instance variable as the class variable by object:
class Person:
name = "John" # Class variable
def test(self): # Instance method
print(self.name) # By "self"
print(Person.name) # By class name
obj = Person()
obj.name = "Tom" # Adds the same name instance variable as the class variable
obj.test()
Or, if you add the same name instance variable as the class variable by self in __init__():
class Person:
name = "John" # Class variable
def __init__(self, name):
self.name = name # Adds the same name instance variable as the class variable
def test(self): # Instance method
print(self.name) # By "self"
print(Person.name) # Directly by class name
obj = Person("Tom")
obj.test()
The same name instance variable is prioritized when accessed by self:
Tom # By "self"
John # By class name

Overriding decorated subclass methods

I'm fiddling around with inheritance and found a behavior that seems strange to me---namely, that some times I can override a parent decorator function (used for validation), but sometimes I cannot, and I cannot understand why or what the difference is.
A quick walkthrough in words---I have a person object I'd like subclass to a more particular person object. The more particular one will have an additional field, "Dance," and will have different validation rules on a previous field, "name."
Here's my base case which works:
# Define the validation wrapper
def ensure(name, validate, doc=None):
def decorator(Class):
privateName = "__" + name
def getter(self):
return getattr(self, privateName)
def setter(self, value):
validate(name, value)
setattr(self, privateName, value)
setattr(Class, name, property(getter, setter, doc=doc))
return Class
return decorator
# Define the not string validation
def is_not_str(name, value):
if isinstance(value, str):
raise ValueError("{} cannot be a string.".format(name))
# Chosen to be exact opposite of above---demonstrating it's possible to reverse.
def is_str(name, value):
if not isinstance(value, str):
raise ValueError("{} must be a string.".format(name))
#ensure("name", is_str)
#ensure("url", is_str)
class Person(object):
def __init__(self,s):
self.name = s.get('name',{})
self.url = s.get('url','')
def __str__(self):
return "Person({{'name':'{}','url':'{}'}})".format(self.name, self.url)
def __repr__(self):
return str(self)
#ensure("name", is_not_str) # require a number rather than a Name() object.
class Crazyperson(Person):
def __init__(self,s):
super(Crazyperson,self).__init__(s) # idiom to inherit init
self.dance = s.get('dance') # add new param.
bill = Person({"name":"bill",
"url":"http://www.example.com"})
fred = Crazyperson({"name":1,
"url":"http://www.example.com",
"dance":"Flamenco"})
This works fine. So, the first object, bill, is created in such a way that the validation is_str succeeds. If you try to put a number there, it fails. The second object, likewise, accepts non-strings, so fred is created successfully.
Now, here's the case where it breaks, which I'd like to understand...
def is_Name(name, value):
if not isinstance(value, dict) and not isinstance(value,Name):
raise ValueError("{} must be a valid Name object".format(name))
# new object that will be a non-string type of name.
#ensure("firstname", is_str)
#ensure("lastname", is_str)
class Name(object):
def __init__(self,s):
self.firstname = s.get('firstname','')
self.lastname = s.get('lastname')
def __str__(self):
return "Name({{'firstname':'{}','lastname':'{}' }})".format(self.firstname, self.lastname)
def __repr__(self):
return str(self)
#ensure("name", is_Name) # require it as the default for the base class
#ensure("url", is_str)
class Person(object):
def __init__(self,s):
self.name = Name(s.get('name',{}))
self.url = s.get('url','')
def __str__(self):
return "Person({{'name':'{}','url':'{}'}})".format(self.name, self.url)
def __repr__(self):
return str(self)
#ensure("name", is_str) # require a number rather than a Name() object.
class Crazyperson(Person):
def __init__(self,s):
super(Crazyperson,self).__init__(s)
self.name = s.get('name','') # THIS IS THE KEY
self.dance = s.get('dance')
bill = Person({"name":{"firstname":"Bill", "lastname":"billbertson"},
"url":"http://www.example.com"})
fred = Crazyperson({"name":"Fred",
"url":"http://www.example.com",
"dance":"Flamenco"})
In this instance, the Crazyperson fails. The error suggests that the is_Name validation function in the __init__ is still being applied:
Traceback (most recent call last):
File "<stdin>", line 3, in <module>
File "<stdin>", line 4, in __init__
File "<stdin>", line 5, in __init__
File "<stdin>", line 5, in __init__
AttributeError: 'str' object has no attribute 'get'
It looks like it has called the Name initializer: Name(s.get('name',{})) on the string name "Fred".
But it seems it can't be, because in the previous example, I was able to remove a completely contradictory validation (is_str versus is_not_str). Why is this less opposite but failing more? In the first case it wasn't applying both is_str and is_not_str, why is it /now/ applying both is_Name and is_str with seemingly identical syntax?
My question is: what's different about the first way of doing this that causes it to succeed from the second way? I've tried to isolate variables here, but don't understand why I can undo the wrapped validator inherited from the parent class in Scenario I but cannot do what seems similar in Scenario II. It seems the only meaningful difference is that it's an object instead of a string.
(I understand that the better architectural way to do this would be to have a third more abstract parent class, with no validation rules that need changing---and both kinds of person would inherit from that. But I also understand I am supposed to be able to change methods in subclasses, so I'd like to at least understand the difference between why one is succeeding and the other failing here.)
In your second setup, the is_Name function is not applied. You are creating Name object, regardless, in the __init__ method:
class Person(object):
def __init__(self,s):
self.name = Name(s.get('name',{}))
self.url = s.get('url','')
Note the self.name = Name(...) line there.
In Crazyperson.__init__() you call the parent method:
def __init__(self,s):
super(Crazyperson,self).__init__(s)
self.dance = s.get('dance')
passing on s to Person.__init__() which creates a Name() object.
So when you create fred with fred = Crazyperson({"name":"Fred", ...}) you are passing name set to the string 'Fred' to Name.__init__(), which expected a dictionary instead:
class Name(object):
def __init__(self,s):
self.firstname = s.get('firstname','')
self.lastname = s.get('lastname')
and this is where your code fails:
>>> 'Fred'.get('firstname', '')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'str' object has no attribute 'get'
Only set name on Person if no self.name has been set yet:
class Person(object):
def __init__(self,s):
if not hasattr(self, 'name')
self.name = Name(s.get('name', {}))
self.url = s.get('url','')
and set name first in Crazyperson:
def __init__(self,s):
self.name = s.get('name', 0)
self.dance = s.get('dance')
super(Crazyperson,self).__init__(s)

Dynamically assigning function implementation in Python

I want to assign a function implementation dynamically.
Let's start with the following:
class Doer(object):
def __init__(self):
self.name = "Bob"
def doSomething(self):
print "%s got it done" % self.name
def doItBetter(self):
print "Done better"
In other languages we would make doItBetter an anonymous function and assign it to the object. But no support for anonymous functions in Python. Instead, we'll try making a callable class instance, and assign that to the class:
class Doer(object):
def __init__(self):
self.name = "Bob"
class DoItBetter(object):
def __call__(self):
print "%s got it done better" % self.name
Doer.doSomething = DoItBetter()
doer = Doer()
doer.doSomething()
That gives me this:
Traceback (most recent call last): Line 13, in
doer.doSomething() Line 9, in call
print "%s got it done better" % self.name AttributeError: 'DoItBetter' object has no attribute 'name'
Finally, I tried assigning the callable to the object instance as an attribute and calling it:
class Doer(object):
def __init__(self):
self.name = "Bob"
class DoItBetter(object):
def __call__(self):
print "%s got it done better" % self.name
doer = Doer()
doer.doSomething = DoItBetter()
doer.doSomething()
This DOES work as long as I don't reference self in DoItBetter, but when I do it gives me an name error on self.name because it's referencing the callable's self, not the owning class self.
So I'm looking for a pythonic way to assign an anonymous function to a class function or instance method, where the method call can reference the object's self.
Your first approach was OK, you just have to assign the function to the class:
class Doer(object):
def __init__(self):
self.name = "Bob"
def doSomething(self):
print "%s got it done" % self.name
def doItBetter(self):
print "%s got it done better" % self.name
Doer.doSomething = doItBetter
Anonymous functions have nothing to do with this (by the way, Python supports simple anonymous functions consisting of single expressions, see lambda).
yak's answer works great if you want to change something for every instance of a class.
If you want to change the method only for a particular instance of the object, and not for the entire class, you'd need to use the MethodType type constructor to create a bound method:
from types import MethodType
doer.doSomething = MethodType(doItBetter, doer)

Categories