Select the object with a larger value of a specific attribute












0















I just started learning python so I'm not familiar with the various tricks or tools, or the proper way to word my question. Because of that, I was unable to find previous questions that do what I am looking for.



I have a working code outlined here:



import random

class UserGroup:
def __init__(self, users):
self.user_list = users

def random_users(self):
self.random_1 = random.choice(self.user_list)
self.random_2 = self.random_1
while self.random_2 == self.random_1:
self.random_2 = random.choice(self.user_list)
return self.random_1, self.random_2

class User:
def __init__(self, nickname, stats):
self.nickname = nickname
self.strength = stats['strength']
self.constitution = stats['constitution']
self.dexterity = stats['dexterity']
self.intelligence = stats['intelligence']
self.wisdom = stats['wisdom']
self.charisma = stats['charisma']

def __repr__(self):
return self.nickname

class Jared(User):
def fight_stat(self):
self.attack = self.strength + self.intelligence
self.defense = self.constitution * 2
self.speed = self.dexterity / 2

class Poptart(User):
def fight_stat(self):
self.attack = self.strength + self.dexterity
self.defense = self.dexterity
self.speed = self.dexterity + self.charisma

class Kaos(User):
def fight_stat(self):
self.attack = self.dexterity + self.wisdom
self.defense = self.wisdom * 2
self.speed = self.dexterity

class Magda(User):
def fight_stat(self):
self.attack = self.intelligence + self.charisma
self.defense = self.dexterity + self.charisma
self.speed = self.dexterity + self.constitution / 2

class Battle:
def __init__(self, user1, user2):
self.user1 = user1
self.user2 = user2
print(user1, "and", user2, "have entered the fight!")

def fight(self):
self.user1.fight_stat()
self.user2.fight_stat()
if self.user1.speed > self.user2.speed:
self.attacker = self.user1
self.defender = self.user2
elif self.user2.speed > self.user1.speed:
self.attacker = self.user2
self.defender = self.user1
elif self.user1.dexterity > self.user2.dexterity:
self.attacker = self.user1
self.defender = self.user2
else:
self.attacker = self.user2
self.defender = self.user1
if self.attacker.attack > self.defender.defense:
return self.attacker
elif self.defender.attack > self.attacker.defense:
return self.defender
else:
return "Draw"

# HERE STARTS BATTLE CODE
jared = Jared('Jarebear', {'strength': 7, 'constitution': 6, 'dexterity': 6, 'intelligence': 8, 'wisdom': 5, 'charisma': 5})
poptart = Poptart('Yung SLizzy', {'strength': 4, 'constitution': 5, 'dexterity': 10, 'intelligence': 7, 'wisdom': 5, 'charisma': 7})
kaos = Kaos('Kung Cows', {'strength': 8, 'constitution': 7, 'dexterity': 6, 'intelligence': 4, 'wisdom': 7, 'charisma': 4})
magda = Magda('Meghan M', {'strength': 7, 'constitution': 5, 'dexterity': 7, 'intelligence': 8, 'wisdom': 5, 'charisma': 5})

users = UserGroup([jared, poptart, kaos, magda])

for i in range(1,4):
print("Battle number", i)
battle = Battle(*users.random_users())
print("The winner is: ", battle.fight())


The example output is shown below:



Battle number 1
Jarebear and Kung Cows have entered the fight!
The winner is: Kung Cows
Battle number 2
Jarebear and Kung Cows have entered the fight!
The winner is: Kung Cows
Battle number 3


As I have written it, the code performs as expected. However, I am concerned about the way that I've implemented the fight() method inside the Battle class. I don't think the large sequence of if statements is the proper way to say "user with higher speed attacks first". Logically, I just need a statement that is like self.attacker = max(self.user1.speed, self.user2.speed) but the attacker is set to the user, not the user's speed. However, I don't know how to accomplish this in one or two lines of code in python.










share|improve this question

























  • Try self.attacker = max(self.user1, self.user2, key=lambda u: u.speed). The only issue is that it will favor user1 when the speed of user1 and user2 are the same.

    – John Szakmeister
    Jan 2 at 1:27













  • in my if/else statements I have it look at the dexterity if speed happens to be the same. Any way to include that?

    – Jared C
    Jan 2 at 1:31











  • why not create a def who_goes_first(user1,user2) method - put your logic into it and if they draw, choose one randomly? cleans up your fight code, creates a funciton with low reason to change and makes it more obvious whats happening?

    – Patrick Artner
    Jan 2 at 1:34











  • I felt if I move the if/else statements into yet another function, that I would just be over-engineering what should be a simple solution

    – Jared C
    Jan 2 at 1:35











  • @JaredC yes, just return a tuple of what you want out of the lambda function. In this case, it would be: self.attacker = max(self.user1, self.user2, key=lambda u: (u.speed, u.dexterity)) I do recommend the suggestion about factoring the logic out into it's own method. As a seasoned developer (20+ years of experience), I would not call it over-engineering, I'd call it making it readable and providing logical separation of responsibilities. :-)

    – John Szakmeister
    Jan 2 at 9:31
















0















I just started learning python so I'm not familiar with the various tricks or tools, or the proper way to word my question. Because of that, I was unable to find previous questions that do what I am looking for.



I have a working code outlined here:



import random

class UserGroup:
def __init__(self, users):
self.user_list = users

def random_users(self):
self.random_1 = random.choice(self.user_list)
self.random_2 = self.random_1
while self.random_2 == self.random_1:
self.random_2 = random.choice(self.user_list)
return self.random_1, self.random_2

class User:
def __init__(self, nickname, stats):
self.nickname = nickname
self.strength = stats['strength']
self.constitution = stats['constitution']
self.dexterity = stats['dexterity']
self.intelligence = stats['intelligence']
self.wisdom = stats['wisdom']
self.charisma = stats['charisma']

def __repr__(self):
return self.nickname

class Jared(User):
def fight_stat(self):
self.attack = self.strength + self.intelligence
self.defense = self.constitution * 2
self.speed = self.dexterity / 2

class Poptart(User):
def fight_stat(self):
self.attack = self.strength + self.dexterity
self.defense = self.dexterity
self.speed = self.dexterity + self.charisma

class Kaos(User):
def fight_stat(self):
self.attack = self.dexterity + self.wisdom
self.defense = self.wisdom * 2
self.speed = self.dexterity

class Magda(User):
def fight_stat(self):
self.attack = self.intelligence + self.charisma
self.defense = self.dexterity + self.charisma
self.speed = self.dexterity + self.constitution / 2

class Battle:
def __init__(self, user1, user2):
self.user1 = user1
self.user2 = user2
print(user1, "and", user2, "have entered the fight!")

def fight(self):
self.user1.fight_stat()
self.user2.fight_stat()
if self.user1.speed > self.user2.speed:
self.attacker = self.user1
self.defender = self.user2
elif self.user2.speed > self.user1.speed:
self.attacker = self.user2
self.defender = self.user1
elif self.user1.dexterity > self.user2.dexterity:
self.attacker = self.user1
self.defender = self.user2
else:
self.attacker = self.user2
self.defender = self.user1
if self.attacker.attack > self.defender.defense:
return self.attacker
elif self.defender.attack > self.attacker.defense:
return self.defender
else:
return "Draw"

# HERE STARTS BATTLE CODE
jared = Jared('Jarebear', {'strength': 7, 'constitution': 6, 'dexterity': 6, 'intelligence': 8, 'wisdom': 5, 'charisma': 5})
poptart = Poptart('Yung SLizzy', {'strength': 4, 'constitution': 5, 'dexterity': 10, 'intelligence': 7, 'wisdom': 5, 'charisma': 7})
kaos = Kaos('Kung Cows', {'strength': 8, 'constitution': 7, 'dexterity': 6, 'intelligence': 4, 'wisdom': 7, 'charisma': 4})
magda = Magda('Meghan M', {'strength': 7, 'constitution': 5, 'dexterity': 7, 'intelligence': 8, 'wisdom': 5, 'charisma': 5})

users = UserGroup([jared, poptart, kaos, magda])

for i in range(1,4):
print("Battle number", i)
battle = Battle(*users.random_users())
print("The winner is: ", battle.fight())


The example output is shown below:



Battle number 1
Jarebear and Kung Cows have entered the fight!
The winner is: Kung Cows
Battle number 2
Jarebear and Kung Cows have entered the fight!
The winner is: Kung Cows
Battle number 3


