【问题标题】:Python create if elif in __init__ for package and functionPython 在 __init__ 中为包和函数创建 if elif
【发布时间】:2019-06-11 15:25:43
【问题描述】:

我将所有定义的函数组合成一个class,并使用ifelif进行操作。
我将在下面解释。

首先,我有 3 种类型的情节,combolinebar
我知道如何为这三个情节分别定义函数。

其次,我想使用 if 将这 3 个图组合在一个包中。
我试过的代码是:

import pandas as pd
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt


class AP(object):

    def __init__(self, dt, date, group, value, value2, value3, value4, value5, value6, TYPE):
        self.dt = dt
        self.date = date
        self.group= carrier
        self.value = value
        self.col1 = col1
        self.col2 = col2
        self.col3 = col3
        self.col4 = col4
        self.TYPE = TYPE

        if self.TYPE == "combo":

            def ComboChart(self, dt, date, group, value, TYPE):
                dataset = pd.read_csv(dt)
                dataset['date'] = pd.to_datetime(dataset[date])
                dataset['yq'] = pd.PeriodIndex(dataset['date'], freq='Q')
                dataset['qtr'] = dataset['date'].dt.quarter
                dataset = dataset.groupby([carrier, 'yq', 'qtr'])[value].sum().reset_index()
                dataset['total.YQGR'] = dataset[value] / dataset.groupby(['qtr', carrier])[value].transform('shift') - 1
                dataset = dataset[np.isfinite(dataset['total.YQGR'])]
                dataset['total.R'] = dataset[value] / dataset.groupby(group)[value].transform('first')
                dataset.yq = dataset.yq.astype(str)

                fig, ax1 = plt.subplots(figsize=(12,7))
                ax2=ax1.twinx()
                sns.lineplot(x='yq',y='total.R', data=dataset, hue=group, ax=ax1, legend = None, palette = ('navy', 'r'), linewidth=5)
                ax1.set_xticklabels(ax1.get_xticks(), rotation=45, fontsize=15, weight = 'heavy')
                ax1.set_xlabel("", fontsize=15)
                ax1.set_ylabel("")
                ax1.set_ylim((0, max(dataset['total.R']) + 0.05))
                sns.barplot(x='yq', y='total.YQGR', data=dataset, hue=group, ax=ax2, palette = ('navy', 'r'))
                ax2.set_yticklabels(['{:.1f}%'.format(a*100) for a in ax2.get_yticks()])
                ax2.set_ylabel("")
                ax2.set_ylim((min(dataset['total.YQGR']) - 0.01, max(dataset['total.YQGR']) + 0.2))
                ax2.get_legend().remove()
                ax2.legend(bbox_to_anchor=(-0.35, 0.5), loc=2, borderaxespad=0., fontsize = 'xx-large')
                for groups in ax2.containers:
                    for bar in groups:
                        if bar.get_height() >= 0:
                            ax2.text(
                                    bar.get_xy()[0] + bar.get_width()/1.5,
                                    bar.get_height() + 0.003, 
                                '{:.1f}%'.format(round(100*bar.get_height(),2)), 
                                    color='black',
                                    horizontalalignment='center',
                                    fontsize = 12, weight = 'heavy'
                                    )
                        else:
                            ax2.text(
                                    bar.get_xy()[0] + bar.get_width()/1.5,
                                    bar.get_height() - 0.008, 
                                '{:.1f}%'.format(round(100*bar.get_height(),2)), 
                                    color='black',
                                    horizontalalignment='center',
                                    fontsize = 12, weight = 'heavy'
                                    )
                ax1.yaxis.set_visible(False)
                ax2.yaxis.set_visible(False)
                ax2.xaxis.set_visible(False)
                ax1.spines["right"].set_visible(False)
                ax1.spines["left"].set_visible(False)
                ax1.spines["top"].set_visible(False)
                ax1.spines["bottom"].set_visible(False)
                ax2.spines["right"].set_visible(False)
                ax2.spines["left"].set_visible(False)
                ax2.spines["top"].set_visible(False)
                ax2.spines["bottom"].set_visible(False)
                ax1.set_title(TYPE, fontsize=20)
                plt.show()

                fig.savefig(TYPE, bbox_inches='tight', dpi=600)

        elif self.TYPE == "line":

            def line(self, dt, date, carrier, value, value2, TYPE):
                dataset = pd.read_csv(dt)
                dataset['date'] = pd.to_datetime(dataset[date])
                dataset['yq'] = pd.PeriodIndex(dataset['date'], freq='Q')
                dataset = dataset.groupby([group, 'yq'])[value, value2].sum().reset_index()
                dataset['Arate'] = dataset[value2] / dataset[value]
                dataset.yq = dataset.yq.astype(str)

                fig, ax1 = plt.subplots(figsize=(12,7))
                sns.lineplot(x='yq', y='Arate', data=dataset, hue=group, ax=ax1, linewidth=5)
                ax1.set_xticklabels(dataset['yq'], rotation=45, fontsize = 15)
                ax1.set_xlabel("")
                ax1.set_ylabel("")
                ax1.set_ylim((min(dataset['Arate']) - 0.05, max(dataset['Arate']) + 0.05))
                ax1.set_yticklabels(['{:.1f}%'.format(a*100) for a in ax1.get_yticks()], fontsize = 18, weight = 'heavy')
                ax1.legend(bbox_to_anchor=(0., 1.02, 1., .102), loc=2, borderaxespad=0., ncol = 6)
                ax1.yaxis.grid(True)
                ax1.spines["right"].set_visible(False)
                ax1.spines["left"].set_visible(False)
                ax1.spines["top"].set_visible(False)
                ax1.spines["bottom"].set_visible(False)
                ax1.set_title(TYPE, fontsize = 20)
                plt.show()

                fig.savefig(TYPE, bbox_inches='tight', dpi=600)

        elif self.TYPE == "bar":

            def Bar(self, dt, date, group, value3, value4, value5, value6, TYPE):
                dataset = pd.read_csv(dt, sep = '|')
                dataset['date'] = pd.to_datetime(dataset[date])
                dataset['yq'] = pd.PeriodIndex(dataset['date'], freq='Q')
                dataset = dataset.groupby([group, 'yq'])[value3, value4, value5, value6].sum().reset_index()
                dataset = dataset.groupby([group]).tail(4)
                dataset.yq = dataset.yq.astype(str)
                dataset = pd.melt(dataset, id_vars = [group, 'yq'], value_vars = [value3, value4, value5, value6])
                dataset = dataset.groupby(['variable', group]).value.sum().reset_index()
                dataset['L4Qtr'] = dataset.value / dataset.groupby([group]).value.transform('sum')

                fig, ax1 = plt.subplots(figsize=(12,7))
                sns.barplot(x='variable', y='L4Qtr', data=dataset, hue=group, ax=ax1)
                ax1.set_xticklabels(ax1.get_xticklabels(), fontsize=17.5, weight = 'heavy')
                ax1.set_xlabel("", fontsize=15)
                ax1.set_ylabel("")
                ax1.yaxis.set_ticks(np.arange(0, max(dataset['L4Qtr']) + 0.1, 0.05), False)
                ax1.set_yticklabels(['{:.1f}%'.format(a*100) for a in ax1.get_yticks()], fontsize = 18, weight = 'heavy')
                ax1.legend(bbox_to_anchor=(0., 1.02, 1., .102), loc=2, borderaxespad=0., ncol = 6)
                for groups in ax1.containers:
                    for bar in groups:
                        ax1.text(
                                bar.get_xy()[0] + bar.get_width()/2,
                                bar.get_height() + 0.005, 
                            '{:.1f}%'.format(round(100*bar.get_height(),2)), 
                                color=bar.get_facecolor(),
                                horizontalalignment='center',
                                fontsize = 16, weight = 'heavy'
                                    )
                ax1.spines["right"].set_visible(False)
                ax1.spines["left"].set_visible(False)
                ax1.spines["top"].set_visible(False)
                ax1.spines["bottom"].set_visible(False)
                ax1.set_title(TYPE, fontsize=20)
                plt.show()

                fig.savefig(TYPE, bbox_inches='tight', dpi=600)

第三,我希望其他人可以简单地使用这个模块,如下所示:

import sys
sys.path.append(r'\\users\desktop\module')
from AP import AP as ap

最后,当有人分配TYPE时,它会自动绘制并保存它。

# This will plot combo chart
ap(r'\\users\desktop\dataset.csv', date = 'DATEVALUE', group = 'GRPS', value = 'total', TYPE = 'combo')

以上是理想的想法。我不需要在其中传递value2 ~ value6,因为combo 不使用它们。
当我想要bar

# This will plot bar chart
ap(r'\\users\desktop\dataset.csv', date = 'DATEVALUE', group = 'GRPS', value3 = 'col1', value4 = 'col2', value5 = 'col3', value6 = 'col4', TYPE = 'combo')

我的代码不正确,因为发生了错误。看来我需要在其中传递所有参数。

但是,即使我在其中传递了所有参数。没有错误但没有输出。

有什么建议吗?

【问题讨论】:

  • 这段代码是否与您正在运行的代码完全相同,包括缩进?一方面,dataset['Arate] 缺少一个结束引号。另一方面,您的if self.TYPE == "combo": 行不应具有与def __init__ 行相同的缩进级别。应该在__init__ 中的所有内容都应该比def __init__ 行至少多一级缩进。但是即使你解决了这些问题,你也不能在其他类实例方法中定义类实例方法,所以 ComboChart 和 bar 和 line 将不能作为你对象的方法来访问。
  • 嗨,你能解释一下,为什么你不只为这些类型创建子类?这不是更直接吗?
  • @Kevin 我编辑了上面的缩进。实际上购买我正在运行的代码格式正确。此外,您的意思是我不能通过ComboChartlinebarclass AP() 中定义的函数?
  • @jottbe 你的意思是创建 3 个类,ComboChartlinebar?这是一个选项,但如果我想创建一个“全局”函数(意味着有人只需要我们ap())并且他/她可以分配什么类型,我认为这很方便。
  • @PeterChen:是的,这将是我建议的标准解决方案,如果您出于某种原因想隐藏类结构,只需创建一个包含实际实现的实例并且什么都不做的第四个否则将方法调用转发给实现类(那时可能几乎没有自己的代码)。请参阅下面的答案(评论太小,无法在 ocmment 中写下更多详细信息)。

标签: python function if-statement package user-defined-functions


【解决方案1】:

你能解释一下,为什么你不为这些类型创建子类?那不是更直接吗?

1.) 一种方法是让子类对用户可见,如果您不喜欢这样,

