使用@property以某种方式开始递归调用?

时间:2016-04-08 16:01:29

标签: python-3.x properties

我正在使用属性类在S3上为AWS包装器类设置目标。如果还设置了infile,它应该只设置目的地。 (我已经意识到最好的解决办法就是将这个特定的课程分开,因为它试图做好两件事,而不是一件事。)

尽管如此,我很好奇导致这种递归堆栈溢出的原因。这是我班级的相关部分:

class S3Loads(PrettyStr):
    def __init__(self,
                 infile=None,
                 s3_destination=None,
                 s3_bucket=config3.S3_BUCKET,
                 s3_credentials=config3.S3_INFO,
                 database_credentials=config3.REDSHIFT_POSTGRES_INFO_PROD):
        """
        This class automates the upload of a file to AWS S3.

        :param infile: A gzipped csv file
        :param s3_destination: The path to the desired folder on S3.  The file
        will be named by joining the s3_destination and the infile name.
        :param s3_bucket: The name of the bucket on S3

        :return: None, but will write out to logging file.
        """
        self.infile = infile
        self.s3_destination = s3_destination
        self.bucket_name = s3_bucket
        self.s3_creds = s3_credentials
        self.database_credentials = database_credentials

    @property
    def s3_destination(self):
        return self.s3_destination
    # TODO This is kicking off a recursive call, find out why
    @s3_destination.setter
    def s3_destination(self, s3_destination):
        if self.infile:
            if config3.SYSTEM == 'OSX':
                self.s3_destination = path.join(
                s3_destination,
                self.infile.split('/')[-1]
                )
            elif config3.SYSTEM == 'Windows':
                self.s3_destination = path.join(
                s3_destination,
                self.infile.split('\\')[-1]
                )
        else:
            logging.warning('S3 Destination is being set to "None" due to '
                            'no infile being set.  Please set an infile '
                            'and then set the S3 Destination.')
            self.s3_destination = None

以下是正在进行此项测试的单元测试:

def test_setting_s3_destination_without_infile_set_it_to_none(self):
        s3 = aws_utils.S3Loads()
        def test_func():
            s3.s3_destination = 'Some destination'
        self.assertIsNone(s3.s3_destination)

    def test_can_set_s3_destination_with_infile_specified(self):
        s3 = aws_utils.S3Loads()
        s3.infile='testfile.txt'
        s3.destination='testloads/test1'
        self.assertEqual(s3.destination, 'testloads/test1/testfile.txt')

我只是对导致递归的原因感到好奇。

1 个答案:

答案 0 :(得分:1)

每次Python遇到self.s3_destination时,都会调用s3_destination函数。由于返回值self.s3_destination引用了该属性,因此s3_destination函数被递归调用,无限制地...

@property
def s3_destination(self):
    return self.s3_destination

解决此问题的标准方法是使用私有属性self._s3_destination

class S3Loads(PrettyStr):
    def __init__(self,...)
        ...
        self._s3_destination = s3_destination

    @property
    def s3_destination(self):
        return self._s3_destination


    @s3_destination.setter
    def s3_destination(self, value):
        if self.infile:
            if config3.SYSTEM == 'OSX':
                self._s3_destination = path.join(
                value,
                self.infile.split('/')[-1]
                )
            elif config3.SYSTEM == 'Windows':
                self._s3_destination = path.join(
                value,
                self.infile.split('\\')[-1]
                )
        else:
            logging.warning('S3 Destination is being set to "None" due to '
                            'no infile being set.  Please set an infile '
                            'and then set the S3 Destination.')
            self._s3_destination = None