Suppose you have an object called e_book that simulate an electronic book. Functionality to be achieved is that every time you execute "print(e_book)", the printed display will behave like flipping through the pages.
For example, execute "print(e_book)" the first time:
"All happy families are alike."
execute "print(e_book)" the second time displayed content will change:
"Each unhappy family is unhappy in its own way."
and the third time it will change again, and so on.
To sum up, I want to control the string display of an object by simply calling "print(object_name)". Is this achievable?
To control the display of an objet, override the repr method in your class
def __repr__(self):
return 'whatever'
You can also redefine the str method.
class EBOOK():
def __init__(self):
self.pages = list()
self.seenPages = -1
def addPage(self, data):
self.pages.append(data)
def __repr__(self):
self.seenPages += 1
return str(self.pages[self.seenPages])
e_book = EBOOK()
e_book.addPage("All happy families are alike.")
e_book.addPage("Each unhappy family is unhappy in its own way.")
print(e_book)
print(e_book)
should produce:
All happy families are alike.
Each unhappy family is unhappy in its own way.
Related
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 years ago.
Improve this question
I am currently trying to teach myself python by reading through "Python for absolute beginners" by Michael Dawson. I am currently working through the challenges in chapter 9, largely to really get a grip on how classes actually interact with each other. I am attempting to write a (very) simple text based adventure game where the user travels between various locations. However the way that I am trying is not doing what I want it to. Here is the code:
*Disclaimer - I am well aware this probably looks like garbage, I don't entirely understand what I've written myself and its aim is just to give me an understanding of class interactions.
# classes module for my basic adventure game
import random
# the locations that the player will travel to
class Location(object):
"""Locations that the adventurer can travel to"""
def __init__(self, name, description):
self.name = name
self.description = description
class Location_list(object):
def __init__(self):
self.locations = []
def __str__ (self):
if self.locations:
rep = ""
for location in self.locations:
rep += str(location)
else:
rep = "<empty>"
return rep
def clear(self):
self.locations = []
def add(self, location):
self.locations.append(location)
def rand_location(self):
x = random.choice(self.locations)
print("You step out of the magical portal, it has taken you to", x, "!")
# The player
class Adventurer(object):
"""An adventurer who travels to different locations within a mystical world"""
def __init__(self, name):
self.name = name
def travel(self):
Location_list.rand_location
print("You step into the magic portal")
loc1 = Location("London", "The capital of the UK")
loc2 = Location("Paris", "The capital city of France")
loc3 = Location("Berlin", "The capital city of Germany")
location_list = Location_list
player = Adventurer(input("What is your name traveller?"))
question = input("do you want to travel now?")
if question == "yes":
player.travel()
else: print("No journey for you bellend")
input("press enter to exit")
This is my code so far. Effectively what I wanted to do was have a class of locations and a class that created a list of those locations. I would then have a method on the location class that called a method on the location list class to return a random location from the list. As far as I can tell the problem i'm having is that the list isn't actually being created. The code i used for this i actually stole from earlier in the chapter as i thought it would do what i wanted it to do - code in question:
class Location_list(object):
def __init__(self):
self.locations = []
def __str__ (self):
if self.locations:
rep = ""
for location in self.locations:
rep += str(location)
The problem is that i dont actually get anything back from calling the players travel method beyond calling the print parts of it.
So firstly could someone please help me sort out what i've already got so that that the location list actually creates a list of location objects, and then the method randomly selects from this list
And secondly, if my code is, as i suspect, barking up the completely wrong tree. Could someone show me a way of creating a class that is a list of other objects.
I mentioned in a comment why this is a bad question. Just to emphasize, I'll point you again to https://stackoverflow.com/help/mcve.
You don't describe your problem, but mention you suspect some list not getting created. Indeed you have a line like this:
location_list = Location_list
This line has a mistake! You should change it to:
location_list = Location_list()
The second version creates an instance of the Location_list class and assigns it to a variable. This is what you want. On the other hand the first version gives another name to the Location_list class. So then you could say location_list() to create an instance of the same class. But that is not what you want.
I didn't read through the whole code, just looked at uses of this list, but here's another mistake:
def travel(self):
Location_list.rand_location
print("You step into the magic portal")
Location_list is a class. Location_list.rand_location is an unbound method of this class. In that line you just refer to this method, but you don't even call it. It's like writing 15 on a line. Valid code, but doesn't do anything.
Instead you want to refer to an instance of the class. If you've fixed the first mistake you can write location_list. (note the lowercase l instead of L.) And you want to call the rand_location method. So you need to write:
def travel(self):
location_list.rand_location()
print("You step into the magic portal")
First you have to properly instantiate Location_list with location_list = Location_list() Then you have to add the location instances to your location_list instance. So after that
add
location_list.add(loc1)
location_list.add(loc2)
location_list.add(loc3)
Also to print these locations you should add a __str__ method to your Location class else str(location) won't give you the name of the location:
def __str__ (self):
if self.name:
return str(self.name)
I have the following code;
class weather(object):
temperature = 0
humidity = 0
precis = "There is no weather when there plainly should be, please contact an administrator."
cloud = "none"
windDirection = "nnw"
windSpeed = 0
def getWeather(self):
weatherJSON = requests.get('http://www.bom.gov.au/fwo/IDT60901/IDT60901.94970.json')
weatherDoc = json.loads(weatherJSON.text)
temperature = weatherDoc["observations"]["data"][1]["apparent_t"]
humidity = weatherDoc["observations"]["data"][1]["rel_hum"]
windDirection = weatherDoc["observations"]["data"][1]["wind_dir"]
windSpeed = weatherDoc["observations"]["data"][1]["wind_spd_kmh"]
cloud = weatherDoc["observations"]["data"][1]["cloud_type"]
This is a class that has weather features, and contains a function to update them. If I then instantiate the class with
this = weather()
this.getWeather()
The variables in this don't get updated with real world weather. Two questions, why not, and I guess as more of a sub-question, am I doing this right? Should my approach be to use the methods in a class to manipulate an instance of the class?
You've got two fundamental problems here.
First, you're mixing up class attributes—that is, variables that are shared by all instances of the same class—and normal instance attributes—that is, variables that are a part of each instance.
You very rarely want class attributes for anything. You want instance attributes, however, all the time. So, to start with:
class weather(object):
def __init__(self):
self.temperature = 0
self.humidity = 0
self.precis = "There is no weather when there plainly should be, please contact an administrator."
self.cloud = "none"
self.windDirection = "nnw"
self.windSpeed = 0
Notice the self.temperature, not just temperature. That's how you create an instance attribute. It's also how you access or update one.
Second, you're also mixing up local variables—that is, variables that exist while a function is running and then disappear—with instance attributes. But you already know hot to update instance attributes from above. So:
def getWeather(self):
weatherJSON = requests.get('http://www.bom.gov.au/fwo/IDT60901/IDT60901.94970.json')
weatherDoc = json.loads(weatherJSON.text)
self.temperature = weatherDoc["observations"]["data"][1]["apparent_t"]
self.humidity = weatherDoc["observations"]["data"][1]["rel_hum"]
self.windDirection = weatherDoc["observations"]["data"][1]["wind_dir"]
self.windSpeed = weatherDoc["observations"]["data"][1]["wind_spd_kmh"]
self.cloud = weatherDoc["observations"]["data"][1]["cloud_type"]
self.precis = '???'
(I'm not sure what you want to put in precis, but clearly you don't want to leave it as "There is no weather…".)
If you make the second fix without the first, everything will appear to work, but only by coincidence. When you ask for this.temperature, if this has no instance attribute named temperature, Python will automatically look for the class attribute type(this).temperature. If you then add an instance attribute named temperature, it "shadows" the class attribute, so next time you do this.temperature, you get the instance's value.
So, you can use class attributes as a sort of "default value" for instance attributes. But you should only do this if you know what you're doing. (It can get really confusing if, say, you start using mutable values like lists and mutating them in your methods…)
Two questions, why not, and I guess as more of a sub-question, am I doing this right?
You're updating a local variable in getWeather().
You should update the instance variable instead, which can be done by prefixing the variable name with self, in other words, replace:
def getWeather(self):
...
cloud = ...
with
def getWeather(self):
...
self.cloud = ...
Is the indentation in your example broken? Are those variables supposed to be class members of the weather class?
Eitherway, the function is shadowing them, creating new ones locally and therefore not changing the others.
I am new to python, but I have some knowledge of Java. Here I have my first python code :
class Movie(object):
def __init__(self, name, year):
self.name = name
self.year = year
def tostring(self):
return "%s (%s)" % (self.name,self.year)
def __str__(self):
return self.tostring()
class MoviesCollection(object):
def __init__(self):
self.colection = []
def add_movie(self, movie):
self.colection.append(movie)
def __iter__(self):
return iter(self.colection)
def __str__(self):
return '\n'.join(map(str, self.colection))
filmy = MoviesCollection()
a = Movie('A', 256)
b = Movie('B', 512)
c = Movie('C', 1024)
filmy.add_movie(a)
filmy.add_movie(b)
filmy.add_movie(c)
filmy.add_movie(c)
filmy.add_movie(c)
filmy.add_movie(c)
#filmy.add_movie('Aloha')
for m in filmy:
print m.tostring()
print filmy
Now this works well, but as I uncoment the line from the bottom I will have some runtime errors as I am calling a tostring() method on str type object. And here is the question. How can I prevent inserting such object of different type than Movie into colection ? The Java guy in me would make that list colection like this:
List<Movie>
Also I could put a condition there to add_movie function like this :
if isinstance(movie, Movie):
but isn't there any other way ?
In Python - you are expected to behave appropriately and don't do things that don't make sense. This is part of the flexibility of a language that was designed for teaching and scientists, and doesn't put too much emphasis on types, or "object contracts" and other such fluff.
The way you would write your code by taking all the "Java" out of it is:
class Movie(object):
""" A movie, thing to spend a few hours
watching, then a few hours hating yourself
over watching it. """
def __init__(self, name, year):
self.name = name
self.year = year
def __str__(self):
return '{} ({})'.format(self.name, self.year)
movie_collection = [Movie('Titanic', 1997), Movie('Showgirls', 1995)]
for movie in movie_collection:
print(movie)
In the Python world Java is sometimes affectionately referred to as a "bondage" language. There are two fundamentally different programming language philosophies: one group seeks to make it harder to write bad programs (Java), the other strives to make it easier to write good programs (Python). Neither is completely successful, because it is possible to write bad programs in any language.
Overall, in Python we prefer to write our code so that only Movie objects are added to the list, rather than take the time to verify that every element put on the list is a Movie. Unit tests can be used to verify this in a given number of cases, but this will never give you the assurance you seek.
Type checking of the nature you suggest is possible, but generally held to be unnecessary or even "unPythonic".
I am working on a project using pydev. This is my first project using pydev.
My project structure is:
myProject(project)
projFolder(folder)
userInterface.py
makeTriangle.py
I've a file userInterface.py. This file is used to take input from the user and to show the desired result via a class after doing some operations on the input in another file.
Now I've to pass the value returned from this file to another file named makeTriangle. But I am unable to do that. How can I pass the value returned from one file to another file?
Please let me know if I am doing any thing wrong here. Your response will help me to sharpen my skills.
### userInterface.py #########
class userInterface():
getList = []
maxList = 4
def getUserList(self):
print("*** getting user input ***")
while len(self.getList) < self.maxList:
item = input("enter numbers: ")
self.getList.append(item)
return self.getList
def showUserList(self,passedList):
print("*** showing user input ***")
print (passedList)
### makeTriangle.py #########
from userInterface import userInterface
class makeTriangle():
### how to get the value of getUserList here
I would put your initialiaztion of userInterface variable in the init method:
### userInterface.py #########
class userInterface():
def __init__(self):
#do initialization.
self. getList = []
self. maxList = 4
Then in your other file you can create an instance of userInterface and invoke the methods needed. For instance in the example below the doSomething uses getUserList of userInterface.
### makeTriangle.py #########
from userInterface import userInterface
class makeTriangle():
def __init__(self):
#do any initialization.
def doSomething():
### how to get the value of getUserList here
UI = userInterface()
input = UI.getUserList()
for num in input:
#do whatever
I strongly recommend you read how classes work in python. Checkout https://docs.python.org/3.2/tutorial/classes.html
I agree that you really need to read the docs, but basically any thing that you labled with self.xxxx and any methods you made can be accessed in makeTriange by saying userInterface.xxxxx
so if you need access to the maxList variable, its:
userInterface.maxList
if you need to use the getuserList() function, its
userInterface.getUserList()
But like the other poster said, you should be using init(). Right now, you are making CLASS variables. Remember, you usually want to give these attributes to the objects you are making with the class, not the class it self, the init() method will do this for you.
right now, every time you are making a triangle, you are appending to the same list because getList is a CLASS method, but I think you want a new list for each triangle, so you need to make it an INSTANCE method by putting it in init(), which implicitly gets called every time you make an object with the class.
all of this is explained in the docs.
I'm writing an exporter for a game my friend and I are making and it involves setting custom properties and tags to objects which are then recognized in the game and dealt with accordingly. Our engine, which is written in C/C++ has been successfully tested with my current version of the export script, and I''m currently working on tidying it up.
The script uses Blender's feature of custom properties to write custom tags to output file. The model typically consists of multiple 'parts' (Blender mesh objects that are parented to form a tree, with one 'parent' and multiple 'child' objects) and some of those parts are simple Blender Empty objects (for only it's X, Y and Z coordinates are needed) with custom properties that mark where things like ship's propulsion (it's a 3D shooter) are placed, or where the flames/explosions appear when ship's been shot. Those empty parts are also parented to either 'root' object or any of it's children. So far it's been working good, I have written a generic Operator class and some extended classes that reside in a panel which set part's properties (pretty handy since you don't have to add those custom properties by hand).
Now I want to speed thing up even more, that is to be able to simply click on an operator of desired type, and it should automatically add it to the scene and parent it to the active/selected object. I know how to do that, but I can't get those operators to change their labels. Basically, what I want is to operator to say 'Bullet point' when an existing empty is selected (I've got that part done), and when there's a mesh object selected to say 'Add bullet point'. So I just need a way to dynamically change operators' labels depending on the context (as the title of the question states clearly :))
This is what I got so far:
class OBJECT_OT_tg_generic (bpy.types.Operator):
bl_label = "Sets Generic Part Type"
bl_idname = "rbm.set_generic_part_type"
OB_TYPE = None
#classmethod
def poll (cls, context):
act = context.active_object
if 'Type' in act.keys ():
if act['Type'] == cls.OB_TYPE:
cls.bl_label = 'foo'
print (cls.bl_label)
# this prints foo but doesn't change the label
return False
return True
def execute (self, context):
# TODO: add code to automatically place empties and parent them to active object
bpy.context.active_object['Type'] = self.OB_TYPE
return{"FINISHED"}
And an example of a subclass:
class OBJECT_OT_tg_bullet_point (OBJECT_OT_tg_generic):
bl_label = "Bullet Point"
bl_idname = "rbm.set_bullet_point"
OB_TYPE = OT_BULLET_POINT
Here's how it looks in Blender:
http://i.imgur.com/46RAS.png
Guess I solved it. When you're adding an operator to a panel, you can do something like this:
def draw (self, context):
layout = self.layout
row = layout.row()
row.operator("foo.bar", text="Whatever you want")
and the "Whatever you want" is going to be your button's label. But what I did was something else. I didn't change the operators' labels, but instead gave them a different icons depending on whether it's a mesh or an empty currently selected/active:
def draw (self, context):
# (...) we're skipping some code here, obviously
act = context.active_object
if act.type == 'MESH':
op_icon = 'ZOOMIN'
else:
op_icon = 'EMPTY_DATA'
row = layout.column(align=True)
row.operator('rbm.set_bullet_point', icon=op_icon)
row.operator('rbm.set_rocket_point', icon=op_icon)
# (...) rest of the code