2.) 你可以只创建一种接口类(例如,隐藏在幕后使用的类的 AP,例如,一旦设置类型就会实例化。

3.) 你可以像开始一样工作,但我想你必须让用户可以看到这些方法,因为我猜你实现它的方式,这些函数只在 init 方法(也许你的缩进不太正确)。例如,如果您的 if 语句由 init 方法执行,那么您可以将方法分配给 self.ComboChart= ComboChart 等实例变量,以便能够从外部调用该方法。但是恕我直言,这不是很pythonic,而且更hacky/更少面向对象。

所以我建议 1.) 如果由于某种原因这不可能,那么我会选择解决方案 2。这两种解决方案还允许你形成一个干净的类结构并以这种方式重用代码,而你如果您愿意,仍然可以构建您的简化接口类。

方法 1 的示例(伪代码)如下所示。请注意,我没有测试它,它只是为了给你一个想法,关于以面向对象的方式拆分逻辑。我没有检查您的整个解决方案,因此我不知道您是否总是以相同的方式对数据进行分组。我可能还会将表示逻辑与数据逻辑分开。如果您计划以更多方式显示相同的数据,那将是一个好主意,因为使用当前逻辑,您将重新读取 csv 文件并在每次需要另一个表示时重新处理数据。所以不要让它变得更复杂,而我只是想解释基本原理,我忽略了这一点,并给出了一个基类“Chart”和一个子类“ComboChart”的例子。 "ComboChart" 类知道如何读取/分组数据,因为它继承了 "Chart" 的方法,因此您只需实现一次,因此如果您发现错误或以后想要增强它,您只需要在一个地方做。然后 draw_chart 方法只需要根据选择的表示做不同的事情。用户必须根据他们想要显示的图表类型创建子类的实例并调用 display_chart()。

import pandas as pd
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt


class Chart(object):
    def __init__(self, dt, date, group, value, value2, value3, value4, value5, value6):
        self.dt = dt
        self.date = date
        self.group= carrier
        self.value = value
        self.col1 = col1
        self.col2 = col2
        self.col3 = col3
        self.col4 = col4
        self.TYPE = TYPE
        self.dataset= None

    def _read_data_(self)        
        dataset = pd.read_csv(dt)
        dataset['date'] = pd.to_datetime(dataset[self.date])
        dataset['yq'] = pd.PeriodIndex(dataset['date'], freq='Q')
        dataset['qtr'] = dataset['date'].dt.quarter
        dataset = dataset.groupby([carrier, 'yq', 'qtr'])[value].sum().reset_index()
        dataset['total.YQGR'] = dataset[value] / dataset.groupby(['qtr', carrier])[value].transform('shift') - 1
        dataset = dataset[np.isfinite(dataset['total.YQGR'])]
        dataset['total.R'] = dataset[value] / dataset.groupby(group)[value].transform('first')
        dataset.yq = dataset.yq.astype(str)
        self.dataset= dataset
        return dataset

    def get_data(self):
        if self.dataset is None:
            self._read_data_()
        return self.dataset

    def group_data(self):
        dataset= self.get_data()
        dataset = dataset.groupby([carrier, 'yq', 'qtr'])[value].sum().reset_index()
        dataset['total.YQGR'] = dataset[value] / dataset.groupby(['qtr', carrier])[value].transform('shift') - 1
        dataset = dataset[np.isfinite(dataset['total.YQGR'])]
        dataset['total.R'] = dataset[value] / dataset.groupby(group)[value].transform('first')
        dataset.yq = dataset.yq.astype(str)
        return dataset

    def draw_chart(self):
        pass


