Sign in to follow this  
mrpeed

Which approach would be best for checking if an inventory is full in Python?

Recommended Posts

mrpeed    277

Here are 3 versions of a method from my inventory class that adds an item to the given inventory (or increases the items quantity). From a Python perspective, which approach would be best? Each method is followed by a sample of how I would use it in practice. I've been pretty interested in code design/architecture lately and I've been trying to get better at Python, so it may seem like a silly question but I'm just curious what you people think. Currently, I'm using approach #1, but I find it misleading that you could add an item and not actually have an item added. And if there's another approach not listed here that would be good please let me know.

#1 prevent adding item if is_full():
def add_item(self, item):
        i = next((i for i in self.items if i.tag == item.tag), None) #Duplicate item...
        if i is not None:
            i.quantity += item.quantity
        elif not self.is_full():
            self.items.append(item)

player_inventory.add_item(item)

#2 throw exception if is_full() and handle outside method:
def add_item(self, item):
        i = next((i for i in self.items if i.tag == item.tag), None)
        if i is not None:
            i.quantity += item.quantity
        elif not self.is_full():
            self.items.append(item)
        else: 
            raise InvetoryFullException("Inventory can only hold 8 items.")

try:			
	player_inventory.add_item(item)
except InvetoryFullException:
	pass
			
#3 check if inventory is_full() outside of method:
def add_item(self, item):
        i = next((i for i in self.items if i.tag == item.tag), None)
        if i is not None:
            i.quantity += item.quantity
        else:
            self.items.append(item)

if not player_inventory.is_full():
	player_inventory.items.append(item)

 

Edited by mrpeed

Share this post


Link to post
Share on other sites
mrpeed    277
9 hours ago, fastcall22 said:

items = dict()

Makes sense to use a dict actually, not sure why I went with a list.

9 hours ago, fastcall22 said:

@property def full(self): return len(self.items) >= self.max_inventory_size

Curious to why you decided to make this a property?

 

Also, what's your take on using an exception? As in my second example.

Share this post


Link to post
Share on other sites
Alberth    9530

Silently ignoring a request is a recipe for making buggy code, so I would strongly suggest you don't do that. Python also recommends that in the "Zen of Python" (type "import this" after the ">>>" prompt). "Explicit is better than implicit."

Making it testable before-hand, or returning "False" if it fails is a simple solution here. For something as simple as a full inventory, it's likely also enough. If you cannot store the item, something else must be done with it, and likely the best place to handle that problem is at the same spot in the code as where you tried (and failed) to insert the item into the inventory. An obvious thing to do is to put the item back where the player found it, for example.

An exception is a stronger failure, it is typically used when you're in real trouble. A file you loaded last time suddenly disappeared for example. The "return False" trick is a valid solution here too, but one level higher, there isn't much you can do about a missing file, so the only thing you can do is again "return False" to the next higher level, and so on, until you are somewhere near the top-level, where you know what files exist, you scratch the missing file, and you pick a new file to load.

When you raise an exception when you find the file missing instead, it does the above in one big step, it repeatedly exits the function, checks for a "catch", and if it doesn't exist, immediately exits that function too, etc, until it finds a "catch" statement that matches, or it reaches the main program (at which point the entire program ends). As such the raise is a substitute for the whole chain of
 

result = subfunction()
if not result: return False

that you'd have to write otherwise. It's a sort-of super-return.

Exceptions are quite controversial, there are disadvantages to them as well. Since you make big jumps from some innner-inner function back to some much higher function, all the variables that you have created and computations you have done in the functions between "raise" and "catch" are lost. You may not want that.

 

 

Share this post


Link to post
Share on other sites
Kylotan    10011
On 14/07/2017 at 5:38 AM, fastcall22 said:

Since the items are referred to by their tag, then it would be easier to use an associative array, such as `dict` or `collections.OrderedDict`.  Then, checking if the inventory is full is only a matter of checking the number of tags it has:


items = dict()

def is_full(self):
    return len(self.items) >= 8
    
...etc...

 

Slight amendment here; I would expect that to be more like:

def __init__():
    self.items = dict()
    
