简体   繁体   English

类中的 Python 条件语句

[英]Python conditional statement within a Class

What is the best way to achieve having class attributes that change, based on input that has been passed in via a cli argument?根据通过 cli 参数传入的输入,实现类属性发生变化的最佳方法是什么?

What I've written works perfectly fine, however feels overly messy and bad design.我写的东西非常好,但是感觉过于凌乱和糟糕的设计。 Is there a better way to go about this?有没有更好的方法来解决这个问题?

The example below has four different inputs, however as this program grows larger this would become very messy.下面的例子有四个不同的输入,但是随着这个程序变大,这将变得非常混乱。

Here's some short example code;这是一些简短的示例代码;

class Example(object):

    def __init__(self, var1):
        self.var1 = var1
        self.var2 = None
        self.var3 = None
        self.var4 = None

        if var1 == 'foo':
            self.var2 = 'foo2'
            self.var3 = 'foo3'
            self.var4 = 'foo4'
        elif var1 == 'bar':
            self.var2 = 'bar2'
            self.var3 = 'bar3'
            self.var4 = 'bar4'
        elif var1 == 'foobar':
            self.var2 = 'foobar2'
            self.var3 = 'foobar3'
            self.var4 = 'foobar4'
        elif var1 == 'barfoo':
            self.var2 = 'barfoo2'
            self.var3 = 'barfoo3'
            self.var4 = 'barfoo4'


def main()

    parser = argparse.ArgumentParser()
    parser.add_argument('input')
    args = parser.parse_args()

    example = Example(args.input)

    print(example.var2) # returns 'foo2'

Example of calling with an argument;带参数调用的示例;

python main.py foo

There are many ways to clean this up, as suggested in the comments.正如评论中所建议的,有很多方法可以清理它。 For something of the size and scale of your example, I would do something like this:对于你的例子的大小和规模,我会做这样的事情:

class Example:
    _DEPENDENT_VALS = {
        'foo': ('foo2', 'foo3', 'foo4'),
        'bar': ('bar2', 'bar3', 'bar4'),
        'foobar': ('foobar2', 'foobar3', 'foobar4'),
        'barfoo': ('barfoo2', 'barfoo3', 'barfoo4')
    }

    def __init__(self, var1):
        self.var1 = var1
        self.var2 = None
        self.var3 = None
        self.var4 = None

        if var1 in Example._DEPENDENT_VALS:
            self.var2, self.var3, self.var4 = Example._DEPENDENT_VALS[var1]

This method might not always be appropriate depending on the number and type of values you're setting but it's one way to go about it.根据您设置的值的数量和类型,此方法可能并不总是合适的,但这是一种方法。

` ls=['foo','bar','foobar','barfoo'] #add the list of prefixes ` ls=['foo','bar','foobar','barfoo'] #添加前缀列表

if self.var1 in ls:如果 ls 中的 self.var1:

self.var2= f'{self.var1}2'
self.var3= f'{self.var1}3'
self.var4= f'{self.var1}4'

` `

Define a dict mapping prefixes to a tuple of the three modifiers, then use it to initialize them:定义一个dict映射前缀到三个修饰符的tuple ,然后用它来初始化它们:

class Example:
    _var_suffixes = {'foo': ('1', '2', '3'),
                     'bar': ('1', '2', '3'),
                     'foobar': ('1', '2', '3'),
                     'barfoo': ('1', '2', '3'),
                     }
    def __init__(self, var1):
        self.var1 = var1
        self.var2 = None
        self.var3 = None
        self.var4 = None

        if var1 in self._var_suffixes:
            suf2, suf3, suf4 = self._var_suffixes[var1]
            self.var2 = var1 + suf2
            self.var3 = var1 + suf3
            self.var4 = var1 + suf4

Optionally, this may make more sense to store var2 through var4 as a list (especially if the number of suffixes is variable by key), in which case you'd do something like this, which is even simpler:或者,将var2var4存储为list可能更有意义(特别是如果后缀的数量是按键可变的),在这种情况下,您可以执行以下操作,甚至更简单:

