简体   繁体   English

如何从父实例调用子类中的方法?

[英]How to call method in child class from parent instance?

How do I create an instance of Stats and call a method on in GameStats ?如何创建Stats实例并在GameStats调用方法? Like below:像下面这样:

class Stats():

    """Object to instansiate a league and season pair 
    Args:
        league(str): league_id
        season(str): season_id
    """
    fb = Football()
    dir = Directory()
    def __init__(self, league='EN_PR', season='2019/2020'):
        self.pool = multiprocessing.cpu_count()
        self.league = league
        self.season = season

    def load_season_fixture(self):
        """Loads the fixtures for a league-season,
        calls api_scraper.py methods
        """
        self.fb.load_leagues()
        self.fb.leagues[self.league].load_seasons()
        return self.fb.leagues[self.league].seasons[self.season].load_played_fixtures()

    def load_season_players(self):
        """Loads the players for a league-season,
        calls api_scraper.py methods
        """
        player_id = []
        self.fb.load_leagues()
        self.fb.leagues[self.league].load_seasons()
        teams = self.fb.leagues[self.league].seasons[self.season].load_teams()
        for team in tqdm(teams.values()):
            players = self.fb.leagues[self.league].seasons['2019/2020'].teams[team['shortName']].load_players()
        for player in players.keys():
            player_id.append(player)
        return player_id

    def load_season_teams(self):
        """Loads the teams for a league-season,
        calls api_scraper.py methods
        """
        player_id = []
        self.fb.load_leagues()
        self.fb.leagues[self.league].load_seasons()
        return self.fb.leagues[self.league].seasons[self.season].load_teams()

class GameStats(Stats):
    def __init__(self, *args, **kwargs):
        super().__init__()
        self.fixture_id = [fix['id'] for fix in self.load_season_fixture().values()]

    def fixture_stats_singel(self, fixture):
        """Gets stats for a fixture"""
        ds = load_match_data(f'https://footballapi.pulselive.com/football/stats/match/{fixture}')
        return ds

    def fixture_stats(self):
        """Gets stats for all fixtures in a league-season using multithreading
        saves output in a json file.

        """
        stats = {}
        with Pool(self.pool) as p:
            fixture_stats = list(tqdm(p.imap(self.fixture_stats_singel, self.fixture_id, chunksize=1), total=len(self.fixture_id)))
        i = 0
        for fixture in fixture_stats:
            game_id = fixture['entity']['id'] #Get's the gameIDs for each game
            index = game_id #Set's gameIDs as index for dictionairy
            stats[index] = {'info': fixture['entity']}

        print(f'Saved as {filename}.json in {path}')

class PlayerStats(Stats):
    def __init__(self, *args, **kwargs):
        super().__init__()
        self.player_id = self.load_season_players()

    def player_stats_singel(self, player):
        #NEED TO HAVE SEASON ID
        season_id = self.fb.leagues[self.league].seasons[self.season]['id']
        ds = load_match_data(
            f'https://footballapi.pulselive.com/football/stats/player/{player}?compSeasons={season_id}')
        return ds

    def player_stats(self):
        stats = {}
        with Pool(self.pool) as p:
            player_stats = list(tqdm(p.imap(self.player_stats_singel, self.player_id, chunksize=1), total=len(self.player_id)))
        all_players = player_stats
        i = 0
        for player in all_players:
            game_id = int(player['entity']['id']) #Get's the gameIDs for each game
            index = game_id #Set's gameIDs as index for dictionairy
            stats[index] = {'info': player['entity']}

        print(f'Saved as {filename}.json in {path}')

class TeamStandings(Stats):
    def __init__(self, *args, **kwargs):
        super().__init__()
        self.team_id = [fix['id'] for fix in self.load_season_teams().values()]

    def team_standings_singel(self, team_id):
        #NEED TO HAVE SEASON ID
        season_id = self.fb.leagues[self.league].seasons[self.season]['id']
        ds = load_match_data(
            f'https://footballapi.pulselive.com/football/compseasons/{season_id}/standings/team/{team_id}')
        return ds

    def team_standings(self):
        stats = {}
        with Pool(self.pool) as p:
            team_standings = list(tqdm(p.imap(self.team_standings_singel, self.team_id, chunksize=1), total=len(self.team_id)))
        i = 0
        team_standing = team_standings
        for team in team_standing:
            team_id = int(team['team']['club']['id']) #Get's the gameIDs for each game
            index = team_id #Set's gameIDs as index for dictionairy
            if 'compSeason' in team:
                stats[index] = {'season': team['compSeason']}

        print(f'Saved as {filename}.json in {path}')