... other methods here, etc ...

 

Apart from that, I completely agree with this approach, and that the ability to add to the inventory should be checked explicitly with a function rather than handled with an exception. Exceptions are best saved for situations where it's not practical to easily check for the problem or to easily handle the problem where it's discovered.

Share this post


Link to post
Share on other sites
mrpeed    277
On 7/15/2017 at 6:26 AM, Kylotan said:

Slight amendment here; I would expect that to be more like:


def __init__():
    self.items = dict()
    
... other methods here, etc ...

 

Apart from that, I completely agree with this approach, and that the ability to add to the inventory should be checked explicitly with a function rather than handled with an exception. Exceptions are best saved for situations where it's not practical to easily check for the problem or to easily handle the problem where it's discovered.

Yes, I am initializing that in the __init__ method. And makes sense, I decided to remove the is_full() check from each method and have the inventory size enforced outside of the inventory class. This also removed a lot of clutter from my methods which is good.

I was wondering if you can clarify when to use properties? I tend to avoid them because I feel like they are misleading.

For example,

@property
    def full(self):
        return len(self.items) >= self.max_inventory_size

Doesn't this hide the fact that this is a method? Would a user not think this a regular variable and possibly try to assign to it? I have other methods labeled get and set throughout my code base that changes behavior within different classes. Would it be misleading to convert those to properties?

Another example, would it be to misleading to make this a next_sprite property?

def get_next_sprite(self):
        if self.current_count == self.max_count: #Time to switch sprites...
            self.current_count = 0
            self.current_sprite = next(self.sprite_reel)
        else: #Increment and return the same sprite from last frame...
            self.current_count += 1
        return self.current_sprite

 

Edited by mrpeed

Share this post


Link to post
Share on other sites
Kylotan    10011

Properties are intended to hide the fact that they are a method; whether you think that is a good idea or not is up to you. A reasonable middle-ground would be to use a property only where the hidden side-effects make sense in some way. I write entire Python programs without ever defining properties and I'm happy with that. And I see some popular Python packages that use properties in a way I don't agree with, but the world doesn't end. It's up to you.

Examples of 'good' candidates for properties, in my opinion, might be methods that fix up the incoming value on a set-property (e.g. changing a string to a unicode, or an integer to a float), or methods which wrap a more complex comparison (e.g. the 'is_full' concept)