class Example:
    _var_suffixes = {'foo': ('1', '2'),
                     'bar': ('1', '2', '3'),
                     'foobar': ('1', '2', '3', '4'),
                     'barfoo': ('1', '2', '3', '4', '5'),
                     }
    def __init__(self, var1):
        self.var1 = var1
        self.varlist = []

        for suf in self._var_suffixes.get(var1, ()):
            self.varlist.append(var1 + suf)

    # Optional property for access by name
    @property
    def var2(self):
        try:
            return self.varlist[0]
        except IndexError:
            return None

The class body is just Python code.类主体只是 Python 代码。 It has specific scope rules, but anything goes otherwise.它有特定的范围规则,但除此之外什么都没有。 This means you can create functions conditionally:这意味着您可以有条件地创建函数:

class C: if some_condition: def optional_method(self): pass or pull methods from elsewhere: C类:if some_condition:def optional_method(self):从别处传递或拉取方法:

import some_module导入 some_module

class D: method_name = some_module.function_that_accepts_self etc. D 类:method_name = some_module.function_that_accepts_self 等。

One approach is to keep __init__ as "dumb" as possible, define separate class methods for each "style" of object, and push the burden of selecting the right class method to call to the caller.一种方法是尽可能保持__init__为“哑”,为每个“样式”对象定义单独的类方法,并将选择正确的类方法调用的负担推给调用者。

class Example:

    def __init__(self, var1, var2, var3, var4):
        self.var1 = var1
        self.var2 = var2
        self.var3 = var3
        self.var4 = var4

    @classmethod
    def foo(cls):
        return cls('foo', 'foo2', 'foo3', 'foo4')

    @classmethod
    def bar(cls):
        return cls('bar', 'bar2', 'bar3', 'bar4')

    # etc

# Instead of Example('foo')
e = Example.foo()

The only thing you lose here is the ability to pass an unknown value to Example and get a properly initialized value back, for example,您在这里唯一失去的是将未知值传递给Example并获得正确初始化值的能力,例如,

x = "..."  # Assumed to be foo, bar, foobar, or barfoo
e = Example(x)

However, the caller can always use whatever method you might have hidden in side Element.__init__ to pick the values for var2 et al.但是,调用者始终可以使用您可能隐藏在侧Element.__init__任何方法来选择var2等的值。 to pick which class method to all.选择所有的类方法。 For example,例如,

x = "foo"
e = getattr(Example, x)()  # e = Example.foo()

Don't know if the best option but assuming that actual values aren 'foo1' 'foo2' but something else or more complex I would go for updating the self.不知道是否是最好的选择,但假设实际值是'foo1' 'foo2'但其他或更复杂的东西我会去更新 self. dict字典

Two ways (I think the seccond is more clear)两种方式(我觉得第二种更清楚)

class A():
    def __init__(self,var1):
        self.var1 = var1
        fooDict = {'var2':'foo2','var3':'foo3','var4':'foo4'}
        foovarDict = {'var2':'foovar2','var3':'foovar3','var4':'foovar4'}
        if var1 == 'foo':
            self.__dict__ = {**self.__dict__,**fooDict}
        elif var1 == 'foovar':
            self.__dict__ = {**self.__dict__,**foovarDict}
            
    def getVars(self):
        print(self.var1)
        print(self.var2)
        print(self.var3)
        print(self.var4)



a = A('foo')
a.getVars()

#ouputs
#foo
#foo2
#foo3
#foo4

b = A('foovar')
b.getVars()

#outputs
#foovar
#foovar2
#foovar3
#foovar4

Second way:第二种方式:

class A():
    def __init__(self,var1):
        self.var1 = var1
        fooDict = {'var2':'foo2','var3':'foo3','var4':'foo4'}
        foovarDict = {'var2':'foovar2','var3':'foovar3','var4':'foovar4'}
        if var1 == 'foo':
            self.__dict__.update(fooDict)
        elif var1 == 'foovar':
            self.__dict__.update(foovarDict)

    def getVars(self):
        print(self.var1)
        print(self.var2)
        print(self.var3)
        print(self.var4)

a = A('foo')
a.getVars()


b = A('foovar')
b.getVars()

with same outputs具有相同的输出

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

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