#What I'm doing right now
d = TeamStandings()
d.team_standings()
e = PlayerStats()
e.player_stats()
f = GameStats()
f.fixture_stats()

#What I want to do
d.Stats()
d.team_standings()
d.player_stats()
d.fixture_stats()

With the more context from the comments:随着评论的更多背景:

So... you don't want to have a child object, you just want to have more methods in the original class?所以......你不想有一个子对象,你只想在原始类中有更多的方法? But without putting those methods in the original class?但是没有将这些方法放在原始类中?

@h4ze that sounds right! @h4ze 听起来不错! I want the fragmentation我想要碎片

If you specify class name explicitly, you can pass anything as self .如果您明确指定类名,则可以将任何内容作为self传递。

d = Stats()
GameStats.fixture_stats(d)

It's called duck typing - we don't care about actual type of the object, we care about what it does: "if it swims like a duck and quacks like a duck, it's a duck".这叫做鸭子类型——我们不关心对象的实际类型,我们关心它做什么:“如果它像鸭子一样游泳,像鸭子一样嘎嘎叫,它就是一只鸭子”。

This allows you to pass any object anywhere... But this also means the object needs to "swim" and "quacks" like the originally expected object, right?这允许您在任何地方传递任何对象......但这也意味着该对象需要像最初预期的对象一样“游泳”和“嘎嘎叫”,对吧?

We know that all GameStats object are Stats objects (because inheritance), but not the other way around.我们知道所有GameStats对象都是Stats对象(因为继承),但GameStats不是。 - This means your methods in GameStats can only use things that Stats has. - 这意味着您在GameStats的方法只能使用Stats拥有的东西。


But just because you can do something doesn't mean you should .但是,仅仅因为您可以做某事并不意味着您应该这样做。 You can't use your child class's potential - you're basically just using the class as storage of methods for different class!您不能使用子类的潜力——您基本上只是将类用作不同类的方法存储!


Better idea would be to do it the other way around - use multi-inheritance.更好的办法是做周围的其他方法-利用多继承。 Each parent class would have what is needed to perform its actions (and of course you would set all those parts in your child init) and those actions - thus minimizing the need of overwriting methods in child.每个父类都有执行其操作所需的内容(当然您会在子初始化中设置所有这些部分)和这些操作 - 从而最大限度地减少覆盖 child.init 中的方法的需要。

Think of it like interfaces in other languages, but with already implemented methods (normally you have to implement the interface - causing more things in the class).把它想象成其他语言中的接口,但是已经实现了方法(通常你必须实现接口 - 在类中产生更多的东西)。


Or just do normal functions , document (in docstrings) that they should take the given object, and use that.或者只是做普通的函数,记录(在文档字符串中)他们应该接受给定的对象,并使用它。 You can store those functions in different modules, thus giving them different namespaces - providing the "fragmentation" you want.您可以将这些函数存储在不同的模块中,从而为它们提供不同的命名空间——提供您想要的“碎片化”。

This is a bad design.这是一个糟糕的设计。 So my answer is just you should not do that .所以我的回答是你不应该那样做

It is dangerous, because methods from a subclass expect a subclass object that could have additional attributes.这是危险的,因为来自子类的方法需要一个可以具有附加属性的子类对象。 And calling those methods on a base class object could break.在基类对象上调用这些方法可能会中断。 In your example, only true GameStats object will have an initialized fixture_id在您的示例中,只有真正的GameStats对象才会具有初始化的fixture_id

Ok, if you write that carefully, it will work, but it would require comments in red flashing font to prevent future maintainers not to break it, because you are willingly misusing a class hierachy.好吧,如果你仔细写,它会起作用,但它需要红色闪烁字体的注释,以防止未来的维护者不破坏它,因为你故意滥用类层次结构。