As I have written it, the code performs as expected. However, I am concerned about the way that I've implemented the fight() method inside the Battle class. I don't think the large sequence of if statements is the proper way to say "user with higher speed attacks first". Logically, I just need a statement that is like self.attacker = max(self.user1.speed, self.user2.speed) but the attacker is set to the user, not the user's speed. However, I don't know how to accomplish this in one or two lines of code in python.










share|improve this question

























  • Try self.attacker = max(self.user1, self.user2, key=lambda u: u.speed). The only issue is that it will favor user1 when the speed of user1 and user2 are the same.

    – John Szakmeister
    Jan 2 at 1:27













  • in my if/else statements I have it look at the dexterity if speed happens to be the same. Any way to include that?

    – Jared C
    Jan 2 at 1:31











  • why not create a def who_goes_first(user1,user2) method - put your logic into it and if they draw, choose one randomly? cleans up your fight code, creates a funciton with low reason to change and makes it more obvious whats happening?

    – Patrick Artner
    Jan 2 at 1:34











  • I felt if I move the if/else statements into yet another function, that I would just be over-engineering what should be a simple solution

    – Jared C
    Jan 2 at 1:35











  • @JaredC yes, just return a tuple of what you want out of the lambda function. In this case, it would be: self.attacker = max(self.user1, self.user2, key=lambda u: (u.speed, u.dexterity)) I do recommend the suggestion about factoring the logic out into it's own method. As a seasoned developer (20+ years of experience), I would not call it over-engineering, I'd call it making it readable and providing logical separation of responsibilities. :-)

    – John Szakmeister
    Jan 2 at 9:31














0












0








0


1






I just started learning python so I'm not familiar with the various tricks or tools, or the proper way to word my question. Because of that, I was unable to find previous questions that do what I am looking for.



I have a working code outlined here:



import random

class UserGroup:
def __init__(self, users):
self.user_list = users

def random_users(self):
self.random_1 = random.choice(self.user_list)
self.random_2 = self.random_1
while self.random_2 == self.random_1:
self.random_2 = random.choice(self.user_list)
return self.random_1, self.random_2

class User:
def __init__(self, nickname, stats):
self.nickname = nickname
self.strength = stats['strength']
self.constitution = stats['constitution']
self.dexterity = stats['dexterity']
self.intelligence = stats['intelligence']
self.wisdom = stats['wisdom']
self.charisma = stats['charisma']

def __repr__(self):
return self.nickname

class Jared(User):
def fight_stat(self):
self.attack = self.strength + self.intelligence
self.defense = self.constitution * 2
self.speed = self.dexterity / 2

class Poptart(User):
def fight_stat(self):
self.attack = self.strength + self.dexterity
self.defense = self.dexterity
self.speed = self.dexterity + self.charisma

class Kaos(User):
def fight_stat(self):
self.attack = self.dexterity + self.wisdom
self.defense = self.wisdom * 2
self.speed = self.dexterity

class Magda(User):
def fight_stat(self):
self.attack = self.intelligence + self.charisma
self.defense = self.dexterity + self.charisma
self.speed = self.dexterity + self.constitution / 2

class Battle:
def __init__(self, user1, user2):
self.user1 = user1
self.user2 = user2
print(user1, "and", user2, "have entered the fight!")

def fight(self):
self.user1.fight_stat()
self.user2.fight_stat()
if self.user1.speed > self.user2.speed:
self.attacker = self.user1
self.defender = self.user2
elif self.user2.speed > self.user1.speed:
self.attacker = self.user2
self.defender = self.user1
elif self.user1.dexterity > self.user2.dexterity:
self.attacker = self.user1
self.defender = self.user2
else:
self.attacker = self.user2
self.defender = self.user1
if self.attacker.attack > self.defender.defense:
return self.attacker
elif self.defender.attack > self.attacker.defense:
return self.defender
else:
return "Draw"

# HERE STARTS BATTLE CODE
jared = Jared('Jarebear', {'strength': 7, 'constitution': 6, 'dexterity': 6, 'intelligence': 8, 'wisdom': 5, 'charisma': 5})
poptart = Poptart('Yung SLizzy', {'strength': 4, 'constitution': 5, 'dexterity': 10, 'intelligence': 7, 'wisdom': 5, 'charisma': 7})
kaos = Kaos('Kung Cows', {'strength': 8, 'constitution': 7, 'dexterity': 6, 'intelligence': 4, 'wisdom': 7, 'charisma': 4})
magda = Magda('Meghan M', {'strength': 7, 'constitution': 5, 'dexterity': 7, 'intelligence': 8, 'wisdom': 5, 'charisma': 5})

users = UserGroup([jared, poptart, kaos, magda])

for i in range(1,4):
print("Battle number", i)
battle = Battle(*users.random_users())
print("The winner is: ", battle.fight())


The example output is shown below:



Battle number 1
Jarebear and Kung Cows have entered the fight!
The winner is: Kung Cows
Battle number 2
Jarebear and Kung Cows have entered the fight!
The winner is: Kung Cows
Battle number 3


As I have written it, the code performs as expected. However, I am concerned about the way that I've implemented the fight() method inside the Battle class. I don't think the large sequence of if statements is the proper way to say "user with higher speed attacks first". Logically, I just need a statement that is like self.attacker = max(self.user1.speed, self.user2.speed) but the attacker is set to the user, not the user's speed. However, I don't know how to accomplish this in one or two lines of code in python.










share|improve this question
















I just started learning python so I'm not familiar with the various tricks or tools, or the proper way to word my question. Because of that, I was unable to find previous questions that do what I am looking for.



I have a working code outlined here:



import random

class UserGroup:
def __init__(self, users):
self.user_list = users

def random_users(self):
self.random_1 = random.choice(self.user_list)
self.random_2 = self.random_1
while self.random_2 == self.random_1:
self.random_2 = random.choice(self.user_list)
return self.random_1, self.random_2

class User:
def __init__(self, nickname, stats):
self.nickname = nickname
self.strength = stats['strength']
self.constitution = stats['constitution']
self.dexterity = stats['dexterity']
self.intelligence = stats['intelligence']
self.wisdom = stats['wisdom']
self.charisma = stats['charisma']

def __repr__(self):
return self.nickname

class Jared(User):
def fight_stat(self):
self.attack = self.strength + self.intelligence
self.defense = self.constitution * 2
self.speed = self.dexterity / 2

class Poptart(User):
def fight_stat(self):
self.attack = self.strength + self.dexterity
self.defense = self.dexterity
self.speed = self.dexterity + self.charisma

class Kaos(User):
def fight_stat(self):
self.attack = self.dexterity + self.wisdom
self.defense = self.wisdom * 2
self.speed = self.dexterity

class Magda(User):
def fight_stat(self):
self.attack = self.intelligence + self.charisma
self.defense = self.dexterity + self.charisma
self.speed = self.dexterity + self.constitution / 2

class Battle:
def __init__(self, user1, user2):
self.user1 = user1
self.user2 = user2
print(user1, "and", user2, "have entered the fight!")

def fight(self):
self.user1.fight_stat()
self.user2.fight_stat()
if self.user1.speed > self.user2.speed:
self.attacker = self.user1
self.defender = self.user2
elif self.user2.speed > self.user1.speed:
self.attacker = self.user2
self.defender = self.user1
elif self.user1.dexterity > self.user2.dexterity:
self.attacker = self.user1
self.defender = self.user2
else:
self.attacker = self.user2
self.defender = self.user1
if self.attacker.attack > self.defender.defense:
return self.attacker
elif self.defender.attack > self.attacker.defense:
return self.defender
else:
return "Draw"

# HERE STARTS BATTLE CODE
jared = Jared('Jarebear', {'strength': 7, 'constitution': 6, 'dexterity': 6, 'intelligence': 8, 'wisdom': 5, 'charisma': 5})
poptart = Poptart('Yung SLizzy', {'strength': 4, 'constitution': 5, 'dexterity': 10, 'intelligence': 7, 'wisdom': 5, 'charisma': 7})
kaos = Kaos('Kung Cows', {'strength': 8, 'constitution': 7, 'dexterity': 6, 'intelligence': 4, 'wisdom': 7, 'charisma': 4})
magda = Magda('Meghan M', {'strength': 7, 'constitution': 5, 'dexterity': 7, 'intelligence': 8, 'wisdom': 5, 'charisma': 5})

users = UserGroup([jared, poptart, kaos, magda])

for i in range(1,4):
print("Battle number", i)
battle = Battle(*users.random_users())
print("The winner is: ", battle.fight())


The example output is shown below:



Battle number 1
Jarebear and Kung Cows have entered the fight!
The winner is: Kung Cows
Battle number 2
Jarebear and Kung Cows have entered the fight!
The winner is: Kung Cows
Battle number 3


As I have written it, the code performs as expected. However, I am concerned about the way that I've implemented the fight() method inside the Battle class. I don't think the large sequence of if statements is the proper way to say "user with higher speed attacks first". Logically, I just need a statement that is like self.attacker = max(self.user1.speed, self.user2.speed) but the attacker is set to the user, not the user's speed. However, I don't know how to accomplish this in one or two lines of code in python.







python






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Jan 2 at 1:56









Mad Physicist

38k1674107




38k1674107










asked Jan 2 at 1:14









Jared CJared C

230213




230213













  • Try self.attacker = max(self.user1, self.user2, key=lambda u: u.speed). The only issue is that it will favor user1 when the speed of user1 and user2 are the same.

    – John Szakmeister
    Jan 2 at 1:27













  • in my if/else statements I have it look at the dexterity if speed happens to be the same. Any way to include that?

    – Jared C
    Jan 2 at 1:31











  • why not create a def who_goes_first(user1,user2) method - put your logic into it and if they draw, choose one randomly? cleans up your fight code, creates a funciton with low reason to change and makes it more obvious whats happening?

    – Patrick Artner
    Jan 2 at 1:34











  • I felt if I move the if/else statements into yet another function, that I would just be over-engineering what should be a simple solution

    – Jared C
    Jan 2 at 1:35











  • @JaredC yes, just return a tuple of what you want out of the lambda function. In this case, it would be: self.attacker = max(self.user1, self.user2, key=lambda u: (u.speed, u.dexterity)) I do recommend the suggestion about factoring the logic out into it's own method. As a seasoned developer (20+ years of experience), I would not call it over-engineering, I'd call it making it readable and providing logical separation of responsibilities. :-)

    – John Szakmeister
    Jan 2 at 9:31



















  • Try self.attacker = max(self.user1, self.user2, key=lambda u: u.speed). The only issue is that it will favor user1 when the speed of user1 and user2 are the same.

    – John Szakmeister
    Jan 2 at 1:27













  • in my if/else statements I have it look at the dexterity if speed happens to be the same. Any way to include that?

    – Jared C
    Jan 2 at 1:31











  • why not create a def who_goes_first(user1,user2) method - put your logic into it and if they draw, choose one randomly? cleans up your fight code, creates a funciton with low reason to change and makes it more obvious whats happening?

    – Patrick Artner
    Jan 2 at 1:34











  • I felt if I move the if/else statements into yet another function, that I would just be over-engineering what should be a simple solution

    – Jared C
    Jan 2 at 1:35











  • @JaredC yes, just return a tuple of what you want out of the lambda function. In this case, it would be: self.attacker = max(self.user1, self.user2, key=lambda u: (u.speed, u.dexterity)) I do recommend the suggestion about factoring the logic out into it's own method. As a seasoned developer (20+ years of experience), I would not call it over-engineering, I'd call it making it readable and providing logical separation of responsibilities. :-)

    – John Szakmeister
    Jan 2 at 9:31

















Try self.attacker = max(self.user1, self.user2, key=lambda u: u.speed). The only issue is that it will favor user1 when the speed of user1 and user2 are the same.

– John Szakmeister
Jan 2 at 1:27







Try self.attacker = max(self.user1, self.user2, key=lambda u: u.speed). The only issue is that it will favor user1 when the speed of user1 and user2 are the same.

– John Szakmeister
Jan 2 at 1:27















in my if/else statements I have it look at the dexterity if speed happens to be the same. Any way to include that?

– Jared C
Jan 2 at 1:31





in my if/else statements I have it look at the dexterity if speed happens to be the same. Any way to include that?

– Jared C
Jan 2 at 1:31













why not create a def who_goes_first(user1,user2) method - put your logic into it and if they draw, choose one randomly? cleans up your fight code, creates a funciton with low reason to change and makes it more obvious whats happening?

– Patrick Artner
Jan 2 at 1:34





why not create a def who_goes_first(user1,user2) method - put your logic into it and if they draw, choose one randomly? cleans up your fight code, creates a funciton with low reason to change and makes it more obvious whats happening?

– Patrick Artner
Jan 2 at 1:34













I felt if I move the if/else statements into yet another function, that I would just be over-engineering what should be a simple solution

– Jared C
Jan 2 at 1:35





I felt if I move the if/else statements into yet another function, that I would just be over-engineering what should be a simple solution

– Jared C
Jan 2 at 1:35













@JaredC yes, just return a tuple of what you want out of the lambda function. In this case, it would be: self.attacker = max(self.user1, self.user2, key=lambda u: (u.speed, u.dexterity)) I do recommend the suggestion about factoring the logic out into it's own method. As a seasoned developer (20+ years of experience), I would not call it over-engineering, I'd call it making it readable and providing logical separation of responsibilities. :-)

– John Szakmeister
Jan 2 at 9:31





@JaredC yes, just return a tuple of what you want out of the lambda function. In this case, it would be: self.attacker = max(self.user1, self.user2, key=lambda u: (u.speed, u.dexterity)) I do recommend the suggestion about factoring the logic out into it's own method. As a seasoned developer (20+ years of experience), I would not call it over-engineering, I'd call it making it readable and providing logical separation of responsibilities. :-)

– John Szakmeister
Jan 2 at 9:31












7 Answers
7






active

oldest

votes


















1














Creating small methods that concentrate logic is no "overhead". They are easy to understand, and do not need to change for lots of reasons - hence they are done, testet and unchanged most of the time.



class Battle:

# snipped some code

@staticmethod
def get_attacker_defender(u1, u2):
"""Returs tuple (attacker,defender) based on given user."""
if u1.speed > u2.speed:
return u1,u2
elif u2.speed > u1.speed:
return u2,u1
# probably cleaner to stay with elif: ... else ... but this is shorter
return (u1,u2) if u1.dexterity > u2.dexterity else (u2,u1)


def fight(self):
self.user1.fight_stat()
self.user2.fight_stat()
self.attacker, self.defender = Battle.get_attacker_defender(self.user1,self.user2)

if self.attacker.attack > self.defender.defense:
return self.attacker
elif self.defender.attack > self.attacker.defense:
return self.defender
else:
return "Draw"




If you like a brain teaser you could as well do:



@staticmethod
def get_attacker_defender(u1,u2):
return sorted( [u1,u2], key = lambda u:(u.speed,u.dexterity), reverse=True)


which leverages tuple-sorting that sorts based on the 1st element, and when the 1st ones are equal on the 2nd element of the tuple. If both are equal the order stays as is (stable sorting with Timsort).



Doku:





  • Does Python have a ternary conditional operator? (for return .. if ... else ...)

  • sorted(... with key and reversed ...)

  • Why are Python lambdas useful?






share|improve this answer


























  • If I can learn to understand and use the "brain teaser" then I think I will become a better programmer

    – Jared C
    Jan 2 at 1:51











  • @JaredC you might - but it will make the code only shorter - not cleaner

    – Patrick Artner
    Jan 2 at 1:52











  • There has been a wealth of knowledge offered in response to my question, and I think I can take things from every answer and improve my understanding of python. This is the answer which best fits my specific needs, although many of the answers presented could be used to achieve the desired results.

    – Jared C
    Jan 2 at 12:54



















3














The min and max functions accept a key function that tells them how to compare the inputs. The key accepts each input and returns the actual value to compare:



max(self.user1, self.user2, key=lambda item: item.speed)


For a large number of comparisons, this can be rewritten as



from operator import attrgetter

speed_key = attrgetter('speed')
max(self.user1, self.user2, key=speed_key)


If you have equal speeds, you can decide to compare using a different attribute. This is done by understanding that Python sequences are compared in lexicographixal order. This is easiest to understand with strings, since it's basically just dictionary order: e.g. 'abc' > 'abb' because each element is compared in order. The same applies to lists and tuples: [1, 2, 3] > [1, 2, 2].



So to use the dexterity attribute as a fallback for equal speeds, do



max(self.user1, self.user2, key=lambda item: (item.speed, item.dexterity))


OR



speedex_key = attrgetter('speed', 'dexterity')
max(self.user1, self.user2, key=speedex_key)





share|improve this answer































    1














    If you want to use max with your objects, you can implement __gt__ com compare them (and __eq__ for consistency). So your User class could look like this:



    class User:
    def __init__(self, nickname, stats):
    self.nickname = nickname
    self.strength = stats['strength']
    self.constitution = stats['constitution']
    self.dexterity = stats['dexterity']
    self.intelligence = stats['intelligence']
    self.wisdom = stats['wisdom']
    self.charisma = stats['charisma']

    def __repr__(self):
    return self.nickname

    def __eq__(self, other):
    return self.speed == other.speed and self.dexterity == other.dexterity

    def __gt__(self, other):
    return self.speed > other.speed or self.dexterity > other.dexterity


    This implementation would allow you to use max and min to define the attacker and defender in the Battle class.



    class Battle:
    def __init__(self, user1, user2):
    self.user1 = user1
    self.user2 = user2
    print(user1, "and", user2, "have entered the fight!")

    def fight(self):
    self.user1.fight_stat()
    self.user2.fight_stat()

    self.attacker = max(self.user1, self.user2)
    self.defender = min(self.user1, self.user2)

    if self.attacker.attack > self.defender.defense:
    return self.attacker
    elif self.defender.attack > self.attacker.defense:
    return self.defender
    else:
    return "Draw"





    share|improve this answer































      0















      I just need a statement that is like self.attacker =
      max(self.user1.speed, self.user2.speed) but the attacker is set to the
      user, not the user's speed.




      You can use



      from operator import attrgetter
      ...
      self.attacker = max(self.user1, self.user2, key=attrgetter('speed'))


      This will return the user (not speed) has max speed



      If you have more than 2 users, you can also pass list



      More information about attrgetter






      share|improve this answer
























      • Is there a way to have it check the dexterity score (or just select one at random) if the speed of the users is the same?

        – Jared C
        Jan 2 at 1:36



















      0














      You can indeed use max() to get the user with most speed.



      The way of doing it is with the keyargument which you use to pass a custom scoring function that takes each object and returns a orderable value like a float or int.



      def score(user):
      return user.speed

      fastest_user = max(list_of_users, key=score)


      The most common is to pass an anonymous lambda function which you define with the syntax:



      lambda var1, var2: expression


      So the code would look like:



      fastest_user = max(list_of_users, key=lambda user: user.speed)





      share|improve this answer


























      • Is there a way to have it check the dexterity score (or just select one at random) if the speed of the users is the same?

        – Jared C
        Jan 2 at 1:36











      • Max will just return the first element if all the users have the same speed, so shuffling the list before should do the trick. for that just do from random import shuffle and use that function to mess the list before.

        – Jeacom
        Jan 2 at 1:43



















      0














      Here is an answer that separates the logic as was mentioned above, and uses your original max desire. The benefit to this solution is that logic to determine first attack could be easily refactored. Simply change the order (or add attributes to) attribute_priority_order



      class Battle:
      def __init__(self, user1, user2):
      self.user1 = user1
      self.user2 = user2
      print(user1, "and", user2, "have entered the fight!")


      @staticmethod
      def _compare_attributes(user1: User, user2: User, attribute: str):
      if getattr(user1, attribute) != getattr(user2, attribute):
      return max(
      [user1, user2],
      key=lambda user: getattr(user, attribute)
      )

      def get_attacker(self):
      """
      Returns attacker based on attribute comparison
      :return: User
      """
      default_attacker = self.user2
      attribute_priority_order = [
      'speed',
      'dexterity'
      ]

      for attribute in attribute_priority_order:
      attacker = self._compare_attributes(
      user1=self.user1,
      user2=self.user2,
      attribute=attribute
      )
      if attacker:
      return attacker

      return default_attacker

      def get_defender(self):
      """
      User in the battle that isn't the attacker.
      :return: User
      """
      for user in [self.user1, self.user2]:
      if str(user) != str(self.attacker):
      return user


      def fight(self):
      self.user1.fight_stat()
      self.user2.fight_stat()

      self.attacker = self.get_attacker()
      self.defender = self.get_defender()

      if self.attacker.attack > self.defender.defense:
      return self.attacker
      elif self.defender.attack > self.attacker.defense:
      return self.defender
      else:
      return "Draw"


      With a little extra abstraction, _compare_attributes method could be recycled to determine the winner as well maybe with an optional second attribute. The return from this method is optionally a user if there is no tie.






      share|improve this answer

































        0














        How about using the fact that python lists compare so your ability measure is:



        def ability(user):
        return (user.speed, user.dexterity)


        Your winning criteria is:



        def winner(attacker, defender):
        return attacker.attack > defender.defense


        And the fight becomes:



        def fight(a, b):
        return winner(a, b) if ability(a) >= ability(b) else winner(b, a)





        share|improve this answer























          Your Answer






          StackExchange.ifUsing("editor", function () {
          StackExchange.using("externalEditor", function () {
          StackExchange.using("snippets", function () {
          StackExchange.snippets.init();
          });
          });
          }, "code-snippets");

          StackExchange.ready(function() {
          var channelOptions = {
          tags: "".split(" "),
          id: "1"
          };
          initTagRenderer("".split(" "), "".split(" "), channelOptions);

          StackExchange.using("externalEditor", function() {
          // Have to fire editor after snippets, if snippets enabled
          if (StackExchange.settings.snippets.snippetsEnabled) {
          StackExchange.using("snippets", function() {
          createEditor();
          });
          }
          else {
          createEditor();
          }
          });

          function createEditor() {
          StackExchange.prepareEditor({
          heartbeatType: 'answer',
          autoActivateHeartbeat: false,
          convertImagesToLinks: true,
          noModals: true,
          showLowRepImageUploadWarning: true,
          reputationToPostImages: 10,
          bindNavPrevention: true,
          postfix: "",
          imageUploader: {
          brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
          contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
          allowUrls: true
          },
          onDemand: true,
          discardSelector: ".discard-answer"
          ,immediatelyShowMarkdownHelp:true
          });


          }
          });














          draft saved

          draft discarded


















          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54000219%2fselect-the-object-with-a-larger-value-of-a-specific-attribute%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown

























          7 Answers
          7






          active

          oldest

          votes








          7 Answers
          7






          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes









          1














          Creating small methods that concentrate logic is no "overhead". They are easy to understand, and do not need to change for lots of reasons - hence they are done, testet and unchanged most of the time.



          class Battle:

          # snipped some code

          @staticmethod
          def get_attacker_defender(u1, u2):
          """Returs tuple (attacker,defender) based on given user."""
          if u1.speed > u2.speed:
          return u1,u2
          elif u2.speed > u1.speed:
          return u2,u1
          # probably cleaner to stay with elif: ... else ... but this is shorter
          return (u1,u2) if u1.dexterity > u2.dexterity else (u2,u1)


          def fight(self):
          self.user1.fight_stat()
          self.user2.fight_stat()
          self.attacker, self.defender = Battle.get_attacker_defender(self.user1,self.user2)

          if self.attacker.attack > self.defender.defense:
          return self.attacker
          elif self.defender.attack > self.attacker.defense:
          return self.defender
          else:
          return "Draw"




          If you like a brain teaser you could as well do:



          @staticmethod
          def get_attacker_defender(u1,u2):
          return sorted( [u1,u2], key = lambda u:(u.speed,u.dexterity), reverse=True)


          which leverages tuple-sorting that sorts based on the 1st element, and when the 1st ones are equal on the 2nd element of the tuple. If both are equal the order stays as is (stable sorting with Timsort).



          Doku:





          • Does Python have a ternary conditional operator? (for return .. if ... else ...)

          • sorted(... with key and reversed ...)

          • Why are Python lambdas useful?






          share|improve this answer


























          • If I can learn to understand and use the "brain teaser" then I think I will become a better programmer

            – Jared C
            Jan 2 at 1:51











          • @JaredC you might - but it will make the code only shorter - not cleaner

            – Patrick Artner
            Jan 2 at 1:52











          • There has been a wealth of knowledge offered in response to my question, and I think I can take things from every answer and improve my understanding of python. This is the answer which best fits my specific needs, although many of the answers presented could be used to achieve the desired results.

            – Jared C
            Jan 2 at 12:54
















          1














          Creating small methods that concentrate logic is no "overhead". They are easy to understand, and do not need to change for lots of reasons - hence they are done, testet and unchanged most of the time.



          class Battle:

          # snipped some code

          @staticmethod
          def get_attacker_defender(u1, u2):
          """Returs tuple (attacker,defender) based on given user."""
          if u1.speed > u2.speed:
          return u1,u2
          elif u2.speed > u1.speed:
          return u2,u1
          # probably cleaner to stay with elif: ... else ... but this is shorter
          return (u1,u2) if u1.dexterity > u2.dexterity else (u2,u1)


          def fight(self):
          self.user1.fight_stat()
          self.user2.fight_stat()
          self.attacker, self.defender = Battle.get_attacker_defender(self.user1,self.user2)

          if self.attacker.attack > self.defender.defense:
          return self.attacker
          elif self.defender.attack > self.attacker.defense:
          return self.defender
          else:
          return "Draw"




          If you like a brain teaser you could as well do:



          @staticmethod
          def get_attacker_defender(u1,u2):
          return sorted( [u1,u2], key = lambda u:(u.speed,u.dexterity), reverse=True)


          which leverages tuple-sorting that sorts based on the 1st element, and when the 1st ones are equal on the 2nd element of the tuple. If both are equal the order stays as is (stable sorting with Timsort).



          Doku:





          • Does Python have a ternary conditional operator? (for return .. if ... else ...)

          • sorted(... with key and reversed ...)

          • Why are Python lambdas useful?






          share|improve this answer


























          • If I can learn to understand and use the "brain teaser" then I think I will become a better programmer

            – Jared C
            Jan 2 at 1:51











          • @JaredC you might - but it will make the code only shorter - not cleaner

            – Patrick Artner
            Jan 2 at 1:52











          • There has been a wealth of knowledge offered in response to my question, and I think I can take things from every answer and improve my understanding of python. This is the answer which best fits my specific needs, although many of the answers presented could be used to achieve the desired results.

            – Jared C
            Jan 2 at 12:54














          1












          1








          1







          Creating small methods that concentrate logic is no "overhead". They are easy to understand, and do not need to change for lots of reasons - hence they are done, testet and unchanged most of the time.



          class Battle:

          # snipped some code

          @staticmethod
          def get_attacker_defender(u1, u2):
          """Returs tuple (attacker,defender) based on given user."""
          if u1.speed > u2.speed:
          return u1,u2
          elif u2.speed > u1.speed:
          return u2,u1
          # probably cleaner to stay with elif: ... else ... but this is shorter
          return (u1,u2) if u1.dexterity > u2.dexterity else (u2,u1)


          def fight(self):
          self.user1.fight_stat()
          self.user2.fight_stat()
          self.attacker, self.defender = Battle.get_attacker_defender(self.user1,self.user2)

          if self.attacker.attack > self.defender.defense:
          return self.attacker
          elif self.defender.attack > self.attacker.defense:
          return self.defender
          else:
          return "Draw"




          If you like a brain teaser you could as well do:



          @staticmethod
          def get_attacker_defender(u1,u2):
          return sorted( [u1,u2], key = lambda u:(u.speed,u.dexterity), reverse=True)


          which leverages tuple-sorting that sorts based on the 1st element, and when the 1st ones are equal on the 2nd element of the tuple. If both are equal the order stays as is (stable sorting with Timsort).



          Doku:





          • Does Python have a ternary conditional operator? (for return .. if ... else ...)

          • sorted(... with key and reversed ...)

          • Why are Python lambdas useful?






          share|improve this answer















          Creating small methods that concentrate logic is no "overhead". They are easy to understand, and do not need to change for lots of reasons - hence they are done, testet and unchanged most of the time.



          class Battle:

          # snipped some code

          @staticmethod
          def get_attacker_defender(u1, u2):
          """Returs tuple (attacker,defender) based on given user."""
          if u1.speed > u2.speed:
          return u1,u2
          elif u2.speed > u1.speed:
          return u2,u1
          # probably cleaner to stay with elif: ... else ... but this is shorter
          return (u1,u2) if u1.dexterity > u2.dexterity else (u2,u1)


          def fight(self):
          self.user1.fight_stat()
          self.user2.fight_stat()
          self.attacker, self.defender = Battle.get_attacker_defender(self.user1,self.user2)

          if self.attacker.attack > self.defender.defense:
          return self.attacker
          elif self.defender.attack > self.attacker.defense:
          return self.defender
          else:
          return "Draw"




          If you like a brain teaser you could as well do:



          @staticmethod
          def get_attacker_defender(u1,u2):
          return sorted( [u1,u2], key = lambda u:(u.speed,u.dexterity), reverse=True)


          which leverages tuple-sorting that sorts based on the 1st element, and when the 1st ones are equal on the 2nd element of the tuple. If both are equal the order stays as is (stable sorting with Timsort).



          Doku:





          • Does Python have a ternary conditional operator? (for return .. if ... else ...)

          • sorted(... with key and reversed ...)

          • Why are Python lambdas useful?







          share|improve this answer














          share|improve this answer



          share|improve this answer








          edited Jan 2 at 1:55

























          answered Jan 2 at 1:42









          Patrick ArtnerPatrick Artner

          25k62443




          25k62443













          • If I can learn to understand and use the "brain teaser" then I think I will become a better programmer

            – Jared C
            Jan 2 at 1:51











          • @JaredC you might - but it will make the code only shorter - not cleaner

            – Patrick Artner
            Jan 2 at 1:52











          • There has been a wealth of knowledge offered in response to my question, and I think I can take things from every answer and improve my understanding of python. This is the answer which best fits my specific needs, although many of the answers presented could be used to achieve the desired results.

            – Jared C
            Jan 2 at 12:54



















          • If I can learn to understand and use the "brain teaser" then I think I will become a better programmer

            – Jared C
            Jan 2 at 1:51











          • @JaredC you might - but it will make the code only shorter - not cleaner

            – Patrick Artner
            Jan 2 at 1:52











          • There has been a wealth of knowledge offered in response to my question, and I think I can take things from every answer and improve my understanding of python. This is the answer which best fits my specific needs, although many of the answers presented could be used to achieve the desired results.

            – Jared C
            Jan 2 at 12:54

















          If I can learn to understand and use the "brain teaser" then I think I will become a better programmer

          – Jared C
          Jan 2 at 1:51





          If I can learn to understand and use the "brain teaser" then I think I will become a better programmer

          – Jared C
          Jan 2 at 1:51













          @JaredC you might - but it will make the code only shorter - not cleaner

          – Patrick Artner
          Jan 2 at 1:52





          @JaredC you might - but it will make the code only shorter - not cleaner

          – Patrick Artner
          Jan 2 at 1:52













          There has been a wealth of knowledge offered in response to my question, and I think I can take things from every answer and improve my understanding of python. This is the answer which best fits my specific needs, although many of the answers presented could be used to achieve the desired results.

          – Jared C
          Jan 2 at 12:54





          There has been a wealth of knowledge offered in response to my question, and I think I can take things from every answer and improve my understanding of python. This is the answer which best fits my specific needs, although many of the answers presented could be used to achieve the desired results.

          – Jared C
          Jan 2 at 12:54













          3














          The min and max functions accept a key function that tells them how to compare the inputs. The key accepts each input and returns the actual value to compare:



          max(self.user1, self.user2, key=lambda item: item.speed)


          For a large number of comparisons, this can be rewritten as



          from operator import attrgetter

          speed_key = attrgetter('speed')
          max(self.user1, self.user2, key=speed_key)


          If you have equal speeds, you can decide to compare using a different attribute. This is done by understanding that Python sequences are compared in lexicographixal order. This is easiest to understand with strings, since it's basically just dictionary order: e.g. 'abc' > 'abb' because each element is compared in order. The same applies to lists and tuples: [1, 2, 3] > [1, 2, 2].



          So to use the dexterity attribute as a fallback for equal speeds, do



          max(self.user1, self.user2, key=lambda item: (item.speed, item.dexterity))


          OR



          speedex_key = attrgetter('speed', 'dexterity')
          max(self.user1, self.user2, key=speedex_key)





          share|improve this answer




























            3














            The min and max functions accept a key function that tells them how to compare the inputs. The key accepts each input and returns the actual value to compare:



            max(self.user1, self.user2, key=lambda item: item.speed)


            For a large number of comparisons, this can be rewritten as



            from operator import attrgetter

            speed_key = attrgetter('speed')
            max(self.user1, self.user2, key=speed_key)


            If you have equal speeds, you can decide to compare using a different attribute. This is done by understanding that Python sequences are compared in lexicographixal order. This is easiest to understand with strings, since it's basically just dictionary order: e.g. 'abc' > 'abb' because each element is compared in order. The same applies to lists and tuples: [1, 2, 3] > [1, 2, 2].



            So to use the dexterity attribute as a fallback for equal speeds, do



            max(self.user1, self.user2, key=lambda item: (item.speed, item.dexterity))


            OR



            speedex_key = attrgetter('speed', 'dexterity')
            max(self.user1, self.user2, key=speedex_key)





            share|improve this answer


























              3












              3








              3







              The min and max functions accept a key function that tells them how to compare the inputs. The key accepts each input and returns the actual value to compare:



              max(self.user1, self.user2, key=lambda item: item.speed)


              For a large number of comparisons, this can be rewritten as



              from operator import attrgetter

              speed_key = attrgetter('speed')
              max(self.user1, self.user2, key=speed_key)


              If you have equal speeds, you can decide to compare using a different attribute. This is done by understanding that Python sequences are compared in lexicographixal order. This is easiest to understand with strings, since it's basically just dictionary order: e.g. 'abc' > 'abb' because each element is compared in order. The same applies to lists and tuples: [1, 2, 3] > [1, 2, 2].



              So to use the dexterity attribute as a fallback for equal speeds, do



              max(self.user1, self.user2, key=lambda item: (item.speed, item.dexterity))


              OR



              speedex_key = attrgetter('speed', 'dexterity')
              max(self.user1, self.user2, key=speedex_key)





              share|improve this answer













              The min and max functions accept a key function that tells them how to compare the inputs. The key accepts each input and returns the actual value to compare:



              max(self.user1, self.user2, key=lambda item: item.speed)


              For a large number of comparisons, this can be rewritten as



              from operator import attrgetter

              speed_key = attrgetter('speed')
              max(self.user1, self.user2, key=speed_key)


              If you have equal speeds, you can decide to compare using a different attribute. This is done by understanding that Python sequences are compared in lexicographixal order. This is easiest to understand with strings, since it's basically just dictionary order: e.g. 'abc' > 'abb' because each element is compared in order. The same applies to lists and tuples: [1, 2, 3] > [1, 2, 2].



              So to use the dexterity attribute as a fallback for equal speeds, do



              max(self.user1, self.user2, key=lambda item: (item.speed, item.dexterity))


              OR



              speedex_key = attrgetter('speed', 'dexterity')
              max(self.user1, self.user2, key=speedex_key)






              share|improve this answer












              share|improve this answer



              share|improve this answer










              answered Jan 2 at 1:54









              Mad PhysicistMad Physicist

              38k1674107




              38k1674107























                  1














                  If you want to use max with your objects, you can implement __gt__ com compare them (and __eq__ for consistency). So your User class could look like this:



                  class User:
                  def __init__(self, nickname, stats):
                  self.nickname = nickname
                  self.strength = stats['strength']
                  self.constitution = stats['constitution']
                  self.dexterity = stats['dexterity']
                  self.intelligence = stats['intelligence']
                  self.wisdom = stats['wisdom']
                  self.charisma = stats['charisma']

                  def __repr__(self):
                  return self.nickname

                  def __eq__(self, other):
                  return self.speed == other.speed and self.dexterity == other.dexterity

                  def __gt__(self, other):
                  return self.speed > other.speed or self.dexterity > other.dexterity


                  This implementation would allow you to use max and min to define the attacker and defender in the Battle class.



                  class Battle:
                  def __init__(self, user1, user2):
                  self.user1 = user1
                  self.user2 = user2
                  print(user1, "and", user2, "have entered the fight!")

                  def fight(self):
                  self.user1.fight_stat()
                  self.user2.fight_stat()

                  self.attacker = max(self.user1, self.user2)
                  self.defender = min(self.user1, self.user2)

                  if self.attacker.attack > self.defender.defense:
                  return self.attacker
                  elif self.defender.attack > self.attacker.defense:
                  return self.defender
                  else:
                  return "Draw"





                  share|improve this answer




























                    1














                    If you want to use max with your objects, you can implement __gt__ com compare them (and __eq__ for consistency). So your User class could look like this:



                    class User:
                    def __init__(self, nickname, stats):
                    self.nickname = nickname
                    self.strength = stats['strength']
                    self.constitution = stats['constitution']
                    self.dexterity = stats['dexterity']
                    self.intelligence = stats['intelligence']
                    self.wisdom = stats['wisdom']
                    self.charisma = stats['charisma']

                    def __repr__(self):
                    return self.nickname

                    def __eq__(self, other):
                    return self.speed == other.speed and self.dexterity == other.dexterity

                    def __gt__(self, other):
                    return self.speed > other.speed or self.dexterity > other.dexterity


                    This implementation would allow you to use max and min to define the attacker and defender in the Battle class.



                    class Battle:
                    def __init__(self, user1, user2):
                    self.user1 = user1
                    self.user2 = user2
                    print(user1, "and", user2, "have entered the fight!")

                    def fight(self):
                    self.user1.fight_stat()
                    self.user2.fight_stat()

                    self.attacker = max(self.user1, self.user2)
                    self.defender = min(self.user1, self.user2)

                    if self.attacker.attack > self.defender.defense:
                    return self.attacker
                    elif self.defender.attack > self.attacker.defense:
                    return self.defender
                    else:
                    return "Draw"





                    share|improve this answer


























                      1












                      1








                      1







                      If you want to use max with your objects, you can implement __gt__ com compare them (and __eq__ for consistency). So your User class could look like this:



                      class User:
                      def __init__(self, nickname, stats):
                      self.nickname = nickname
                      self.strength = stats['strength']
                      self.constitution = stats['constitution']
                      self.dexterity = stats['dexterity']
                      self.intelligence = stats['intelligence']
                      self.wisdom = stats['wisdom']
                      self.charisma = stats['charisma']

                      def __repr__(self):
                      return self.nickname

                      def __eq__(self, other):
                      return self.speed == other.speed and self.dexterity == other.dexterity

                      def __gt__(self, other):
                      return self.speed > other.speed or self.dexterity > other.dexterity


                      This implementation would allow you to use max and min to define the attacker and defender in the Battle class.



                      class Battle:
                      def __init__(self, user1, user2):
                      self.user1 = user1
                      self.user2 = user2
                      print(user1, "and", user2, "have entered the fight!")

                      def fight(self):
                      self.user1.fight_stat()
                      self.user2.fight_stat()

                      self.attacker = max(self.user1, self.user2)
                      self.defender = min(self.user1, self.user2)

                      if self.attacker.attack > self.defender.defense:
                      return self.attacker
                      elif self.defender.attack > self.attacker.defense:
                      return self.defender
                      else:
                      return "Draw"





                      share|improve this answer













                      If you want to use max with your objects, you can implement __gt__ com compare them (and __eq__ for consistency). So your User class could look like this:



                      class User:
                      def __init__(self, nickname, stats):
                      self.nickname = nickname
                      self.strength = stats['strength']
                      self.constitution = stats['constitution']
                      self.dexterity = stats['dexterity']
                      self.intelligence = stats['intelligence']
                      self.wisdom = stats['wisdom']
                      self.charisma = stats['charisma']

                      def __repr__(self):
                      return self.nickname

                      def __eq__(self, other):
                      return self.speed == other.speed and self.dexterity == other.dexterity

                      def __gt__(self, other):
                      return self.speed > other.speed or self.dexterity > other.dexterity


                      This implementation would allow you to use max and min to define the attacker and defender in the Battle class.



                      class Battle:
                      def __init__(self, user1, user2):
                      self.user1 = user1
                      self.user2 = user2
                      print(user1, "and", user2, "have entered the fight!")

                      def fight(self):
                      self.user1.fight_stat()
                      self.user2.fight_stat()

                      self.attacker = max(self.user1, self.user2)
                      self.defender = min(self.user1, self.user2)

                      if self.attacker.attack > self.defender.defense:
                      return self.attacker
                      elif self.defender.attack > self.attacker.defense:
                      return self.defender
                      else:
                      return "Draw"






                      share|improve this answer












                      share|improve this answer



                      share|improve this answer










                      answered Jan 2 at 2:34









                      Renan IvoRenan Ivo

                      1,266917




                      1,266917























                          0















                          I just need a statement that is like self.attacker =
                          max(self.user1.speed, self.user2.speed) but the attacker is set to the
                          user, not the user's speed.




                          You can use



                          from operator import attrgetter
                          ...
                          self.attacker = max(self.user1, self.user2, key=attrgetter('speed'))


                          This will return the user (not speed) has max speed



                          If you have more than 2 users, you can also pass list



                          More information about attrgetter






                          share|improve this answer
























                          • Is there a way to have it check the dexterity score (or just select one at random) if the speed of the users is the same?

                            – Jared C
                            Jan 2 at 1:36
















                          0















                          I just need a statement that is like self.attacker =
                          max(self.user1.speed, self.user2.speed) but the attacker is set to the
                          user, not the user's speed.




                          You can use



                          from operator import attrgetter
                          ...
                          self.attacker = max(self.user1, self.user2, key=attrgetter('speed'))


                          This will return the user (not speed) has max speed



                          If you have more than 2 users, you can also pass list



                          More information about attrgetter






                          share|improve this answer
























                          • Is there a way to have it check the dexterity score (or just select one at random) if the speed of the users is the same?

                            – Jared C
                            Jan 2 at 1:36














                          0












                          0








                          0








                          I just need a statement that is like self.attacker =
                          max(self.user1.speed, self.user2.speed) but the attacker is set to the
                          user, not the user's speed.




                          You can use



                          from operator import attrgetter
                          ...
                          self.attacker = max(self.user1, self.user2, key=attrgetter('speed'))


                          This will return the user (not speed) has max speed



                          If you have more than 2 users, you can also pass list



                          More information about attrgetter






                          share|improve this answer














                          I just need a statement that is like self.attacker =
                          max(self.user1.speed, self.user2.speed) but the attacker is set to the
                          user, not the user's speed.




                          You can use



                          from operator import attrgetter
                          ...
                          self.attacker = max(self.user1, self.user2, key=attrgetter('speed'))


                          This will return the user (not speed) has max speed



                          If you have more than 2 users, you can also pass list



                          More information about attrgetter







                          share|improve this answer












                          share|improve this answer



                          share|improve this answer










                          answered Jan 2 at 1:30









                          user3790180user3790180

                          10819




                          10819













                          • Is there a way to have it check the dexterity score (or just select one at random) if the speed of the users is the same?

                            – Jared C
                            Jan 2 at 1:36



















                          • Is there a way to have it check the dexterity score (or just select one at random) if the speed of the users is the same?

                            – Jared C
                            Jan 2 at 1:36

















                          Is there a way to have it check the dexterity score (or just select one at random) if the speed of the users is the same?

                          – Jared C
                          Jan 2 at 1:36





                          Is there a way to have it check the dexterity score (or just select one at random) if the speed of the users is the same?

                          – Jared C
                          Jan 2 at 1:36











                          0














                          You can indeed use max() to get the user with most speed.



                          The way of doing it is with the keyargument which you use to pass a custom scoring function that takes each object and returns a orderable value like a float or int.



                          def score(user):
                          return user.speed

                          fastest_user = max(list_of_users, key=score)


                          The most common is to pass an anonymous lambda function which you define with the syntax:



                          lambda var1, var2: expression


                          So the code would look like:



                          fastest_user = max(list_of_users, key=lambda user: user.speed)





                          share|improve this answer


























                          • Is there a way to have it check the dexterity score (or just select one at random) if the speed of the users is the same?

                            – Jared C
                            Jan 2 at 1:36











                          • Max will just return the first element if all the users have the same speed, so shuffling the list before should do the trick. for that just do from random import shuffle and use that function to mess the list before.

                            – Jeacom
                            Jan 2 at 1:43
















                          0














                          You can indeed use max() to get the user with most speed.



                          The way of doing it is with the keyargument which you use to pass a custom scoring function that takes each object and returns a orderable value like a float or int.



                          def score(user):
                          return user.speed

                          fastest_user = max(list_of_users, key=score)


                          The most common is to pass an anonymous lambda function which you define with the syntax:



                          lambda var1, var2: expression


                          So the code would look like:



                          fastest_user = max(list_of_users, key=lambda user: user.speed)





                          share|improve this answer


























                          • Is there a way to have it check the dexterity score (or just select one at random) if the speed of the users is the same?

                            – Jared C
                            Jan 2 at 1:36











                          • Max will just return the first element if all the users have the same speed, so shuffling the list before should do the trick. for that just do from random import shuffle and use that function to mess the list before.

                            – Jeacom
                            Jan 2 at 1:43














                          0












                          0








                          0







                          You can indeed use max() to get the user with most speed.



                          The way of doing it is with the keyargument which you use to pass a custom scoring function that takes each object and returns a orderable value like a float or int.



                          def score(user):
                          return user.speed

                          fastest_user = max(list_of_users, key=score)


                          The most common is to pass an anonymous lambda function which you define with the syntax:



                          lambda var1, var2: expression


                          So the code would look like:



                          fastest_user = max(list_of_users, key=lambda user: user.speed)





                          share|improve this answer















                          You can indeed use max() to get the user with most speed.



                          The way of doing it is with the keyargument which you use to pass a custom scoring function that takes each object and returns a orderable value like a float or int.



                          def score(user):
                          return user.speed

                          fastest_user = max(list_of_users, key=score)


                          The most common is to pass an anonymous lambda function which you define with the syntax:



                          lambda var1, var2: expression


                          So the code would look like:



                          fastest_user = max(list_of_users, key=lambda user: user.speed)






                          share|improve this answer














                          share|improve this answer



                          share|improve this answer








                          edited Jan 2 at 1:36

























                          answered Jan 2 at 1:30









                          JeacomJeacom

                          254




                          254













                          • Is there a way to have it check the dexterity score (or just select one at random) if the speed of the users is the same?

                            – Jared C
                            Jan 2 at 1:36











                          • Max will just return the first element if all the users have the same speed, so shuffling the list before should do the trick. for that just do from random import shuffle and use that function to mess the list before.

                            – Jeacom
                            Jan 2 at 1:43



















                          • Is there a way to have it check the dexterity score (or just select one at random) if the speed of the users is the same?

                            – Jared C
                            Jan 2 at 1:36











                          • Max will just return the first element if all the users have the same speed, so shuffling the list before should do the trick. for that just do from random import shuffle and use that function to mess the list before.

                            – Jeacom
                            Jan 2 at 1:43

















                          Is there a way to have it check the dexterity score (or just select one at random) if the speed of the users is the same?

                          – Jared C
                          Jan 2 at 1:36





                          Is there a way to have it check the dexterity score (or just select one at random) if the speed of the users is the same?

                          – Jared C
                          Jan 2 at 1:36













                          Max will just return the first element if all the users have the same speed, so shuffling the list before should do the trick. for that just do from random import shuffle and use that function to mess the list before.

                          – Jeacom
                          Jan 2 at 1:43





                          Max will just return the first element if all the users have the same speed, so shuffling the list before should do the trick. for that just do from random import shuffle and use that function to mess the list before.

                          – Jeacom
                          Jan 2 at 1:43











                          0














                          Here is an answer that separates the logic as was mentioned above, and uses your original max desire. The benefit to this solution is that logic to determine first attack could be easily refactored. Simply change the order (or add attributes to) attribute_priority_order



                          class Battle:
                          def __init__(self, user1, user2):
                          self.user1 = user1
                          self.user2 = user2
                          print(user1, "and", user2, "have entered the fight!")


                          @staticmethod
                          def _compare_attributes(user1: User, user2: User, attribute: str):
                          if getattr(user1, attribute) != getattr(user2, attribute):
                          return max(
                          [user1, user2],
                          key=lambda user: getattr(user, attribute)
                          )

                          def get_attacker(self):
                          """
                          Returns attacker based on attribute comparison
                          :return: User
                          """
                          default_attacker = self.user2
                          attribute_priority_order = [
                          'speed',
                          'dexterity'
                          ]

                          for attribute in attribute_priority_order:
                          attacker = self._compare_attributes(
                          user1=self.user1,
                          user2=self.user2,
                          attribute=attribute
                          )
                          if attacker:
                          return attacker

                          return default_attacker

                          def get_defender(self):
                          """
                          User in the battle that isn't the attacker.
                          :return: User
                          """
                          for user in [self.user1, self.user2]:
                          if str(user) != str(self.attacker):
                          return user


                          def fight(self):
                          self.user1.fight_stat()
                          self.user2.fight_stat()

                          self.attacker = self.get_attacker()
                          self.defender = self.get_defender()

                          if self.attacker.attack > self.defender.defense:
                          return self.attacker
                          elif self.defender.attack > self.attacker.defense:
                          return self.defender
                          else:
                          return "Draw"


                          With a little extra abstraction, _compare_attributes method could be recycled to determine the winner as well maybe with an optional second attribute. The return from this method is optionally a user if there is no tie.






                          share|improve this answer






























                            0














                            Here is an answer that separates the logic as was mentioned above, and uses your original max desire. The benefit to this solution is that logic to determine first attack could be easily refactored. Simply change the order (or add attributes to) attribute_priority_order



                            class Battle:
                            def __init__(self, user1, user2):
                            self.user1 = user1
                            self.user2 = user2
                            print(user1, "and", user2, "have entered the fight!")


                            @staticmethod
                            def _compare_attributes(user1: User, user2: User, attribute: str):
                            if getattr(user1, attribute) != getattr(user2, attribute):
                            return max(
                            [user1, user2],
                            key=lambda user: getattr(user, attribute)
                            )

                            def get_attacker(self):
                            """
                            Returns attacker based on attribute comparison
                            :return: User
                            """
                            default_attacker = self.user2
                            attribute_priority_order = [
                            'speed',
                            'dexterity'
                            ]

                            for attribute in attribute_priority_order:
                            attacker = self._compare_attributes(
                            user1=self.user1,
                            user2=self.user2,
                            attribute=attribute
                            )
                            if attacker:
                            return attacker

                            return default_attacker

                            def get_defender(self):
                            """
                            User in the battle that isn't the attacker.
                            :return: User
                            """
                            for user in [self.user1, self.user2]:
                            if str(user) != str(self.attacker):
                            return user


                            def fight(self):
                            self.user1.fight_stat()
                            self.user2.fight_stat()

                            self.attacker = self.get_attacker()
                            self.defender = self.get_defender()

                            if self.attacker.attack > self.defender.defense:
                            return self.attacker
                            elif self.defender.attack > self.attacker.defense:
                            return self.defender
                            else:
                            return "Draw"


                            With a little extra abstraction, _compare_attributes method could be recycled to determine the winner as well maybe with an optional second attribute. The return from this method is optionally a user if there is no tie.






                            share|improve this answer




























                              0












                              0








                              0







                              Here is an answer that separates the logic as was mentioned above, and uses your original max desire. The benefit to this solution is that logic to determine first attack could be easily refactored. Simply change the order (or add attributes to) attribute_priority_order



                              class Battle:
                              def __init__(self, user1, user2):
                              self.user1 = user1
                              self.user2 = user2
                              print(user1, "and", user2, "have entered the fight!")


                              @staticmethod
                              def _compare_attributes(user1: User, user2: User, attribute: str):
                              if getattr(user1, attribute) != getattr(user2, attribute):
                              return max(
                              [user1, user2],
                              key=lambda user: getattr(user, attribute)
                              )

                              def get_attacker(self):
                              """
                              Returns attacker based on attribute comparison
                              :return: User
                              """
                              default_attacker = self.user2
                              attribute_priority_order = [
                              'speed',
                              'dexterity'
                              ]

                              for attribute in attribute_priority_order:
                              attacker = self._compare_attributes(
                              user1=self.user1,
                              user2=self.user2,
                              attribute=attribute
                              )
                              if attacker:
                              return attacker

                              return default_attacker

                              def get_defender(self):
                              """
                              User in the battle that isn't the attacker.
                              :return: User
                              """
                              for user in [self.user1, self.user2]:
                              if str(user) != str(self.attacker):
                              return user


                              def fight(self):
                              self.user1.fight_stat()
                              self.user2.fight_stat()

                              self.attacker = self.get_attacker()
                              self.defender = self.get_defender()

                              if self.attacker.attack > self.defender.defense:
                              return self.attacker
                              elif self.defender.attack > self.attacker.defense:
                              return self.defender
                              else:
                              return "Draw"


                              With a little extra abstraction, _compare_attributes method could be recycled to determine the winner as well maybe with an optional second attribute. The return from this method is optionally a user if there is no tie.






                              share|improve this answer















                              Here is an answer that separates the logic as was mentioned above, and uses your original max desire. The benefit to this solution is that logic to determine first attack could be easily refactored. Simply change the order (or add attributes to) attribute_priority_order



                              class Battle:
                              def __init__(self, user1, user2):
                              self.user1 = user1
                              self.user2 = user2
                              print(user1, "and", user2, "have entered the fight!")


                              @staticmethod
                              def _compare_attributes(user1: User, user2: User, attribute: str):
                              if getattr(user1, attribute) != getattr(user2, attribute):
                              return max(
                              [user1, user2],
                              key=lambda user: getattr(user, attribute)
                              )

                              def get_attacker(self):
                              """
                              Returns attacker based on attribute comparison
                              :return: User
                              """
                              default_attacker = self.user2
                              attribute_priority_order = [
                              'speed',
                              'dexterity'
                              ]

                              for attribute in attribute_priority_order:
                              attacker = self._compare_attributes(
                              user1=self.user1,
                              user2=self.user2,
                              attribute=attribute
                              )
                              if attacker:
                              return attacker

                              return default_attacker

                              def get_defender(self):
                              """
                              User in the battle that isn't the attacker.
                              :return: User
                              """
                              for user in [self.user1, self.user2]:
                              if str(user) != str(self.attacker):
                              return user


                              def fight(self):
                              self.user1.fight_stat()
                              self.user2.fight_stat()

                              self.attacker = self.get_attacker()
                              self.defender = self.get_defender()

                              if self.attacker.attack > self.defender.defense:
                              return self.attacker
                              elif self.defender.attack > self.attacker.defense:
                              return self.defender
                              else:
                              return "Draw"


                              With a little extra abstraction, _compare_attributes method could be recycled to determine the winner as well maybe with an optional second attribute. The return from this method is optionally a user if there is no tie.







                              share|improve this answer














                              share|improve this answer



                              share|improve this answer








                              edited Jan 2 at 2:16

























                              answered Jan 2 at 2:10









                              Andrew RiessAndrew Riess

                              10423




                              10423























                                  0














                                  How about using the fact that python lists compare so your ability measure is:



                                  def ability(user):
                                  return (user.speed, user.dexterity)


                                  Your winning criteria is:



                                  def winner(attacker, defender):
                                  return attacker.attack > defender.defense


                                  And the fight becomes:



                                  def fight(a, b):
                                  return winner(a, b) if ability(a) >= ability(b) else winner(b, a)





                                  share|improve this answer




























                                    0














                                    How about using the fact that python lists compare so your ability measure is:



                                    def ability(user):
                                    return (user.speed, user.dexterity)


                                    Your winning criteria is:



                                    def winner(attacker, defender):
                                    return attacker.attack > defender.defense


                                    And the fight becomes:



                                    def fight(a, b):
                                    return winner(a, b) if ability(a) >= ability(b) else winner(b, a)





                                    share|improve this answer


























                                      0












                                      0








                                      0







                                      How about using the fact that python lists compare so your ability measure is:



                                      def ability(user):
                                      return (user.speed, user.dexterity)


                                      Your winning criteria is:



                                      def winner(attacker, defender):
                                      return attacker.attack > defender.defense


                                      And the fight becomes:



                                      def fight(a, b):
                                      return winner(a, b) if ability(a) >= ability(b) else winner(b, a)





                                      share|improve this answer













                                      How about using the fact that python lists compare so your ability measure is:



                                      def ability(user):
                                      return (user.speed, user.dexterity)


                                      Your winning criteria is:



                                      def winner(attacker, defender):
                                      return attacker.attack > defender.defense


                                      And the fight becomes:



                                      def fight(a, b):
                                      return winner(a, b) if ability(a) >= ability(b) else winner(b, a)






                                      share|improve this answer












                                      share|improve this answer



                                      share|improve this answer










                                      answered Jan 2 at 2:18









                                      Mike RobinsMike Robins

                                      1,297510




                                      1,297510






























                                          draft saved

                                          draft discarded




















































                                          Thanks for contributing an answer to Stack Overflow!


                                          • Please be sure to answer the question. Provide details and share your research!

                                          But avoid



                                          • Asking for help, clarification, or responding to other answers.

                                          • Making statements based on opinion; back them up with references or personal experience.


                                          To learn more, see our tips on writing great answers.




                                          draft saved


                                          draft discarded














                                          StackExchange.ready(
                                          function () {
                                          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54000219%2fselect-the-object-with-a-larger-value-of-a-specific-attribute%23new-answer', 'question_page');
                                          }
                                          );

                                          Post as a guest















                                          Required, but never shown





















































                                          Required, but never shown














                                          Required, but never shown












                                          Required, but never shown







                                          Required, but never shown

































                                          Required, but never shown














                                          Required, but never shown












                                          Required, but never shown







                                          Required, but never shown







                                          Popular posts from this blog

                                          Monofisismo

                                          Angular Downloading a file using contenturl with Basic Authentication

                                          Olmecas