-1
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
<ipython-input-1-902791409a52> in <module>()
     57         ObjectLists.sounds[5].play_sound()
     58 
---> 59 class Scale:
     60     scales = [Scale.zv, Scale.newton]
     61     screening = False

<ipython-input-1-902791409a52> in Scale()
     58 
     59 class Scale:
---> 60     scales = [Scale.zv, Scale.newton]
     61     screening = False
     62     newtoncount = 0

NameError: name 'Scale' is not defined

Can't for the life of me figure out what this is about. The name 'Scale' is defined, however, the interpreter's never wrong. What am I missing?

EDIT: When I run:

class things:
    poo = [things.roughage(), things.towels()]
    @staticmethod
    def roughage():
        return('health')

    @staticmethod
    def towels():
        return('dryness')

print(things.poo)

it raises a NameError; things is not defined.

However when I run:

class things:
    @staticmethod
    def roughage():
        return('health')

    @staticmethod
    def towels():
        return('dryness')

class holder:
    poo = [things.roughage(), things.towels()]

print(holder.poo)

there's no error and output is as expected.

Khari Thompson
  • 99
  • 1
  • 10
  • Can you provide the full code for the class 'Scale'? As well as how it is executed. – Abstracted Mar 06 '17 at 03:21
  • How is the interpreter supposed to know what `Scale` is before you've finished defining it? For what it's worth, I can't figure it out any better than the interpreter can, in this case. – TigerhawkT3 Mar 06 '17 at 03:21

2 Answers2

0

The name 'Scale' is defined, however, the interpreter's never wrong

Is it defined though? You're using Scale within its own definition. At the time that the interpreter accesses line 60 it hasn't defined Scale yet. Let alone it's attributes zv and newton. Instead, you could try defining zv and newton before defining scales.

class Scale:
    screening = False
    newtoncount = 0
    zv = 'zv'
    newton = 'newton'
    scales = [zv, newton]

scale = Scale()
print scale.scales

Edit: I'm glad you got something working (judging from your last edit). In your working example there is no error because things is fully defined before it's used in the definition of holder.

Another way you could achieve what you seem to be looking for would be by using the __init__ function in your class definition and accessing poo on an instance of things instead of the class itself.

class things():
    def __init__(self):
        self.poo = [self.roughage(), self.towels()]
    @staticmethod
    def roughage():
        return('health')
    @staticmethod
    def towels():
        return('dryness')

holder = things()  # create an instance of things
print(holder.poo)

This way you don't need to split up your definitions into two classes.

I don't know anything about your full implementation of these classes but I want to point two key differences in these two implementations.

Your example with Scales and the first implementation of things declare class level attributes whereas my implementation declares poo as an instance level attribute.

A quick search turned up the following links on the subject:

Community
  • 1
  • 1
  • Thanks for this. I'd tried relocating the `scales` list at multiple positions in my `Scales` class, and also defining `zv` and `newton` before adding them to the `scales` list. However, these attempts made no difference. In my frustration I didn't really think about relocating the scales list, and that seems to be what works. – Khari Thompson Mar 06 '17 at 04:09
0

In Python, you can't use something until it's been created. The interpreter works in a fairly linear top-down fashion, so even something as simple as

foo()
def foo():
    print('hi')

will raise a NameError.

To create a class, the interpreter executes the class definition and then binds the resulting class object to the supplied name. Your first things example tries to use the name things before it's bound to an object and before the object itself exists. It also tries to call those static methods before they exist.

I realise your code is just a toy example, but it's not a very typical Python class: it has no instance attributes, and no normal methods, only static ones. Sure, the language lets you do that, but it's much more common to make classes that are used to create instances.

FWIW, it's possible to initialise a class attribute inside the __init__ method. Of course that's useless if you have no intention of creating instances, but I'll show a brief example anyway.

class Things():
    poo = None

    def __init__(self):
        if Things.poo is None:
            print('Initialising poo...')
            Things.poo = [self.roughage(), self.towels()]

    @staticmethod
    def roughage():
        return('health')
    @staticmethod
    def towels():
        return('dryness')

print(Things.poo)

h1 = Things()
p = h1.poo
print(p, id(p))

p = Things.poo
print(p, id(p))

h2 = Things()  
p = h2.poo
print(p, id(p))

output

None
Initialising poo...
['health', 'dryness'] 3072932652
['health', 'dryness'] 3072932652
['health', 'dryness'] 3072932652

The initialisation could also be done with

Things.poo = [Things.roughage(), Things.towels()]
['health', 'dryness'] 3072924460
PM 2Ring
  • 54,345
  • 6
  • 82
  • 182