繁体   English   中英

在类属性更改时调用Python方法

[英]Call Python Method on Class Attribute Change

我正在编写一个API解析Twitter机器人,对OOP来说是个新手。 我有一些依赖于全局变量的现有Python代码,并认为我可以借此机会学习。

我有以下Team类,这些类在解析API时会更新,并且希望能够在类属性更改时调用完全不相关的(外部)方法。

class Team(object):
  def __init__(self, team_name, tri_code, goals, shots, goalie_pulled):
    self.team_name = team_name
    self.tri_code = tri_code
    self.goals = goals
    self.shots = shots
    self.goalie_pulled = goalie_pulled

goalie_pulled是改变现有实例Team ,我想下面的方法被调用(伪代码):

def goalie_pulled_tweet(team):
  tweet = "{} has pulled their goalie with {} remaining!".format(team.team_name, game.period_remain)
  send_tweet(tweet)

两件事情 -

  1. 一旦我检测到goalie_pulled属性已更改,如何在Team类中调用goalie_pulled_tweet
  2. 我可以从任何地方访问Game对象的实例,还是也需要将其传递给该变量?

您应该看看属性类。 基本上,它使您可以封装行为和私有成员,而消费者甚至不会注意到它。

在您的示例中,您可能具有goalie_pulled属性:

class Team(object):
    def __init__(self, team_name, tri_code, goals, shots, goalie_pulled):
        # Notice the identation here. This is very important.
        self.team_name = team_name
        self.tri_code = tri_code
        self.goals = goals
        self.shots = shots

        # Prefix your field with an underscore, this is Python standard way for defining private members
        self._goalie_pulled = goalie_pulled

    @property
    def goalie_pulled(self):
        return self._goalie_pulled

    @goalie_pulled.setter
    def goalie_pulled(self, new_value):
        self._goalie_pulled = new_value
        goalie_pulled_tweet(self) #self is the current Team instance

从消费者的角度来看:

team = create_team_instance()

# goalie_pulled_tweet is called
team.goalie_pulled = 'some_value'

我建议您尽可能(并且必须)使用属性,因为它们是一种很好的抽象方法。

从设计的角度来看,使用pull_goalie方法会更有意义。

类是创建更有意义的抽象的工具。 拉守门员是一个动作。 如果您认为Team代表了现实生活中的团队,那么说“团队拔了守门员!”更有意义。 而不是“团队将他们的拉高目标属性设置为X玩家!”

class Team(object):
    ...

    def pull_goalie(self, player):
        self.pulled_goalie = player
        tweet = '<your format string>'.format(
            self.pulled_goalie,
            # Yes, your Team *could* store a reference to the current game.
            # It's hard to tell if that makes sense in your program without more context.
            self.game.period_remaining  
        )

我打算推荐一个属性,但是我认为这可以解决当前的问题,而无需考虑更广泛的设计清晰度。

注意:Python中没有“私有”属性。 有一个约定,以单个下划线( self._pulled_goalie )开头的属性被视为私有,但这只是为了使使用您的代码的人知道,他们不能一直依赖于该值来始终执行他们认为会做的事情。 (即,它不是代码公共合同的一部分,您可以更改它而不会发出警告。)

编辑:要在Game对象上创建一个register_team方法,您可以做这样的事情:

class Game(object):
    def __init__(<stuff>):
        ...
        self.teams = {}

    ...

    def register_team(self, team):
        if len(self.teams) > 1:
            raise ValueError(
                "Too many teams! Cannot register {} for {}"
                .format(team, game)
            )

        self.teams[team] = team
        team.game = self

    def unregister_team(self, team):
        try:
            del self.teams[team]
        except KeyError:
            pass

        team.game = None

请注意,通过使用字典,可以多次调用register_teamunregiser_team而不会产生不良影响。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM