Python - UnboundLocalError: локальная переменная 'd', на которую ссылается перед присваиванием - PullRequest
0 голосов
/ 12 ноября 2019

Эта функция:

def weighted_choice(self, dna):

    """
    Chooses a random element from tags.
    Weight determines the probability 
    of choosing its respective item. 
    """

    weight_total = sum((d[1] for d in dna))

    n = random.uniform(0, weight_total)

    for d, weight in dna:
        if n < weight:
            return d
        n = n - weight

    return d

возвращает следующую ошибку:

Traceback (most recent call last):
  File "/usr/src/app/project/api/classifiers/metadata/bio/replicate.py", line 39, in brandio_genetics
    client_and_product_genes = bio.fitness(place_dna, client_dna)
  File "/usr/src/app/project/api/classifiers/metadata/bio/dna.py", line 553, in fitness
    # print each offspring
  File "/usr/src/app/project/api/classifiers/metadata/bio/dna.py", line 508, in crossover
    # genre 2
  File "/usr/src/app/project/api/classifiers/metadata/bio/dna.py", line 440, in weighted_choice
UnboundLocalError: local variable 'd' referenced before assignment

структура данных:

dna1 = {'patalanov': {'indie pop': 100, 'indie': 97, 'australian': 90, '80s': 52, 'alternative': 52, 'new wave': 27, 'jangle pop': 26, 'seen live': 25, 'rock': 23, 'indie rock': 23, 'pop': 21, 'australia': 16, 'post-punk': 15, 'alternative rock': 11, 'Brisbane': 10, 'twee': 6, 'college rock': 5, 'singer-songwriter': 5, 'Post punk': 5, 'Aussie': 4, 'The Go-Betweens': 4, 'punk': 3, 'power pop': 3, 'elegant': 3, "80's": 3, 'alternative pop': 3, 'Favourites': 3, 'indie-pop': 3, 'guitar pop': 3, 'All': 3, 'twee pop': 2, 'romantic': 2, '90s': 2, 'Passionate': 2, 'literate': 2, 'melancholy': 2, 'Favorite Artists': 2, 'soft': 2, 'male vocalists': 2, 'oz': 2, 'emusic': 2, 'neo acoustic': 2, '80s indie': 2, 'postcard': 2, 'Grant McLennan': 2, 'Robert Forster': 2, '70s': 2, 'emo': 2, 'folk': 2, 'favorites': 2, 'indiepop': 2, 'americana': 2, 'Reflective': 2, 'genius': 2, 'Alt-country': 2, 'Bittersweet': 2, '00s': 2, 'sophisticated': 2, '1980s': 2, 'wistful': 2, 'jangle': 2, 'c86': 2, 'Left of the Dial': 2, 'Very Good': 2, 'Godlike': 2, 'old favorites': 2, 'wrongly tagged as twee': 2, 'hi fidelity': 2, 'jangle-pop': 2, 'records and tapes': 2}}

dna2 = {'Suplicy': {'electronica ': 288.0, 'art rock ': 290.0, 'chillout ': 288.0, 'genius ': 290.0, 'trip-hop ': 287.0, 'psychedelic ': 288.0, 'indie pop ': 287.0, 'ambient ': 288.0, 'indie rock ': 291.0, 'post-rock ': 287.0, 'alternative rock ': 291.0, 'seen live ': 288.0, 'melancholic ': 290.0, 'Awesome ': 291.0, 'radiohead ': 295.0, 'emo ': 286.0, 'rock ': 292.0, 'indie ': 289.0, '90s ': 5.0, 'pop ': 288.0, 'britpop ': 289.0, 'british ': 293.0, 'classic rock ': 288.0, 'better than radiohead ': 288.0, 'overrated ': 288.0, 'alternative ': 290.0, 'Progressive ': 289.0, 's ': 283.0, 'Favorite ': 288.0, 'electronic ': 289.0, 'Experimental Rock ': 289.0, 'beautiful ': 290.0, 'melancholy ': 290.0, 'idm ': 288.0, 'Progressive rock ': 288.0, 'favorites ': 288.0, 'english ': 288.0, 'male vocalists ': 289.0, 'experimental ': 288.0, 'UK ': 290.0}}

послеtraceback:

def crossover(self, dna1, dna2):

        """
        Mixes dna1 and dna2.
        """

        global breed
        # get alleles for gene 1
        A = self.alleles(dna1)[1]
        a = self.alleles(dna1)[2]
        # get alleles for gene 2
        B = self.alleles(dna2)[1]
        b = self.alleles(dna2)[2]
        # format alleles as dictionaries
        AB, Ab, Ba, ab = ({} for i in range(4))
        # genre 1
        AB[str(self.weighted_choice(A))]='A'
        AB[str(self.weighted_choice(B))]='B'
        # genre 2
        Ab[str(self.weighted_choice(A))]='A'
        Ab[str(self.weighted_choice(b))]='b'
        # genre 3
        Ba[str(self.weighted_choice(B))]='B'
        Ba[str(self.weighted_choice(a))]='a'
        # genre 4
        ab[str(self.weighted_choice(a))]='a' 
        ab[str(self.weighted_choice(b))]='b'

        # pick a random number
        x = random.random()
        # set percentage
        if x < 0.25:
            # if low, generate recessive genotypes
            genotype = random.choice([ab])
            breed = ' '.join([k for k in genotype])
            #return genotype
        else:
            # if low, generate dominant genotypes
            genotype = random.choice([AB, Ab, Ba])
            breed = ' '.join([k for k in genotype])


        return (genotype, breed)




def fitness(self, dna1, dna2, generations=600):

        '''
        Most adapted phenotype after many generations.
        '''

        # container for unique breeds
        offspring = set()
        # fetch million song dataset 
        pool = self.genome()
        # test for many generations
        for generation in range(generations):
            print ("Generation %s..." % (generation))
            # mix phenotype
            breed = self.crossover(dna1,dna2)[1]
            # print each offspring
            print (breed)
            # build genotype
            offspring.add(breed)


        # container for sequences
        matches = []
        # lookup offspring in genetic pool
        for o in sorted(offspring):
            for p in pool:
                # compare genetic sequences
                seq = difflib.SequenceMatcher(None, a=o.lower(), b=p.lower())
                print (o, p, round(seq.ratio(), 4))
                # sort matches by similarity ratio
                matches.append([o, p, round(seq.ratio(), 4)])

        # order fittest by descending order
        # similarity = sorted(matches, key=lambda x: x[2], reverse=True)
        similarity = sorted(matches, key=lambda x: x[2], reverse=True)

        # containers for optimized genetic values
        fit = []
        # add
        for m in matches:
            # if m[2] == 1.0:
            #   fit.append(m)
            if 0.8880 <= m[2] <= 1.0:
                fit.append(m)

        return sorted(fit, key=lambda x: x[2], reverse=True)


def alleles(self, dna):

        global allele
        # each user is one
        individual = dna.keys()
        # containers for data
        total = []
        dominant = []
        recessive = []

        for k, v in dna.items():
            # track gene strength # python 3 requires list for indexing
            weight = list(v.values())
            # add all weights 
            total.append(weight[0])
            # each tag is a 'gene'
            gene = v.keys()
            # format in allele fashion
            allele = zip(gene, weight)
            # get the average weight for tags
            mean = sum(total)/len(total)
            # print allel
            for a in allele:
                # above avg is a dominant tag
                if a[1] > mean:
                    dominant.append(a)
                elif a[1] == 1.0:
                    dominant.append(a)
                    recessive.append(a)
                # below avg is a recessive tag
                else:
                    recessive.append(a)


        return (individual, dominant, recessive)

что не так?

Ответы [ 2 ]

1 голос
/ 12 ноября 2019

Взять это в качестве примера:

>>> def f(a):
...     for d in a:
...         if d % 2 == 0:
...             return d
...     return d  # You're returning d, but if the list is empty d is expected to be undefined
... 
>>> f([5])
5
>>> f([5, 5, 2])
2
>>> f([])
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 5, in f
UnboundLocalError: local variable 'd' referenced before assignment

Если вы передадите пустой список (в данном случае f([])), цикл for никогда не произойдет, и локальная переменная d никогда не будет создана.

Это означает, что вы получаете эту ошибку, потому что ваша итерация днк не имеет никаких элементов. Два варианта:

  1. Возвращать значение по умолчанию, когда днк пуст
def weighted_choice(self, dna):

    """
    Chooses a random element from tags.
    Weight determines the probability 
    of choosing its respective item. 
    """

    weight_total = sum((d[1] for d in dna))

    n = random.uniform(0, weight_total)

    for d, weight in dna:
        if n < weight:
            return d
        n = n - weight

    return 0 if not dna else d  # return 0 if dna is empty (not dna). otherwise return d
Избегайте вызова weighted_choice, если днк пуст
# Wherever you're calling the weighted_choice method.
if dna:
    self.weighted_choice(dna)

РЕДАКТИРОВАТЬ:

Прежде всего вы вызываете дважды метод аллелей для каждого днна1и dna2

Я бы изменил это:

A = self.alleles(dna1)[1]
a = self.alleles(dna1)[2]

B = self.alleles(dna2)[1]   
b = self.alleles(dna2)[2]

на:

# It seems like you only care about 2nd and 3rd elements being
# returned, so _ will silently take the `individual` value
_, A, a = self.alleles(dna1)
_, B, b = self.alleles(dna2)

Примечания:

  • Только два вызова ирасширение кортежа делает трюк. Правильным переменным присваиваются значения, возвращаемые с помощью return (individual, dominant, recessive).

Однажды сказав, что либо dominant, либо recessive пусты. Сама ошибка должна быть внутри вашего метода аллелей.

    def alleles(self, dna):
        # Your code goes here. Make sure it does what you're expecting.
        # And if dominant and/or recessive are not expected to be empty
        # with the given input (aka. dna) you have to fix this method.

        print('dominant:', dominant)    
        print('recessive:', recessive)

        return (individual, dominant, recessive)
0 голосов
/ 12 ноября 2019

Вы не упомянули, что объект днк относится к какому типу.

1.Для предположим, что днк является диктом, повторяем дикт с элементами метода.

for d, weight in dna.items():
    if n < weight:
        return d
    n = n - weight

return d

2. Если днкСписок, кортеж или набор, итерация по нему методом перечисления.

for d, weight in enumerate(dna):
    if n < weight:
        return d
    n = n - weight

return d
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...