And an example of a 'bad' candidate for properties might be methods that look like getters but which change the object state, e.g. by iterating over some internal collection. (So personally, I wouldn't like a 'next_sprite' property.)

I wouldn't worry about users wrongly thinking they can assign to a property that is read-only; Python code needs to be well-documented to be usable anyway due to the lack of type-checking, so you just need to note such properties accordingly.

Share this post


Link to post
Share on other sites
mrpeed    277
On 7/17/2017 at 5:13 AM, Kylotan said:

Examples of 'good' candidates for properties, in my opinion, might be methods that fix up the incoming value on a set-property (e.g. changing a string to a unicode, or an integer to a float), or methods which wrap a more complex comparison (e.g. the 'is_full' concept)

If I see no reason for something to be a property over a method should I favor making it a property or a method? For example, I can see no benefit in doing a "full" property over a "is_full() method", other than not having to write (). I can understand if full started as a regular variable and was expanded to a property later, but it wasn't. So in that case what would you say?

Share this post


Link to post
Share on other sites
Kylotan    10011

If you don't want to use properties, then don't. They just exist for convenience, to allow you to create things that act much like regular variables but which require a little extra logic.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this  

  • Partner Spotlight

  • Similar Content

    • By Java Nigga
      Hi there!
      We are JN Studios, we are looking for people to work with us in our project.
      About US:
      JN Studios is a 2 people amateur studio. we have like 1 year making games, but this is our first professional project to show it to the public. We are a programmer guy(Me) and a 3d modeller.
      About the game:
      Strategist Sniper is a RPG/FPS game, yes RPG and fps :v you awake in the middle of the unknown and a small voice tells you that you have to go through the world killing other snipers to get out of there. the mechanics of the game are based on the basic controls of games like League of Legends and in FPS games like Counter Strike.
      What we are looking for?
      actually we are looking for another c# programmer, a musician and an artist(for game illustrations for the marketing of the game).
      Profits Share:
      when the game is in a stable alpha phase we will create a campaign in Idiegogo to obtain money to finance the game. each of the project participants will receive a percentage depending on the work done.
      How to apply?
      just send us a email with a portfolio and in what you can help our team -       trabajojava1@gmail.com


      Devblog1.mp4
    • By GottoBlandat
      I'm making a twin stick shooter with a few friends in a course. The course unfortunately don't let us make any game we want without some research or statistics backing it up. So i was hoping some would like to answer a survey about the design of the game.
      https://goo.gl/forms/9oQ4htAPjzzRNGUs2
    • By Seer
      For a sprite based 2D RPG style game, how should assets such as textures, animations, music and sound effects be distributed to and accessed by game objects?
      Assuming you have a resource manager dedicated to loading and containing the resources, should this manager be passed indiscriminately to wherever there is a need for a resource(s)?
      Should the resource manager segregate various textures and animations from sprite sheets as they are loaded and hold segregated sets (maps/lists) of these textures and animations based on a pre-determined need by different game objects so that they can be quickly set up? By this I mean, where you are certain object A needs only a set of X animations and Y sound effects throughout the lifetime of the program.
      If all textures, animations, music and sound effects should not be segregated as they are loaded and should instead each be stored in one big container of their respective type for all objects to freely choose from, how should the objects retrieve the resources they need efficiently and with minimal lines of code? Any object could hold any combination of textures, animations or sound effects held by the resource manager. I believe it would be easy with this approach to have very many lines of code dedicated to retrieving all the resources an object will need, for every object.
      Finally, should objects hold resources at all? At this point I don't see why objects shouldn't hold their own graphical resources since the objects contain the data such as position, width and height that the resources would need in order to be rendered correctly. However, I'm not so sure about resources such as sound effects, since these types of resources don't need any information from the object in order to play. Should they be held and controlled elsewhere, by dedicated music and sound effect playing systems?
       
       
    • By WinterDragon
      My first goal is to build in python a text-based (next version will have graphics) adventure game scenario where a player enters a tavern, and goes on a quest. Earns money, buys weapons and gets in a fight.
       
      So I've got four ideas for games I want to build.
      1. a space simulation where a mute evolving clique is tasked with colonising planets - it's also a social network.
      My next goal is to build a 3rd person shooter and streets of rage style framework for a action/adventure game based on my story which is about God's mightiest heroes (with mutation sandbox) versus the devil (read pinhead meets bizarro superman).
      I also want to build in python, a 3d isometric rpg/sim that looks like the sims 1 but thematically is more like Bully or GTA1, but plays like Hell's Kitchen DS combined with Dofus, with environments combining elements of Phantasy Star, Sonic and art photography of convenience stores, etc.
      I also want to build an epic adventure story in RPGMakerMV.
      Any advice as to what else I should build in between to get closer to my goal projects.
       
      In a few weeks I'll have my first game, I'm not really sure how to turn it into an executable file so i can share it with people who don't have python installed.
    • By rafael rodriguez
      Hello everyone! First if you are taking the time to read this "Thank You!" I'm new to programming (Java and C), and I would like to learn/practice more by making a Text-Based RPG. I have an idea in mind and I kinda started to code it in Java but I'm not sure how to put my bits of code together and would like some help. I'm not asking to make the game for me, but to guide me in the right direction... maybe some books, tutorials or even some one on one if you don't mind.
      The game I have in mind is going to contain:
      A player, world, leveling system, melee combat system(with some skills), monsters, inventory system, intractable objects(like a tree that you can cut down), item storage system, NPC's that interact maybe a store or something, and a saving and loading system.
      After that maybe I would like to add some more Non-Combat skills, a mage and range combat system along with some more skills, and make the world a bit larger with some interesting stuff in it...
      Anyways that's a lot so thank you for taking your time to read this, let me know if I can explain anything better or if I didn't explain something enough!
  • Popular Now