I have written some python code:
class key(object):
def __init__(self,name):
object.__init__(self,age)
this.name = name
this.age = age
def somefunction(self):
print "yay the name is %d" % self.name
baby = key('radan',20)
baby.somefunction()
When I create an instance of key with baby = key('radan',20), I got a TypeError. I don't know why I am getting this error. Is it because of object.__init__(self,age)?
If yes, please help me in explaining why we use object.__init__(self,age) and what the purpose of that is and help me solve this code.
Some pointers:
class Key(object): # in Python, classes are usually named with a starting capital
def __init__(self, name, age): # name all your arguments beside self
self.name = name # use self.name, not this.name
self.age = age
def somefunction(self):
print "yay the name is %s" % self.name
baby = Key('radan',20)
baby.somefunction()
# output: yay the name is radan
Actually, you can can name the self instance parameter whatever you like in Python (even this), but it makes the code harder to read for other people, so just use self.
You don't have to use object.__init__(self, name, age) here. If you remove that line and implement the changes above, your code will work just fine.
Your code contains several errors:
class key(object):
def __init__(self, name, age): # where's your age?
self.name = name # no need to call object.__init__
self.age = age # there is no such thing called "this", use self
def somefunction(self):
print "yay the name is %s" % self.name # use %s as the comment says
baby = key('radan', 20)
baby.somefunction()
output:
>>> baby = key('radan', 20)
>>> baby.somefunction()
yay the name is radan
When you do baby = key('radar', 20) you are actually passing three arguments: the instance, the name and the age. However your initialiser is defined to take exactly two arguments so you get a TypeError.
self is the argument implicitly passed when referring to an instance of an object.
For your __init__ function, I would just do:
def __init__(self, name, age):
self.name = name
self.age = age
So we can assign the arguments passed as attributes to the current instance, conventionally called self.
It makes no sense here to call object.__init__ at all, just remove that line.
Apart from that, everything works fine (except use %s instead of %d).
Testing:
>>> baby = key('radan', 20)
>>> baby.somefunction()
yay the name is radan
Related
I'am using more class based programs, however in some cases it's not handy to provide all self.paramets into a class.
In those cases I want to use a regular input into a function in a class. I figured out a way to achieve both inputs, let me show this in following script:
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def myfunc(a):
if (type(a) == str):
name = a
else:
name = a.name
print("Hello my name is " + name)
p1 = Person("John", 36)
p1.myfunc()
print("---------------------")
Person.myfunc("Harry")
Output:
Hello my name is John
---------------------
Hello my name is Harry
First, the name is initialized by the classes self.params.
Second, the name is provided in the method within the class as a string.
So a type check is necessary.
However I don't think this is a clean approach, because when I have >30 methods I need to implement these type checks again, including upcoming type-error results.
Does anyone know a better approach?
The simplest solution is to implement a __str__ method for your class. This method will be called whenever something tries to convert an instance of the class to a string.
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def __str__(self):
return self.name
p = Person('Jane', 25)
print('Hello', p)
'Hello Jane'
I have multiple classes and I have instances from each class e.g: Student class. every instance (a student) has their own courses. Now when a user signs in (by input) I want to print their list of courses. Or even just their age to show that I have the correct object.
Is there a better way than eval() to get an object from class based on input
like the following example:
class Student:
def __init__(self, name, age):
self._name = name
self._age = age
blablue = Student('bla blue', '23')
name = input('enter your name')
name = name.split(' ')
stundent = eval(name[0] + name[1])
print(student)
print(student.age)
output:
enter your name: bla blue
<__main__.Foo object at 0x000001B2978C73C8>
23
I assume this is for educational purpose (production code would use a SQL database and some ORM):
try:
# python 2.x
input = raw_input
except NameError:
# python 3.x
pass
class AlreadyExists(ValueError):
pass
class DoesNotExist(LookupError):
pass
class FooCollection(object):
def __init__(self):
self._foos = {}
def add(self, foo):
if foo.name in self._foos:
raise AlreadyExists("Foo with name '{}' already exists".format(foo.name))
self.update(foo)
def update(self, foo):
self._foos[foo.name] = foo
def get(self, name):
try:
return self._foos[name]
except KeyError:
raise DoesNotExist("no Foo named '{}'".format(name))
class Foo(object):
def __init__(self, name, age):
self._name = name
self._age = age
# we at least need to be able to read the name
#property
def name(self):
return self._name
def __repr__(self):
return "Foo({}, {})".format(self._name, self._age)
def main():
foos = FooCollection()
blablue = Foo('bla blue', '23')
foos.add(blablue)
name = input('enter your name: ').strip()
try:
print("found {}".format(foos.get(name)))
except DoesNotExist as e:
print(e)
if ___name__ == "__main__":
main()
The principle here is to have a storage for your instances. I chose a dict for fast lookup with the Foo.name as key, in real life you'd probably want an opaque unique identifier for each instance and multiple indexes (i.e. one by id, one by name etc) - but actually in real life you would use a SQL database that already provide all those features in a much more optimized way ;-)
Also, I wrapped the dict in a dedicated class with its own interface. This allows to decouple the interface from the implementation (if you later decide you want more indexes than just name for example), and encapsulate domain logic too (i.e. checking you don't accidentally overwrite an existing Foo).
I am wondering how to initialize an object in python with only named args, and nothing else, if this is possible.
If the order of self.name = name and self.age = age are swapped, the error is with initializing age. I have these given as keyword args to the object, so why is that not enough? I saw a class in dive into python instantiated with explicitly named keyword arguments and their default (filename=None), so I assumed **kwargs would work too. Thank you
What you're missing is that kwargs need to be explicitly retrieved by name. Here's a modified version of your code, to illustrate. Note the initialization of name and age.
class Person(object):
def __init__(self, **kwargs):
self.name = kwargs.get('name')
self.age = kwargs.get('age')
# you'll probably want to check that all required
# members were initialized.
bob = Person(name='bob', age=45)
print bob
print bob.age
Output:
<__main__.Person object at 0x1074e0bd0>
45
kwargs is a dictionary. So you should rather do this:
class Person(object):
def __init__(self, **kwargs):
self.name = kwargs["name"]
self.age = kwargs["age"]
I might be missing something stupid, or I am simply trying to walk through a steel wall instead of going around. Basically I have created turtle class and I use it in different script for drawing L-systems. I thought I could create a function outside the turtle class, which will accept:
turtle - the instance of from my turtle class
a string from L-system
dictionary of rules/instructions of how to interpret different symbols in the string above, that is for which symbol call which method from the turtle class
But it all crashes on trying to pass the method to the function - I think it does not see the method, since it is defined inside the class. To simplify the matters I have created a basic example, which fails at the same place:
class Person():
def __init__(self, age):
self.age = age
def birthday(self):
self.age += 1
def foo(person, method):
person.method()
jane = Person(20)
foo(jane, birthday)
#Traceback (most recent call last):
# File "passmethod.py", line 14, in <module>
# foo(jane, birthday)
#NameError: name 'birthday' is not defined
That is:
the only variable in Person class instance is age, the only method birthday raises the age by 1.
jane is Person class instance, initialized at 20 years old
the by function foo I am trying to call birthday method on her
script does not see birthday method and crashes
So, my question(s) is(are):
Is there a way, how to do it? If so, how?
If not or if it would not be advisable to do so, what should I use?
Update
Thanks for those quick and nice answers! The additional question which naturally follows - is any of those ways preferred? I would guess, that
__getattribute__ and getattr are pretty much the same, although for the first one, the inheritance is probably necessary.
I don't see any great difference in this case between using jane.birthday or Person.birthday, although in general it could be useful to be able to call the method for different Person instances, e.g. created in the foo function.
Here the working code:
class Person():
def __init__(self, age):
self.age = age
def birthday(self):
self.age += 1
def foo(person, method):
getattr(person, method)()
Test:
>>>
>>> jane = Person(20)
>>> foo(jane, 'birthday')
>>> jane.age
21
>>>
Well, there are ways to do that.
First way: just pass method bound to a particular object:
def foo(person, method):
method() # calls jane.birthday()
jane = Person(20)
foo(jane, jane.birthday)
Second way: pass a class method and apply it to a particular object:
def foo(person, method):
method(person) # calls Person.birthday(jane), which is the same thing
jane = Person(20)
foo(jane, Person.birthday)
You can use the __getattribute__ method (inherited from object):
class Person(object):
def __init__(self, age):
self.age = age
def birthday(self):
self.age += 1
def foo(person, method):
person.__getattribute__(method)()
jane = Person(20)
foo(jane, "birthday")
As I suggested in the comments, you could sub-class your Turtle to add a rule-following method. To demonstrate a trivial example:
class InstructableTurtle(Turtle):
def follow_instructions(self, instructions):
for instruction in instructions:
if instruction == "MOVE_LEFT":
self.move_left()
...
But you could also have the rules provided as an additional argument to the new instance:
def __init__(self, ..., rules): # '...' represents args to base Turtle
super().__init__(...) # or 'super(InstructableTurtle, self)' on Python 2.x
self.rules = rules
As an example:
>>> class Turtle():
def __init__(self, name):
self.name = name
def move_left(self):
print("{0.name} is moving left...".format(self))
>>> class InstructableTurtle(Turtle):
def __init__(self, name, rules):
super().__init__(name)
self.rules = rules
def follow_instruction(self, instruction):
self.rules[instruction](self)
>>> tommy = InstructableTurtle("Tommy", {"LEFT": Turtle.move_left})
>>> tommy.follow_instruction("LEFT")
Tommy is moving left...
I am new to Python, and am trying to figure out how to access the global variable count within the repr method in the Student class below:
class Student(object):
count = 0
def __init__(self, **kwargs):
self.name = kwargs.get("name")
self.age = kwargs.get("age")
Student.count += 1
def __repr__(self):
try:
return "name: %s, age: %d" % (self.name, self.age)
except TypeError:
print "student number: %d" % (Student.count)
When I create an instance, such as student = Student, and the try to print the variable student, I get the following error:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "school.py", line 23, in __repr__
print "student number: %d" % (Student.count)
NameError: global name 'count' is not defined
Thanks.
You can access class properties as well using self. Not that in your case, your error handling in __repr__ isn’t necessary. In a method, self will always be correct (unless you really mess something up), so you can just assume that you can access self properly. As you initialize name and age in the initializator, you can also assume that both properties exist:
class Student (object):
count = 0
def __init__ (self, **kwargs):
self.name = kwargs['name']
self.age = kwargs['age']
self.count += 1
def __repr__ (self):
return "name: %s, age: %d" % (self.name, self.age)
Instead of accepting just **kwargs, it might be a good idea to actually ask for name and age as proper parameter in the initializator. Since you do expect name and age to be specified, incorrectly calling your constructor will fail early that way:
def __init__ (self, name, age, **kwargs): # **kwargs in case you want to accept more
self.name = name
self.age = age
self.count += 1
That all being said, the error you show shouldn’t happen. There shouldn’t be an exception being thrown in __repr__, and Student.count should be accessible as well. So you are probably calling __repr__ in some weird way. The proper way would be something like this:
a = Student(name='Peter', age=15)
print(repr(a))
You should use self.count instead of Student.count inside the class. You do not need to use Student.count because you are still inside the class, self refers to anything inside the class. It doesn’t need to be inside the __init__ function. For example:
class RandomClass:
random_var = 0
def __init__(self, var1, var2):
self.var1 = var1
self.var2 = var2
another_var = 3
def __str__(self):
print(“Printing variables: %d and %d” % (self.random_var, self.another_var))#using self.random_var, not RandomClass.random_var