Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/three.js/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在python中,将类实例分配给类属性是一种好的做法吗?_Python_Class_Object_Relationship_Composition - Fatal编程技术网

在python中,将类实例分配给类属性是一种好的做法吗?

在python中,将类实例分配给类属性是一种好的做法吗?,python,class,object,relationship,composition,Python,Class,Object,Relationship,Composition,我正在尝试在python中使用类组合,我想知道在python中将类实例分配给类属性是否是一种好的做法。下面是我想到的两个例子。如果一些有经验的程序员能告诉我何时使用它,我将不胜感激 (一) (二) 像这样的事情总是描述性的!是否每个B都有A对象?如果是这样,那么你最好使用#1。B是某种容器,在这种情况下,它有一个A对象吗?使用#2 例如,假设我正在构建Tile对象的地图。每个平铺对象都有一个位置,我将其进一步抽象为位置对象,如下所示: class Tile(object): def _

我正在尝试在python中使用类组合,我想知道在python中将类实例分配给类属性是否是一种好的做法。下面是我想到的两个例子。如果一些有经验的程序员能告诉我何时使用它,我将不胜感激

(一)


(二)


像这样的事情总是描述性的!是否每个
B
都有
A
对象?如果是这样,那么你最好使用#1。
B
是某种容器,在这种情况下,它有一个
A
对象吗?使用#2

例如,假设我正在构建
Tile
对象的地图。每个
平铺
对象都有一个
位置
,我将其进一步抽象为
位置
对象,如下所示:

class Tile(object):
    def __init__(self, location, *args, **kwargs):
        self.location = location

class Location(object):
    def __init__(self, x, y):
        self.x = x
        self.y = y

x2_y3 = Location(2, 3)
tile = Tile(x2_y3)
tile.location.x # 2
现在我也可以这样做:

class Tile(object):
    def __init__(self, location: "(x, y)", *args, **kwargs):
        x, y = location
        self.location = Location(x, y)

class Location(object):
    def __init__(self, x, y):
        self.x = x
        self.y = y

tile = Tile(2,3) # builds its own location object
在这种情况下,第二种策略可能更可取,但我更喜欢第一种策略,因为它更易于扩展。如果以后我移动到3D空间,我可以执行以下操作:

class Location3D(Location):
    def __init__(self, x, y, z):
        self.z = z
        super().__init__(x, y)

tile = Tile(Location3D(2, 3, -1))

在第二种策略中,这将失败,因为
Tile
s始终具有
Location
对象。您必须使用monkey patch
Tile
来实现该功能,或者构建一个新的
Tile3D
对象,该对象可能与其他
Tile
配合使用,也可能与其他
Tile
配合不好。

类似的内容始终是描述性的!是否每个
B
都有
A
对象?如果是这样,那么你最好使用#1。
B
是某种容器,在这种情况下,它有一个
A
对象吗?使用#2

例如,假设我正在构建
Tile
对象的地图。每个
平铺
对象都有一个
位置
,我将其进一步抽象为
位置
对象,如下所示:

class Tile(object):
    def __init__(self, location, *args, **kwargs):
        self.location = location

class Location(object):
    def __init__(self, x, y):
        self.x = x
        self.y = y

x2_y3 = Location(2, 3)
tile = Tile(x2_y3)
tile.location.x # 2
现在我也可以这样做:

class Tile(object):
    def __init__(self, location: "(x, y)", *args, **kwargs):
        x, y = location
        self.location = Location(x, y)

class Location(object):
    def __init__(self, x, y):
        self.x = x
        self.y = y

tile = Tile(2,3) # builds its own location object
在这种情况下,第二种策略可能更可取,但我更喜欢第一种策略,因为它更易于扩展。如果以后我移动到3D空间,我可以执行以下操作:

class Location3D(Location):
    def __init__(self, x, y, z):
        self.z = z
        super().__init__(x, y)

tile = Tile(Location3D(2, 3, -1))

