Python 选择特定属性值较大的对象

Python 选择特定属性值较大的对象,python,Python,我刚开始学习python,所以我不熟悉各种技巧或工具,也不熟悉正确的提问方式。正因为如此,我无法找到以前的问题,做什么,我正在寻找 我在这里概述了一个工作代码: import random class UserGroup: def __init__(self, users): self.user_list = users def random_users(self): self.random_1 = random.choice(self.use

我刚开始学习python,所以我不熟悉各种技巧或工具,也不熟悉正确的提问方式。正因为如此,我无法找到以前的问题,做什么,我正在寻找

我在这里概述了一个工作代码:

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())
示例输出如下所示:

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
正如我所写的,代码按预期执行。然而,我关心的是我在
Battle
类中实现
fight()
方法的方式。我不认为大序列的
if
语句是说“用户先进行高速攻击”的正确方式。从逻辑上讲,我只需要一个类似于
self.attacker=max(self.user1.speed,self.user2.speed)
的语句,但是攻击者被设置为用户,而不是用户的速度。但是,我不知道如何用python中的一两行代码来实现这一点。

您确实可以使用max()以最快的速度获得
用户

方法是使用
参数,您可以使用该参数传递一个自定义评分函数,该函数接受每个对象并返回一个可排序的值,如float或int

def score(user):
    return user.speed

fastest_user = max(list_of_users, key=score)
最常见的是传递一个匿名lambda函数,该函数由以下语法定义:

lambda var1, var2: expression
所以代码看起来像:

fastest_user = max(list_of_users, key=lambda user: user.speed)
您确实可以使用max()以最快的速度获取
用户

方法是使用
参数,您可以使用该参数传递一个自定义评分函数,该函数接受每个对象并返回一个可排序的值,如float或int

def score(user):
    return user.speed

fastest_user = max(list_of_users, key=score)
最常见的是传递一个匿名lambda函数,该函数由以下语法定义:

lambda var1, var2: expression
所以代码看起来像:

fastest_user = max(list_of_users, key=lambda user: user.speed)
我只需要一个像自我攻击一样的陈述= max(self.user1.speed,self.user2.speed),但攻击者设置为 用户,而不是用户的速度

你可以用

from operator import attrgetter
...
self.attacker = max(self.user1, self.user2, key=attrgetter('speed'))
这将返回
用户
(不是
速度
)具有最大
速度

如果您有2个以上的用户,还可以通过列表

我只需要一个像自我攻击一样的陈述= max(self.user1.speed,self.user2.speed),但攻击者设置为 用户,而不是用户的速度

你可以用

from operator import attrgetter
...
self.attacker = max(self.user1, self.user2, key=attrgetter('speed'))
这将返回
用户
(不是
速度
)具有最大
速度

如果您有2个以上的用户,还可以通过列表


创建集中逻辑的小方法没有“开销”。它们很容易理解,并且不需要出于很多原因进行更改-因此它们在大多数情况下都是完成、测试和不变的

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"

如果你喜欢脑筋急转弯,不妨:

@staticmethod
def get_attacker_defender(u1,u2):
    return sorted( [u1,u2], key = lambda u:(u.speed,u.dexterity), reverse=True)
它利用基于第一个元素排序的元组排序,并且当元组的第二个元素上的第一个元素相等时。如果两者相等,则顺序保持不变(稳定排序)

Doku:

  • (对于
    返回..如果..否则..

创建集中逻辑的小方法没有“开销”。它们很容易理解,并且不需要出于很多原因进行更改-因此它们在大多数情况下都是完成、测试和不变的

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"

如果你喜欢脑筋急转弯,不妨:

@staticmethod
def get_attacker_defender(u1,u2):
    return sorted( [u1,u2], key = lambda u:(u.speed,u.dexterity), reverse=True)
它利用基于第一个元素排序的元组排序,并且当元组的第二个元素上的第一个元素相等时。如果两者相等,则顺序保持不变(稳定排序)

Doku:

  • (对于
    返回..如果..否则..

最小值
和最大值函数接受一个键函数,告诉它们如何比较输入。键接受每个输入并返回要比较的实际值:

max(self.user1, self.user2, key=lambda item: item.speed)
对于大量比较,可以将其改写为

from operator import attrgetter

speed_key = attrgetter('speed')
max(self.user1, self.user2, key=speed_key)
如果速度相等,则可以决定使用不同的属性进行比较。这是通过理解Python序列是按字典顺序进行比较来实现的。这是字符串最容易理解的,因为它基本上只是字典顺序:例如,
'abc'>'abb'
,因为每个元素都是按顺序比较的。列表和元组也是如此:
[1,2,3]>[1,2,2]

因此,要使用
灵巧性
属性作为同等速度的后备方法,请执行以下操作

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


min
max
函数接受一个
函数,告诉它们如何比较输入。键接受每个输入并返回要比较的实际值:

max(self.user1, self.user2, key=lambda item: item.speed)
对于大量比较,可以将其改写为

from operator import attrgetter

speed_key = attrgetter('speed')
max(self.user1, self.user2, key=speed_key)
如果速度相等,则可以决定使用不同的属性进行比较。这是通过理解Python序列是按字典顺序进行比较来实现的。这是字符串最容易理解的,因为它基本上只是字典顺序:例如,
'abc'>'abb'
,因为每个元素都是按顺序比较的。列表和元组也是如此:
[1,2,3]>[1,2,2]

因此,要使用
灵巧性
属性作为同等速度的后备方法,请执行以下操作

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


这里有一个答案,它将上述逻辑分开,并使用您最初的最大欲望。此解决方案的好处是,可以轻松重构确定第一次攻击的逻辑。只需更改顺序(或添加属性)
attribute\u priority\u顺序

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"

通过一些额外的抽象,
\u compare\u attributes
方法可以循环使用,以确定胜利者,也可以使用可选的第二个属性。如果没有联系,此方法的返回也可以由用户选择。

这里有一个答案,它将如上所述的逻辑分开,并使用您最初的最大期望值。此解决方案的好处是,可以轻松重构确定第一次攻击的逻辑。只需更改顺序(或添加属性)
attribute\u priority\u顺序

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"
再加一点