名称错误:未定义变量

时间:2015-03-05 20:24:32

标签: python

程序计算从点到线,再到第二点的最短路径。另外我需要说明从线的起点到点的交叉点有多长。到目前为止我的代码:

from math import sqrt
numbers_total = []
numbers_canal = []
first_triangle_longest_side_length = 300   #defining the variable

def first_triangle(first_triangle_longest_side_length):
    calculation_one = sqrt(first_triangle_longest_side_length)
    first_triangle_bottom_side_length = calculation_one - sqrt(300)

def second_triangle(canal_length_left):
    canal_length_left = canal_length_left ** 2
    calculation_two = canal_length_left + 500 ** 2
    second_triangle_longest_side_length = sqrt(calculation_two)


while True:
    first_triangle_longest_side_length = first_triangle_longest_side_length + 0.01
    first_triangle(first_triangle_longest_side_length)
    canal_length_left = 1000 - first_triangle_bottom_side_length
    second_triangle(canal_length_left)
    if first_triangle_longest_side_length == 1044.03:
        break
    total_distance = first_triangle_longest_side_length + second_triangle_longest_side_length
    numbers_total.append(total_distance)
    numbers_canal.append(first_trangle_bottom_side_length)

minimal_total_distance = min(numbers_total)
number_on_the_list = numbers_total.index(minimal_total_distance)
print "The distance of the shortest route is: " + "%.1f" %     minimal_total_distance
print "The distance of the canal from point A is: " + "%.1f" % numbers_canal[number_on_the_list]

然而,它给出了错误:

line 19, in <module>
    canal_length_left = 1000 - first_triangle_bottom_side_length
NameError: name 'first_triangle_bottom_side_length' is not defined

有什么想法吗?

5 个答案:

答案 0 :(得分:1)

对于那些感兴趣的人,问题是:Cambridge February Computing Competition

你正在采取一种非常强力的方法; 它有效,但可以更有效率 编辑:我把它拿回来;你的数学也不正确。我将在新帖子中更正

这是一种更具分析性的方法:

TOWER_DIST = 300
CANAL_LEN  = 1000
FIRE_DIST  = 500

#
#  express the problem as a function
#
def path_length(dist_a):
    """
    Given distance in meters from A along the canal,
      return total path length
    """
    leg_a = (TOWER_DIST**2 + dist_a**2) ** 0.5
    leg_b = ((CANAL_LEN - dist_a)**2 + FIRE_DIST**2) ** 0.5
    return leg_a + leg_b

#
# find x such that path_length(x) is minimized
#

# (the easy way:
# import scipy.optimize
# result = scipy.optimize.minimize(path_length, CANAL_LEN * 0.5)
# best_dist   = result.x[0]              # =>  375.00092001
# best_length = path_length(best_dist)   # => 1280.6248
#
# but because this is a competition we will avoid add-on modules)

def deriv(f, delta=0.01):
    """
    Return a function which is a numerical first derivative of f
    """
    def df(x):
        a, b = f(x - delta), f(x + delta)
        return (b - a) / (2. * delta)
    return df

def newton_root(f, initial_x, tolerance=0.01, max_tries=1000):
    """
    Use Newton-Raphson method to find x such that abs(f(x)) <= tolerance
    """
    df = deriv(f)
    x  = initial_x
    for try_ in range(max_tries):
        err = f(x)
        if abs(err) <= tolerance:
            # found a solution
            return x
        else:
            # find next value for x
            x -= err / df(x)
    else:
        raise ValueError(
            "newton_root fails to converge for initial_guess = {}"
            .format(initial_x)
        )

# By inspection, path_length is a smooth upward curve (ie a U-shape)
#   on 0 .. CANAL_LEN; minimum occurs where first derivative is 0
best_dist   = newton_root(deriv(path_length), CANAL_LEN * 0.5, 0.00001)   # => 374.9999
best_length = path_length(best_dist)                  # => 1280.62484

# return results to nearest 0.1 meter
print("{:0.1f} {:0.1f}".format(best_dist, best_length))