There are acceptable designs if you want to build a base class object, and later use methods from a subclass:如果您想构建基类对象,然后使用子类中的方法,则有可接受的设计:

  • make sure that all subclasses can be initialized from a base class object and then do:确保所有子类都可以从基类对象初始化,然后执行:

     d = Stats() # additional Stats operation on d... (GameStats(d)).fixture_stats()
  • use a __getattr__ that will load methods from additional mixins (manual equivalent of above design)使用__getattr__将从额外的 mixin 加载方法(手动等效于上述设计)

     class Base: def set_mixin(self, mixin): self.mixin = mixin def __getattr__(self, attr): return functools.partial(getattr(self.mixin, attr), self) class M1: """Mixin for class Base: only contains methods that apply on Base objects""" def __init__(self, *args, **kwargs): raise TypeError("Cannot create M1 objects") def foo(self, x): print(x, 'on', self) b = Base() b.set_mixin(M1) b.foo('x')

    would print会打印

    x on <__main__.Base object at 0x...>

    But IMHO this is a questionable design and should only be used for special use cases.但恕我直言,这是一个有问题的设计,应该只用于特殊用例。

'Simple is better than complex' and 'Practicality beats purity' -- PEP 20 “简单胜于复杂”和“实用性胜过纯粹” ——PEP 20

 #What I want to do d.Stats() d.team_standings() d.player_stats() d.fixture_stats()

Your examples are all in the context of a single season.你的例子都是在一个季节的背景下。 As such, I would simply make it one class SeasonStats with all the methods you want to use.因此,我会简单地将它与您想要使用的所有方法一起SeasonStats一个类SeasonStats This also makes it clear that these methods are restricted to that single season.这也清楚地表明这些方法仅限于那个单一的季节。

class SeasonStats:
    ...
    def __init__(self, league='EN_PR', season='2019/2020'):
        ...

        ### Included from '__init__'s of previous subclasses ###
        self.fixture_ids = [fix['id'] for fix in self.load_season_fixture().values()]
        self.team_ids = [team['id'] for team in self.load_season_teams().values()]
        self.player_ids = self.load_season_players()

    def load_season_fixture(self):
        ...
    def load_season_players(self):
        ...
    def load_season_teams(self):
        ...
    def fixture_stats_singel(self, fixture):
        ...
    def fixture_stats(self):
        ...
    def player_stats_singel(self, player):
        ...
    def player_stats(self):
        ...
    def team_standings_singel(self, team_id):
        ...
    def team_standings(self):
        ...

Note that I've subtly changed the variable names included from the previous subclasses __init__ s请注意,我巧妙地更改了先前子类__init__包含的变量名称

And then indeed just using it as:然后确实只是将其用作:

season_19_20 = SeasonStats(season='2019/2020')
season_19_20.team_standings()
season_19_20.player_stats()
season_19_20.fixture_stats()

Some variable naming advice一些变量命名建议

d , e , f d , e , f

I would advise against using a , b , c , etc... Memory is cheap and screens are large enough: don't be afraid to use meaningful names such as season .我建议不要使用abc等...内存便宜且屏幕足够大:不要害怕使用有意义的名称,例如season

Lists are plural列表是复数

When talking about a list of IDs, you naturally use the plural 'IDs' already.在谈论 ID 列表时,您自然会使用复数的“ID”。 By naming your variable as such, you can easily distinguish between lists of things and single things.通过这样命名变量,您可以轻松区分事物列表和单个事物。 This also makes it very natural to use in eg for -loops:这也使得在例如for循环中使用变得非常自然:

team_ids = [team['id'] for team in ...]
for team_id in team_ids:
    do_something_with(team_id)

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

相关问题 我们可以在python 2.7中从子类的类方法中调用父类的实例方法吗? - Can we call instance method of parent class from class method of child class in python 2.7? 如何在Python的子类中调用和覆盖父类方法 - How to call and override a Parent class method from Child class in Python Python 如何从父元类调用子 class 方法 - Python How to call child class method from Parent metaclass 从父 class 实例创建子 class 实例,并从子 class 实例调用父方法 - Create child class instances from parent class instance, and call parent methods from child class instance 如何从python中的子类静态方法访问父类实例方法? - How to access parent class instance method from child class static method in python? 如何决定从父类或子类中调用子类中的重写方法? - How can I decide to call an overrided method in child class from either parent or child class? 如何在父类方法中调用子类方法? - How do I call a Child class method from within a Parent class Method? 如何判断父 class 的 function 是由子 class 的类方法或实例方法调用的? - How can I tell a function of parent class is called by classmethod or instance method from child class? 在Python 2中从子类调用父类方法 - Call a parent class method from a child class in Python 2 不能从父 class 调用子 class 方法 - Can't call child class method from parent class
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM