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

时间:2019-01-02 01:14:09

标签: python

我刚刚开始学习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

正如我所写,代码按预期执行。但是,我担心在fight()类中实现Battle方法的方式。我认为if语句的较大顺序不是说“首先攻击速度较高的用户”的正确方法。从逻辑上讲,我只需要一个类似于self.attacker = max(self.user1.speed, self.user2.speed)的语句,但攻击者是用户,而不是用户的速度。但是,我不知道如何在python中的一两行代码中完成此操作。

7 个答案:

答案 0 :(得分:3)

minmax函数接受一个key函数,该函数告诉他们如何比较输入。键接受每个输入并返回实际值以进行比较:

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]

因此要使用dexterity属性作为等速的备用,请执行

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)

答案 1 :(得分:1)

创建集中逻辑的小型方法不是“开销”。它们易于理解,并且不需要出于很多原因而进行更改-因此,它们在大多数情况下都可以完成,运行并保持不变。

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)

利用元组排序,该排序基于元组的第一个元素,当元组的第二个元素上的第一个元素相等时进行排序。如果两者相等,则顺序保持不变(使用Timsort进行稳定排序)。

Doku:

答案 2 :(得分:1)

如果要对对象使用max,则可以实现__gt__ com比较它们(和__eq__以获得一致性)。因此,您的User类可能如下所示:

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

此实现将允许您使用maxminattacker类中定义defenderBattle

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"

答案 3 :(得分:0)

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

这样做的方法是使用key参数,您可以使用该参数传递自定义评分函数,该函数将获取每个对象并返回可排序的值,例如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)

答案 4 :(得分:0)

  

我只需要一个类似于self.attacker =的语句   max(self.user1.speed,self.user2.speed),但攻击者设置为   用户,而不是用户的速度。

您可以使用

$("#calendar").fullCalendar({
    events: {
        url: "https://www.hebcal.com/hebcal/?cfg=fc&v=1&i=off&maj=on&min=on&nx=on&mf=on&ss=on&mod=on&lg=s&s=off&d=on",
        cache: true
    }
});

这将返回最大为from operator import attrgetter ... self.attacker = max(self.user1, self.user2, key=attrgetter('speed')) 的{​​{1}}(不是user

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

More information about attrgetter

答案 5 :(得分:0)

这是一个答案,它如上所述分离逻辑,并使用您的原始最大期望。该解决方案的好处在于,可以轻松地重构确定首次攻击的逻辑。只需更改顺序(或向其中添加属性)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"

有了一些额外的抽象,_compare_attributes方法也可以被回收以确定获奖者,也许还有第二个可选属性。如果没有关系,则此方法的返回值可以是用户(可选)。

答案 6 :(得分:0)

如何利用python列表进行比较的事实,以便您的能力测度为:

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

您的获胜标准是:

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

战斗变成:

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