【问题标题】:How best to create object variables from a method如何最好地从方法创建对象变量
【发布时间】:2019-07-29 03:16:51
【问题描述】:

设置由方法设置的对象变量的最佳方法是什么?下面的方法是首先在__init__() 中定义self.toppings,然后在select_toppings() 方法中设置值,是如何设置self.toppings 变量的好习惯吗?如果您有更好的建议,请告诉我。谢谢。

class Pizza:

    def __init__():
        self.toppings = None 

    def select_toppings(input):
        self.toppings = input  

【问题讨论】:

  • 还有 gettersetter 方法,您可以查看
  • 您的代码是很好的做法。它将允许阅读您的代码的开发人员仅通过查看构造函数就知道存在哪些实例属性。另一方面,只有在 Python 中设置属性的方法并不常见。

标签: python class oop object design-patterns


【解决方案1】:

主要问题是:当一个诚实的程序员写作时会发生什么:

pizza = Pizza()
pizza.do_something()

do_something() 需要self.toppings != None

记住:构造函数的作用是正确初始化对象。所有必填字段都应在构造结束时初始化。

如果对象的初始化变得过于复杂(我想说:只要构造函数不仅仅为字段赋值),请使用creational pattern。以工厂为例:

class Pizza:
    @staticmethod
    def create(topping_list):
        toppings = Toppings(topping_list)
        return Pizza(toppings)

    def __init__(self, toppings):
        self._toppings = toppings

    ...

或建设者:

class PizzaBuilder:
    def __init__(self):
        self._toppings = DEFAULT_TOPPINGS
        self._size = DEFAULT_SIZE

    def build(self):
        return Pizza(self.toppings, self._size)

    def toppings(self, toppings):
        self._toppings = toppings
        return self

    def size(self, size):
        self._size = size
        return self

class Pizza:
    def __init__(self, toppings, size):
        self._toppings = toppings
        self._size = size

您可以创建所需的所有组合:

pizza1 = PizzaBuilder().build() # default pizza
pizza2 = PizzaBuilder().size(10).build() # big pizza with default toppings
pizza3 = PizzaBuilder().toppings(t1).build() # ...

创建模式的一个优点是您的对象已完全初始化,并且在大多数情况下是不可变的。简单来说,setter 和 getter 是分开的,你的程序设计就更简洁了。

【讨论】:

  • 嗨,这是一个很好的方式来分离builder和pizza类。但是我无法理解如何链接PizzaBuilder()Pizza()
  • 它们应该在同一个模块中。隐式链接是PizzaBuilder.build 返回一个Pizza。如果需要,您可以将 @staticmethod def builder(): return PizzaBuilder() 添加到 Pizza 类。第二个例子是:Pizza.builder().size(10).build().
【解决方案2】:

您可以将toppings 直接传递给构造函数。 (不要使用input作为变量名,因为它是python内置函数)

class Pizza:

    def __init__(self, toppings):
        self.toppings = toppings

pz = Pizza('cheese')
print(pz.toppings)

输出将是cheese

【讨论】:

  • 这个原则是否适用于更大的班级?它不会在 __init__() 中投入大量工作吗?谢谢。
  • __init__ 就是为此而生的。你可以在__init__ 中传递你想要实例化类的默认参数,然后在其他实例方法中使用它们,(除非你的用例不同?)
【解决方案3】:

这是您可以使用property 设置的另一种方式

class Pizza:
    def __init__(self):
        self._toppings = None

    def get_toppings(self):
        print("get_toppings called!")
        return self._toppings

    def set_toppings(self, x):
        print("set_toppings called!")
        self._toppings = x

    toppings = property(get_toppings, set_toppings)

margherita = Pizza()
margherita.set_toppings("mozzarella cheese")
print(margherita.get_toppings())

# outputs 
mozzarella cheese

没有setget 方法的一个陷阱是这个,我希望你能看到它是如何导致更改变量的问题。

class Pizza:

    def __init__(self, toppings, dough):
        self.toppings = toppings
        self.pizza = toppings + ', ' + dough

pz = Pizza('cheese', 'flour')
pz.toppings = "chicken"
print(pz.toppings)
print(pz.pizza)

# outputs 
chicken
cheese, flour

【讨论】:

  • 有道理。感谢您的提示。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-17
  • 2018-12-19
  • 1970-01-01
  • 2012-01-14
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多