如果你玩这个并考虑一下,你应该意识到最短的路径总是这样,leg_a和运河之间以及运河和leg_b之间的角度是相同的;如果你认为运河是一面镜子,那么最短的路径是直接射向镜子里的火焰反射。

这允许我们将问题简化为一对简单的相似三角形,

# TOWER_DIST / best_dist == (TOWER_DIST + FIRE_DIST) / CANAL_LEN
best_dist = TOWER_DIST * CANAL_LEN / (TOWER_DIST + FIRE_DIST)

best_length = ((TOWER_DIST + FIRE_DIST)**2 + CANAL_LEN**2) ** 0.5

答案 1 :(得分:0)

这正是错误所说的。 Python逐行工作。在你的功能里面看它。你永远不会定义`first_triangle_bottom_side_length&#34;。在函数中定义它,错误就会消失。

答案 2 :(得分:0)

变量first_triangle_bottom_side_length可能在函数内被声明为local,为了解决这个问题,你返回变量并将其设置在函数之外。

(在第一个三角形内):

Return first_triangle_bottom_side_length

...

firsttrianglebottomsidelength = first_triangle(first_triangle_longest_side_length)
canal_length_left = 1000 - firsttrianglebottomsidelength

答案 3 :(得分:0)

就像Tim Castelijns写的那样 - 这是一个范围问题。 first_triangle_bottom_side_length在函数first_triangle中定义,但您永远不会将其返回到主程序。

你应该退货:

def first_triangle(first_triangle_longest_side_length):
    calculation_one = sqrt(first_triangle_longest_side_length)
    return calculation_one - sqrt(300)
[...]
[...]
while True:
    first_triangle_longest_side_length = first_triangle_longest_side_length + 0.01
    first_triangle_bottom_side_length = first_triangle(first_triangle_longest_side_length)
    canal_length_left = 1000 - first_triangle_bottom_side_length

了解范围,但更重要的是 - 了解如何使用功能。

祝你好运!

答案 4 :(得分:0)

再看看你的答案后,我意识到你的数学也错了。我会指出你的语法和数学错误,并在此过程中添加一些免费的建议; - )

单步执行原始代码:

from math import sqrt
numbers_total = []
numbers_canal = []
first_triangle_longest_side_length = 300   #defining the variable

真的? where_on_earth_did_you_learn_variable_naming?试试tower_dist = 300

def first_triangle(tower_hypot):
    calculation_one = sqrt(tower_hypot)
    first_triangle_bottom_side_length = calculation_one - sqrt(300)

第一个错误:为first_triangle_bottom_side_length分配值并没有完成任何事情。变量属于局部范围(即它只存在于此函数中),因此只要函数结束,它就会消失。

可能完全是邪恶的并使其成为一个全局变量,或者你只能return calculation_one - sqrt(300)

第二个错误:数学错误。我马上回过头来看看。

def second_triangle(canal_length_left):
    canal_length_left = canal_length_left ** 2
    calculation_two = canal_length_left + 500 ** 2
    second_triangle_longest_side_length = sqrt(calculation_two)

再次出现相同的错误;改为return sqrt(calculation_two)

重要说明:命名约定! first_triangle返回基本长度,second_triangle返回斜边。这有点令人困惑。此外,两个函数都有常量硬连接,这意味着函数不能重用于其他任何东西。


如果您改为:

def side(adjacent, hypotenuse):
    """
    Given the side and hypotenuse of a right triangle,
      return the other side
    """
    return (hypotenuse**2 - adjacent**2) ** 0.5

def hypotenuse(adjacent, opposite):
    """
    Given two sides of a right triangle,
      return the hypotenuse
    """
    return (adjacent**2 + opposite**2) ** 0.5

def tower_base(tower_hypot, tower_height=300):
    return side(tower_height, tower_hypot)

def fire_hypot(fire_base, fire_height=500):
    return hypotenuse(fire_base, fire_height)

这通常足以重复使用,具有有意义但不可笑的长变量名称,并且可以轻松地进行正确性测试:

assert side(3, 5)  == 4
assert side(5, 13) == 12
assert hypotenuse(3, 4)  == 5
assert hypotenuse(5, 12) == 13

# a (300, 400, 500) triangle
assert tower_base(500) == 400

# a (500, 1200, 1300) triangle
assert fire_hypot(1200) == 1300

测试您之前的代码:

# should make a (300, 400, 500) triangle
assert first_triangle(500) == 400   # 5.04017 ?!  FAIL

并且存在数学错误:first_triangle返回tower_hypot**0.5 - 300**0.5这是无意义的数量;它应该是(tower_hypot**2 - 300**2)**0.5

单位分析为我们提供了一种快速检查的方法;如果tower_hypot以米为单位,则第一个等式返回米的根(这没有意义),而第二个等式返回米(这是我们所期望的)。这并不一定使它正确 - 但它使显然不正确,这是一个好的开始!


while True:
    tower_hypot += 0.01

    first_triangle(first_triangle_longest_side_length)

您正确调用了该函数,但未将结果保留在任何位置;试试a_dist = tower_base(tower_hypot)

    canal_length_left = 1000 - a_dist
    second_triangle(canal_length_left)

你还没有保留功能结果;试试fire_dist = fire_hypot(1000 - a_dist)

    if first_triangle_longest_side_length == 1044.03:
        break

魔术数字!真有趣!

  • 目前尚不清楚这个值的含义((300**2 + 1000**2)**0.5tower_hypot的最大可能值,但乍看之下还不清楚

  • 浮点数学意味着==几乎永远不会起作用;您想要>>=

  • 你已经对tower_height,canal_length,fire_height的值进行了硬编码 - 这是不好的做法 - 但你现在还在派生自这些值的值中硬编码,使你的程序很难维护(下周会发生什么事情,当游侠看到距离运河200米远的地方有火灾?他是否必须从头开始重写程序以找出去哪里?)

然后

    total_distance = first_triangle_longest_side_length + second_triangle_longest_side_length
    numbers_total.append(total_distance)
    numbers_canal.append(first_trangle_bottom_side_length)

minimal_total_distance = min(numbers_total)
number_on_the_list = numbers_total.index(minimal_total_distance)
print "The distance of the shortest route is: " + "%.1f" %     minimal_total_distance
print "The distance of the canal from point A is: " + "%.1f" % numbers_canal[number_on_the_list]

通过一些修改,代码看起来像

# use named variables!
# - makes it easy to modify the program later
# - makes it easier to figure out what's going on
TOWER_HEIGHT = 300
CANAL_LENGTH = 1000
FIRE_HEIGHT  = 500

# generic functions which can be reused!
def side(adjacent, hypotenuse):
    """
    Given the side and hypotenuse of a right triangle,
      return the other side
    """
    return (hypotenuse**2 - adjacent**2) ** 0.5

def hypotenuse(adjacent, opposite):
    """
    Given two sides of a right triangle,
      return the hypotenuse
    """
    return (adjacent**2 + opposite**2) ** 0.5

# work from the most obvious control value
def total_dist(a_dist):
    tower_hypot = hypotenuse(a_dist, TOWER_HEIGHT)
    b_dist      = CANAL_LENGTH - a_dist
    fire_hypot  = hypotenuse(b_dist, FIRE_HEIGHT)
    return tower_hypot + fire_hypot

def main():
    step_size = 0.1

    # equivalent of
    # a_dists = numpy.arange(0.0, CANAL_LENGTH, step_size)
    num_steps = int(CANAL_LENGTH / step_size)
    a_dists   = (k*step_size for k in range(num_steps + 1))

    # find minimum distance
    best_a_dist     = min(a_dists, key=total_dist)
    best_total_dist = total_dist(best_a_dist)

    print("The distance of the shortest route is: {:0.1f}".format(best_total_dist))
    print("The distance of the canal from point A is: {:0.1f}".format(best_a_dist))

main()