class ComboChart(Chart):
    def draw_chart(self):
        dataset = self.group_data()
        fig, ax1 = plt.subplots(figsize=(12,7))
        ax2=ax1.twinx()
        sns.lineplot(x='yq',y='total.R', data=dataset, hue=group, ax=ax1, legend = None, palette = ('navy', 'r'), linewidth=5)
        ax1.set_xticklabels(ax1.get_xticks(), rotation=45, fontsize=15, weight = 'heavy')
        ax1.set_xlabel("", fontsize=15)
        ax1.set_ylabel("")
        ax1.set_ylim((0, max(dataset['total.R']) + 0.05))
        sns.barplot(x='yq', y='total.YQGR', data=dataset, hue=group, ax=ax2, palette = ('navy', 'r'))
        ax2.set_yticklabels(['{:.1f}%'.format(a*100) for a in ax2.get_yticks()])
        ax2.set_ylabel("")
        ax2.set_ylim((min(dataset['total.YQGR']) - 0.01, max(dataset['total.YQGR']) + 0.2))
        ax2.get_legend().remove()
        ax2.legend(bbox_to_anchor=(-0.35, 0.5), loc=2, borderaxespad=0., fontsize = 'xx-large')
        for groups in ax2.containers:
            for bar in groups:
                if bar.get_height() >= 0:
                    ax2.text(
                            bar.get_xy()[0] + bar.get_width()/1.5,
                            bar.get_height() + 0.003, 
                        '{:.1f}%'.format(round(100*bar.get_height(),2)), 
                            color='black',
                            horizontalalignment='center',
                            fontsize = 12, weight = 'heavy'
                            )
                else:
                    ax2.text(
                            bar.get_xy()[0] + bar.get_width()/1.5,
                            bar.get_height() - 0.008, 
                        '{:.1f}%'.format(round(100*bar.get_height(),2)), 
                            color='black',
                            horizontalalignment='center',
                            fontsize = 12, weight = 'heavy'
                            )
        ax1.yaxis.set_visible(False)
        ax2.yaxis.set_visible(False)
        ax2.xaxis.set_visible(False)
        ax1.spines["right"].set_visible(False)
        ax1.spines["left"].set_visible(False)
        ax1.spines["top"].set_visible(False)
        ax1.spines["bottom"].set_visible(False)
        ax2.spines["right"].set_visible(False)
        ax2.spines["left"].set_visible(False)
        ax2.spines["top"].set_visible(False)
        ax2.spines["bottom"].set_visible(False)
        ax1.set_title(TYPE, fontsize=20)
        plt.show()

        fig.savefig(TYPE, bbox_inches='tight', dpi=600)

第二种方法(带有接口类)看起来是一样的,只是你有一个用户知道的第四个类,并且知道如何调用真正的实现。像这样:

class YourInterface:
    def __init__(self, your_arguments, TYPE):
        if TYPE == __ 'ComboChart':
            self.client= ComboChart(your_arguments)
        elif TYPE == ....

    def display_chart(self):
        self.client.display_chart()

但这是一门很无聊的课,不是吗? 如果您的类层次结构非常技术性并且可能会随着时间而改变,如果您想避免库的用户建立对真实类层次结构的依赖关系,那么我只会这样做,一旦您更改层次结构,这种依赖关系可能会被破坏。我猜在大多数情况下,类层次结构保持相对稳定,因此您不需要由接口类创建的这种额外抽象级别。

【讨论】:

  • 我认为第一个和第二个解决方案是好主意。你能解释一下吗?
  • 我看到有人用factory method来做这个但是不知道
  • 是的,它是这样的,但我认为工厂模式在java中更常见,在python中可以更轻松地完成。
猜你喜欢
  • 1970-01-01
  • 2017-05-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多