在第二种策略中,这将失败,因为
Tile
s始终具有
Location
对象。您必须使用monkey patch
Tile
来实现该功能,或者构建一个新的
Tile3D
对象,该对象可能与其他
Tile
配合良好,也可能与其他
配合不良。

我建议使用方法1,因为它比方法2更支持封装

为什么我们关心封装?在方法1中,
objB
可以在一条语句中初始化,因此追踪初始化错误的位置更少。想要使用类的代码不需要知道初始化类所需的一系列步骤;只有一条语句和一个参数列表。这种简单性导致更少的错误和更灵活和可维护的代码


尽管Python中的封装没有其他一些语言(如Java)中的封装那么强,但它仍然是一种很好的实践

我建议使用方法1,因为它比方法2更支持封装

为什么我们关心封装?在方法1中,
objB
可以在一条语句中初始化,因此追踪初始化错误的位置更少。想要使用类的代码不需要知道初始化类所需的一系列步骤;只有一条语句和一个参数列表。这种简单性导致更少的错误和更灵活和可维护的代码

尽管Python中的封装没有其他一些语言(如Java)中的封装那么强,但它仍然是一种很好的实践

re。1) ,我将显式地传递A实例,而不是在B._uuuinit_uuuuuuuu中构建它。原因是,在非常重要的情况下,您可能希望A具有不同的初始化值。或者,您可能希望共享A实例—否则,这是一种1-1关系,具有限制性

class A:
   def __init__(self):
      self.x = 10

class B:
   def __init__(self, instanceA):
      self.y = instanceA

#fire-and forget A
objB = B(A())

#can still do something with the instance
a = A()
objB2 = B(a)
例如,我经常使用具有“manager”或“parent”属性的B类。比如说,一个表类有n个列子类。每一列都有一个对父表的引用,而不是动态地组成一个

如果您基本上不需要担心实例的初始值,则可以进一步优化:

class B:
   #instanceA uses a default value of None
   def __init__(self, instanceA = None):
      #assign the instanceA if it was passed or build your own on the fly
      if instanceA is None:
          self.y = A()
      else:
          self.y = instanceA
p、 不要这样做来启动默认实例。默认值只计算一次,并且只要不显式传递值,就会分配相同的实例

   def __init__(self, instanceA = A()):
        ....
re。2) 我不会用事后作文。如果忘记设置.y属性怎么办?实例应该尽可能不需要多个链式调用和修改才能使用(与skrrgwasme所说的差不多)。Python具有这种灵活性,是的,这并不意味着它应该在没有充分理由的情况下使用

最后,虽然您不需要设置self.y=None,但一些Python代码分析工具仅当在uu init_uu方法上设置实例属性时才会拾取它们。

re。1) ,我将显式地传递A实例,而不是在B._uuuinit_uuuuuuuu中构建它。原因是,在非常重要的情况下,您可能希望A具有不同的初始化值。或者,您可能希望共享A实例—否则,这是一种1-1关系,具有限制性

class A:
   def __init__(self):
      self.x = 10

class B:
   def __init__(self, instanceA):
      self.y = instanceA

#fire-and forget A
objB = B(A())

#can still do something with the instance
a = A()
objB2 = B(a)
例如,我经常使用具有“manager”或“parent”属性的B类。比如说,一个表类有n个列子类。每一列都有一个对父表的引用,而不是动态地组成一个

如果您基本上不需要担心实例的初始值,则可以进一步优化:

class B:
   #instanceA uses a default value of None
   def __init__(self, instanceA = None):
      #assign the instanceA if it was passed or build your own on the fly
      if instanceA is None:
          self.y = A()
      else:
          self.y = instanceA
p、 不要这样做来启动默认实例。默认值只计算一次,并且只要不显式传递值,就会分配相同的实例

   def __init__(self, instanceA = A()):
        ....
re。2) 我不会用事后作文。如果忘记设置.y属性怎么办?实例应该尽可能不需要多个链式调用和修改才能使用(与skrrgwasme所说的差不多)。Python具有这种灵活性