Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Post
  • Reply
QuarkJets
Sep 8, 2008

Everything is a dictionary anyway so why pretend otherwise, just use dictionaries for everything

(I'm lying, don't actually do this)

Eela6 posted:

I am of this opinion.

This is a good video on the subject:
[video type=""]https://m.youtube.com/watch?v=o9pEzgHorH0[/video]

Classes are useful when they make your code easier to reason about. Too many classes are often a signal of code without forethought.

I agree as well; too many times I've seen unnecessary class implementations of things that really seemed like the developer was just looking for excuses to create classes rather than using classes to make the code easier to understand/use. I think it's easy for developers coming over from C++/Java to fall into that trap, whereas developers coming from Matlab/Fortran have the opposite problem (everything should be a function!)

Adbot
ADBOT LOVES YOU

Eela6
May 25, 2007
Shredded Hen
Finding the correct level of abstraction is like tuning a guitar string by ear. The correct tuning depends on the pitch of the strings around it, and large changes might require re-tuning of the surrounding strings.

Similarly, there is no uniform level of abstraction that is 'always correct' for a particular concept. Whether or not a particular piece of code is correctly abstracted is not just a function of the code itself, but the larger program as a whole.

Jose Cuervo
Aug 25, 2004
I am trying to understand OrderedDicts. I am reading the documentation and am having trouble understanding what the following line is saying:

"The OrderedDict constructor and update() method both accept keyword arguments, but their order is lost because Python’s function call semantics pass-in keyword arguments using a regular unordered dictionary."

Is this saying that if I add items to the OrderedDict as follows
Python code:
from collections import OrderedDict

q = OrderedDict()
q[1] = 'first'
q[2] = 'second'
q[3] = 'third'

for i, j in q.iteritems():
	print i, j
then there is no guarantee that what will be printed is
code:
1 first
2 second
3 third
??

Space Kablooey
May 6, 2009


If you add items like you did in your example, you should be fine.

The problem is when you do it like this:

Python code:
from collections import OrderedDict
a = OrderedDict({'a': 1, 'b': 2})
b = OrderedDict(**{'a': 1, 'b': 2})
c = OrderedDict(a=1, b=2)
In all of these examples, Python uses a regular dict to create the OrderedDict, and since regular dicts aren't ordered, you will lose the order that you want.

Master_Odin
Apr 15, 2010

My spear never misses its mark...

ladies
It's more that if you were to do:
code:
>>> q = OrderedDict({1: 'first', 2: 'second', 3: 'third'})
>>> q.update({4: 'fourth', 5: 'fifth'})
>>> for i, j in q.iteritems():
...     print i, j
...
Then you wouldn't be guaranteed to get:
code:
1 first
2 second
3 third
4 fourth
5 fifth
As the order of the dictionaries you're passing in as a paramater to the constructor and update are both normal unordered and could be added to the OrderedDict in any order (based on python spec).

However, the way you were adding to the dictionary is the recommended way that would ensure the order always.

Jose Cuervo
Aug 25, 2004
Got it, thanks!

Tigren
Oct 3, 2003

Jose Cuervo posted:

Got it, thanks!

And remember, in Python 3.6, dicts are now ordered.

Python Changelog posted:

New dict implementation

The dict type now uses a “compact” representation based on a proposal by Raymond Hettinger which was first implemented by PyPy. The memory usage of the new dict() is between 20% and 25% smaller compared to Python 3.5.

The order-preserving aspect of this new implementation is considered an implementation detail and should not be relied upon (this may change in the future, but it is desired to have this new dict implementation in the language for a few releases before changing the language spec to mandate order-preserving semantics for all current and future Python implementations; this also helps preserve backwards-compatibility with older versions of the language where random iteration order is still in effect, e.g. Python 3.5).

Space Kablooey
May 6, 2009


It's right there on the quote that you should not rely on that ordering. :psyduck:

Eela6
May 25, 2007
Shredded Hen
For now, if you are relying on the order, use OrderedDict all the way through. In CPython 3.6 it's just the new dict implementation under the hood, so you lose nothing, but you keep back-and-forward compatibility.

(I will never go back! f-strings are too useful.)

Cingulate
Oct 23, 2012

by Fluffdaddy
I often do something like this:

code:
parameter = 999
while does_not_match_some_condition(parameter):
    parameter = stochastic_process()

do_things_with_parameter(parameter)
I.e., to find a good value for my parameter (might be a string, a number, a sequence ...), I use a while loop to try a few values for my parameter, until I have one that matches some conditions. Then, I use that parameter for some purpose.

Specifying the parameter to some arbitrary value before the while loop feels inelegant. Is there a better way for doing this?


A more fleshed-out example, maybe I want to randomly draw an even integer between 140 and 75858 whose third-to-last digit is a 4 or a 7 for whatever reason:

code:
from random import randint
my_number = -1

while my_number % 1 and str(my_number)[-3] in {'4', '7'}:
    my_number = randint(140, 75859)

print(my_number)
(Ignore that this is probably a very inefficient solution for solving this specific task.)


I guess this is a very minor thing, but it's a pattern I use all the time and it feels weird.

Space Kablooey
May 6, 2009


I try to start with None or a boolean value if I don't have a default value that makes sense.

Cingulate
Oct 23, 2012

by Fluffdaddy

HardDiskD posted:

I try to start with None or a boolean value if I don't have a default value that makes sense.
Yeah but often the check requires a specific type. I guess there's some default for all these types (empty string, empty list, zero ...).
But sometimes these 'natural defaults' match the condition. E.g., what if False matches my criterion of being (not var % 2 and var < 1000)?

Space Kablooey
May 6, 2009


Sorry to be unspecific, but in that case you have to analyze whatever makes the most sense to you and work around the code's limitations.

SurgicalOntologist
Jun 17, 2004

You can also avoid the issue in several ways.

My favored solution would be to turn the stochastic process into a generator then use it like this:
Python code:
value = next(v for v in stochastic_process_generator() if meets_conditions(v))
Or you could use break:
Python code:
while True:
    value = stochastic_process():
    if meets_conditions(value):
        break
Otherwise, I would use None as was suggested and avoid the problem you bring up by prefacing the conditions with value is not None.

Cingulate
Oct 23, 2012

by Fluffdaddy
I like the generator one! Thanks guys.

baka kaba
Jul 19, 2003

PLEASE ASK ME, THE SELF-PROFESSED NO #1 PAUL CATTERMOLE FAN IN THE SOMETHING AWFUL S-CLUB 7 MEGATHREAD, TO NAME A SINGLE SONG BY HIS EXCELLENT NU-METAL SIDE PROJECT, SKUA, AND IF I CAN'T PLEASE TELL ME TO
EAT SHIT

You could also do next(filter(checker, generator)) if you're into that

e- whoooooops

Eela6
May 25, 2007
Shredded Hen

Cingulate posted:

I often do something like this:

code:
parameter = 999
while does_not_match_some_condition(parameter):
    parameter = stochastic_process()

do_things_with_parameter(parameter)
I.e., to find a good value for my parameter (might be a string, a number, a sequence ...), I use a while loop to try a few values for my parameter, until I have one that matches some conditions. Then, I use that parameter for some purpose.

Specifying the parameter to some arbitrary value before the while loop feels inelegant. Is there a better way for doing this?


A more fleshed-out example, maybe I want to randomly draw an even integer between 140 and 75858 whose third-to-last digit is a 4 or a 7 for whatever reason:

code:
from random import randint
my_number = -1

while my_number % 1 and str(my_number)[-3] in {'4', '7'}:
    my_number = randint(140, 75859)

print(my_number)
(Ignore that this is probably a very inefficient solution for solving this specific task.)


I guess this is a very minor thing, but it's a pattern I use all the time and it feels weird.

Python lacks the construct DO -> WHILE, so you have to figure out what makes sense given your level of abstraction. Personally, since this is a single construct ('get a number that satisfies this condition'), I would abstract it out to a function. This also lets you skip the 'pointless' initialization of your parameter that you find inelegant. This is similar to SurgicalOntologist's suggestion of using break.

I just like functions.

Python code:
def get_parameter_that_satisfies_conditions():
    while True:
        n = randint(140, 75858)
        if n % 2 == 0 and ((n % 1000) // 100) in {4, 7}:
            return n
parameter = get_parameter_that_satisfies_conditions()
do_things_with(parameter)

Eela6 fucked around with this message at 19:26 on Mar 15, 2017

SurgicalOntologist
Jun 17, 2004

Not sure if I should put this here or in the Scientific Computing thread, but whatever.

I have a data analysis project that involves computing a series of variables on a dataset (specifically, I'm adding DataArrays to an xarray DataSet, but it's the same idea as if I were adding columns to a DataFrame). Each calculation requires some variables to already be available and adds one or more variables to the dataset. Some of these are expensive to calculate and may not be necessary to run in all circumstances so I don't want to run everything. In short, I want a way to handle this dependency graph.

This seems like it should be a common pattern but I don't know of an existing easy solution. Closest thing I can think of is dask's DAG compute engine but this doesn't really fit into that model since I'm enriching the dataset object rather than passing around values.

If there's no existing solution the the best option I can think of is to have something like a require method call at the top of every function that checks if the required elements are present and then runs the corresponding function if they are not. Any better ideas?

Eela6
May 25, 2007
Shredded Hen

SurgicalOntologist posted:

Not sure if I should put this here or in the Scientific Computing thread, but whatever.

I have a data analysis project that involves computing a series of variables on a dataset (specifically, I'm adding DataArrays to an xarray DataSet, but it's the same idea as if I were adding columns to a DataFrame). Each calculation requires some variables to already be available and adds one or more variables to the dataset. Some of these are expensive to calculate and may not be necessary to run in all circumstances so I don't want to run everything. In short, I want a way to handle this dependency graph.

This seems like it should be a common pattern but I don't know of an existing easy solution. Closest thing I can think of is dask's DAG compute engine but this doesn't really fit into that model since I'm enriching the dataset object rather than passing around values.

If there's no existing solution the the best option I can think of is to have something like a require method call at the top of every function that checks if the required elements are present and then runs the corresponding function if they are not. Any better ideas?

You want to implement lazy attributes - only calculated if they don't already exist.

Here's an implementation, taken from Python Cookbook, 3rd Ed by David Beazley and Brian K. Jones, pg.267-278. (The example class is my own.)

This works because a __get__() method associated with an attribute is only called if the attribute being accessed is not in the underlying instance dictionary.

Python code:
from time import time

class LazyProperty():
    def __init__(self, func):
        self.func = func
    def __get__(self, instance, cls):
        if instance is None:
            return self
        else:
            value = self.func(instance)
            setattr(instance, self.func.__name__, value)
            return value

class Divisors():
    def __init__(self, n):
        self._n = n

    @LazyProperty
    def divisors(self):
        print('calculating divisors')
        return [x for x in range(1, self._n) if self._n % x  == 0]
        #intentionally slow
        
if __name__ == '__main__':
    
   D = Divisors(500000)
   print('calling D.Divisors')
   t0 = time()
   a = D.divisors
   elapsed = time()-t0
   print(f'first access ran in {elapsed}')
   print('calling D.divisors')
   t0 = time()
   b = D.divisors
   elapsed = time()-t0
   print(f'second access ran in {elapsed}')
OUT
code:
calling D.Divisors
calculating divisors
first access ran in 0.054593801498413086
calling D.divisors
second access ran in 0.0

Eela6 fucked around with this message at 00:00 on Mar 17, 2017

Thermopyle
Jul 1, 2003

...the stupid are cocksure while the intelligent are full of doubt. —Bertrand Russell

I always use the one I stole from django.

Python code:
class lazy_property(property):
    """
    A property that works with subclasses by wrapping the decorated
    functions of the base class.
    """
    def __new__(cls, fget=None, fset=None, fdel=None, doc=None):
        if fget is not None:
            @wraps(fget)
            def fget(instance, instance_type=None, name=fget.__name__):
                return getattr(instance, name)()
        if fset is not None:
            @wraps(fset)
            def fset(instance, value, name=fset.__name__):
                return getattr(instance, name)(value)
        if fdel is not None:
            @wraps(fdel)
            def fdel(instance, name=fdel.__name__):
                return getattr(instance, name)()
        return property(fget, fset, fdel, doc)

SurgicalOntologist
Jun 17, 2004

Ah yes, that's the way it should work. But it is complicated slightly by the fact that these aren't attributes but rather DataArrays within a DataSet (analagous to columns in a DataFrame). And xarray does the same thing pandas does to allow these variables to be set with __setitem__ but retrieved with __getitem__.

I could subclass DataSet and make my lazy variables true properties...but I'd probably have to override the name collision detection error.

Or I could make my own get function:
Python code:
    def get(self, var_name):
        if var_name not in self._dataset:
            getter_name = '_' + var_name
            if not hasattr(self, getter_name):
                raise KeyError(var_name)
            self._dataset[var_name] = getattr(self, getter_name)()
        return self._dataset[var_name]
I just realized I might have other issues stemming from the fact that the getter methods have some **kwarg parameters and I may want to maintain multiple copes of each... but this not be a common enough thing to plan for.

SurgicalOntologist
Jun 17, 2004

Hmm seems like this is more complicated. The methods I need to be calling aren't really getters but assigners, because sometimes coordinates need to be fixed or other implementation details when assigning a new data array. Also some of them assign multiple arrays.

For example see these two methods:
Python code:
    def assign_du_dt(self, name, u, t, fix_coords=None, **kwargs):
        """Fixes time coordinate issue with ``ds.assign(name=du_dt(u, t, **kwargs))``.

        Parameters
        ----------
        name : str
        u : str or xr.DataArray
        t : str or xr.DataArray
        fix_coords : list of str
            Default is ``['clock', 'seconds', 'half']``.
        **kwargs

        Returns
        -------
        xr.Dataset

        """
        if isinstance(u, str):
            u = self._ds[u]
        if isinstance(t, str):
            t = self._ds[t]
        if fix_coords is None:
            fix_coords = ['clock', 'seconds', 'half']

        return (
            self._ds
                .assign(**{name: u.s.d_dt(t, **kwargs)})
                .assign_coords(**{coord: self._ds[coord] for coord in fix_coords if coord in self._ds})
        )

      def assign_polarized(self, u, name=None, angle_name=None, dist_name=None):
        """Shortcut for ``ds[name + '_angle'], ds[name + '_dist'] = u.s.polarize()``

        Parameters
        ----------
        u : str or xr.DataArray
        name : str, optional
            Default value is ``u.name``.

        Returns
        -------
        xr.Dataset

        """
        if isinstance(u, str):
            u = self._ds[u]
        if name is None:
            name = u.name
        if angle_name is None:
            angle_name = name + '_angle'
        if dist_name is None:
            dist_name = name + '_dist'

        self._ds[angle_name], self._ds[dist_name] = u.s.polarize()
        return self._ds
My lazy evaluation system would need to do know to call assign_du_dt('velocity', 'position', 'time') if velocity is missing and assign_polarized('velocity', angle_name='heading', dist_name='speed') if heading or speed were missing....

Not sure that coming up with a general solution will be worth it. Maybe I could make the lazy properties work with composition instead of subclassing...

huhu
Feb 24, 2006
I've got a login form and a registration form on a single page with a nav that toggles a hidden class between the two. By default, when the page loads, registration is set to hidden. However, if a user fills out the registration form and there are errors on submit, the page refreshes and login is loaded. How could I get the hidden class to instead be applied to registration if a user registers but has errors?

Space Kablooey
May 6, 2009


huhu posted:

I've got a login form and a registration form on a single page with a nav that toggles a hidden class between the two. By default, when the page loads, registration is set to hidden. However, if a user fills out the registration form and there are errors on submit, the page refreshes and login is loaded. How could I get the hidden class to instead be applied to registration if a user registers but has errors?

Pass a flag to the template and, depending on the state of the flag, apply (or not) the class to the offending elements.


Python code:
@app.route('index/')
def route():
    return render_template('index.html', flag=True)
HTML code:
<div {% 'class="hidden"' if flag %}>
</div>

Space Kablooey fucked around with this message at 04:43 on Mar 17, 2017

EndlessRagdoll
May 20, 2016

Honestly, big shouts to the OP for having a great post for Python newbies like myself.

Boris Galerkin
Dec 17, 2011

I don't understand why I can't harass people online. Seriously, somebody please explain why I shouldn't be allowed to stalk others on social media!
Is it okay to do something like this:

code:
class Beer(object):

  def __new__(type, *args, **kwargs):
    BEERS = {'ipa': BeerIPA, 'stout': BeerStout}
    return BEERS[type.lower()](*args, **kwargs)

  def some_shared_beer_methods(...):
    # do things

class BeerIPA(Beer):

  def __init__(self, *args, **kwargs):
    pass

  def ipa_specific_methods(self):
    # do other things

class BeerStout(Beer):
  pass
I think the proper term is using the __new__ constructor as a factory function? Is this an accepted way to do something or is this one of these things I shouldn't do in python?

e: Silly example aside in the real case I wrote the base class as an interface layer to other classes. It's not actually meant to be instanced directly but I have a few subclasses deriving from it that implement actual functionality. At the moment I have a module level getter function that's just more or less the __new__ method shown above. It's just more convenient and user friendly though I think to be able to instance an object by doing "beer = Beer('ipa', args)" instead of "beer = get_beer('ipa', args)". I want to avoid instancing the actual subclasses directly.

e: vvv What's the proper way to do it then?

Boris Galerkin fucked around with this message at 12:40 on Mar 18, 2017

Nippashish
Nov 2, 2005

Let me see you dance!

Boris Galerkin posted:

I think the proper term is using the __new__ constructor as a factory function? Is this an accepted way to do something or is this one of these things I shouldn't do in python?

Yes, this is what you're doing and no it is not a normal thing to do. I can't think of anything really wrong with it, but it's definitely weird and you will surprise people if you do it.

Thermopyle
Jul 1, 2003

...the stupid are cocksure while the intelligent are full of doubt. —Bertrand Russell

Boris Galerkin posted:

e: vvv What's the proper way to do it then?

Maybe just a regular function or a classmethod on Beer.

Python code:
@classmethod
def get_beer_by_type(cls, type, *args, **kwargs):
   ...

Eela6
May 25, 2007
Shredded Hen
I agree with Thermopyle. @classmethod is the way to make alternative constructors. If your method could be described as
Python code:
cls.from_bytes
cls.from_str
cls.from_some_other_format
It's a good place for @classmethod.

Generally speaking, overriding __new__ is deeper magic than you need to solve a problem in python. However, it is very fun! This happens most often when you want to create new classes 'on demand'. I don't know if your problem requires this, but if you want to get into runtime construction of classes, you should look into Metaclasses.

Python Classes make Instances
- > Python Metaclasses make Classes

I am not confident enough in my python magic to give a good example, but both Fluent Python and the Python Cookbook, 3rd. Ed, have great tutorials.

(I'm sure they exist online, but I don't know them well enough to suggest one).

As a final point, your override of __new__ won't work in the first place. It is a class method that implicitly takes cls as the first argument. The signature is as follows:

Python code:
def __new__(cls, *args, **kwargs): 

Eela6 fucked around with this message at 18:20 on Mar 18, 2017

Boris Galerkin
Dec 17, 2011

I don't understand why I can't harass people online. Seriously, somebody please explain why I shouldn't be allowed to stalk others on social media!
Thanks guys, I'll just stick with having a separate get_class_thing(...) function. It's what I had before but then I found out about __new__ and thought maybe I could just overwrite it.

Another question: I'm using sphinx to document things and in some of my methods I have latex math syntax, e.g
code:
def foo(self):
"""Returns foo.

Foo is defined as:

.. math::

    \mathbf{A} \cdot \mathbf{v} = \bar{\mathbf{x}}_\mathrm{text} + \nabla^2(\mathbf{y})
In the html versions of my docs this gets turned into mathjax so it looks nice. When I do 'pydoc foo' at the command line I get exactly what you see above. I want it to show this instead though:

code:
A*v = x_text + (nabla(y))^2
So I guess what I'm asking for is if there's some kind of preprocessor for pydoc that will rewrite math directives for me. I imagine there would be some kind of mapping involved, i.e., in the above I basically say "strip the mathbf, bar, and mathrm commands, turn cdot in *, keep _ literally, and somehow logic that \nabla^2(y) means raise my nabla operator to the power 2."

The Gunslinger
Jul 24, 2004

Do not forget the face of your father.
Fun Shoe
I decided to pick up Python, I have a fair amount of experience with Perl and C++ but want to update my skillset a bit. My laptop that runs Linux is having hardware problems so I decided to fart around on my Windows gaming PC with this. I'm working through a tutorial book but just encountered an issue.

They want you to mess around with turtle which is part of the standard library. If I call my script or invoke Python in a command shell from my base user directory (C:\users\TGS) I can import turtle and work with it just fine. If I try to import it from a folder on my desktop, I can't. I just get an unknown attribute error since it can't find the library. I've checked the PATH and the installation directory for Python is there so uh, anyone know what gives?

QuarkJets
Sep 8, 2008

The Gunslinger posted:

I decided to pick up Python, I have a fair amount of experience with Perl and C++ but want to update my skillset a bit. My laptop that runs Linux is having hardware problems so I decided to fart around on my Windows gaming PC with this. I'm working through a tutorial book but just encountered an issue.

They want you to mess around with turtle which is part of the standard library. If I call my script or invoke Python in a command shell from my base user directory (C:\users\TGS) I can import turtle and work with it just fine. If I try to import it from a folder on my desktop, I can't. I just get an unknown attribute error since it can't find the library. I've checked the PATH and the installation directory for Python is there so uh, anyone know what gives?

You'll need to modify your PYTHONPATH to point to the folder where your script lives. Print sys.path to see what your PYTHONPATH looks like; if your file lives in a folder that isn't in sys.path then Python doesn't know about it

https://docs.python.org/2/using/windows.html#configuring-python

If that doesn't work then I misunderstood the problem and you should probably copy-paste the actual error

Did you install vanilla Python or did you install Anaconda? If you're going to work in Windows then it's strongly recommended that you uninstall vanilla Python and install Anaconda, which will likely circumvent tons of headaches. Once you have Anaconda installed you can use the Spyder IDE (which comes with Anaconda) for your development / playing around. If you want to get serious, then you could look into installing the PyCharm IDE.

Eela6
May 25, 2007
Shredded Hen

The Gunslinger posted:

I decided to pick up Python, I have a fair amount of experience with Perl and C++ but want to update my skillset a bit. My laptop that runs Linux is having hardware problems so I decided to fart around on my Windows gaming PC with this. I'm working through a tutorial book but just encountered an issue.

They want you to mess around with turtle which is part of the standard library. If I call my script or invoke Python in a command shell from my base user directory (C:\users\TGS) I can import turtle and work with it just fine. If I try to import it from a folder on my desktop, I can't. I just get an unknown attribute error since it can't find the library. I've checked the PATH and the installation directory for Python is there so uh, anyone know what gives?

This is a bit strange. How did you install Python? If you're a beginner, especially on windows, I would try using Anaconda.

As mentioned, Spyder is a great beginner's IDE. I personally use Visual Studio Code

The Gunslinger
Jul 24, 2004

Do not forget the face of your father.
Fun Shoe
I just uninstalled Python and installed Anaconda instead. Having the same problem though.

code:
C:\Users\TGS\Desktop\Python>python bob.py
Traceback (most recent call last):
  File "bob.py", line 8, in <module>
    import turtle
  File "C:\Users\TGS\Desktop\Python\turtle.py", line 2, in <module>
    bob = turtle.Turtle()
AttributeError: module 'turtle' has no attribute 'Turtle'
Anaconda is installed and has set itself in my Path. I just want to be able to work from any directory and import libraries from the standard libs. Do I need to specify the folder when I do this? I don't really understand why its looking for turtle.py inside of that directory instead of in C:\users\TGS\Anaconda3. After setting the PYTHONPATH it still does the same thing.

I can only import sys and print sys.path if I run python from a shell in C:\users\TGS. It shows the default Anaconda install directory, scripts sub folders and etc.

I just want to be able to run scripts from any directory instead of being locked to my user directory.

Jose Cuervo
Aug 25, 2004

The Gunslinger posted:

I just uninstalled Python and installed Anaconda instead. Having the same problem though.

code:
C:\Users\TGS\Desktop\Python>python bob.py
Traceback (most recent call last):
  File "bob.py", line 8, in <module>
    import turtle
  File "C:\Users\TGS\Desktop\Python\turtle.py", line 2, in <module>
    bob = turtle.Turtle()
AttributeError: module 'turtle' has no attribute 'Turtle'
Anaconda is installed and has set itself in my Path. I just want to be able to work from any directory and import libraries from the standard libs. Do I need to specify the folder when I do this? I don't really understand why its looking for turtle.py inside of that directory instead of in C:\users\TGS\Anaconda3. After setting the PYTHONPATH it still does the same thing.

I can only import sys and print sys.path if I run python from a shell in C:\users\TGS. It shows the default Anaconda install directory, scripts sub folders and etc.

I just want to be able to run scripts from any directory instead of being locked to my user directory.

I think you have a file named turtle.py in the same folder as the file bob.py. So when it looks to find the turtle module, it "finds' it where it first looks - in the same folder, and never gets to look in the folder where Python is installed.

The Gunslinger
Jul 24, 2004

Do not forget the face of your father.
Fun Shoe
Haha holy poo poo I hope it's that simple, just got into work but I'll RDP into my machine later and check. Thanks man.

Thermopyle
Jul 1, 2003

...the stupid are cocksure while the intelligent are full of doubt. —Bertrand Russell

The Gunslinger posted:

Haha holy poo poo I hope it's that simple, just got into work but I'll RDP into my machine later and check. Thanks man.

This is probably it. I've been writing python for a decade and this will still occasionally trip me up...particularly when it's a large project and I've been doing lots of refactoring.

Jose Cuervo
Aug 25, 2004
I am using Python 2.7 with PyCharm Community Edition 2016.3.2. I have the following snippet of code:

Python code:
class ParentNode(node.Node):
    """ParentNode is a subclass of Node but also takes an additional child_nodes parameter.
    This class also contains queues (maintenance_queue, available_queue, en_route_queue)
    formed from dictionaries, and a list of TMRs that have occurred.
    @type child_nodes: dict[str: child_node.ChildNode]
    """
    def __init__(self, name, node_type, FSPs, CTT_distributions, TMR_distributions,
                 prob_on_convoy, rep_rndstrm, child_nodes):
        """ParentNode is a subclass of Node but also takes an additional child_nodes parameter.
        This class also contains queues (maintenance_queue, available_queue, en_route_queue)
        formed from dictionaries, and a list of TMRs that have occurred.
        @type child_nodes: dict[str: child_node.ChildNode]
        """
        node.Node.__init__(self, name, node_type, FSPs, CTT_distributions, TMR_distributions,
                           prob_on_convoy, rep_rndstrm)
        self.network_status = 'parent'
        self.child_nodes = child_nodes
The issue is that when I hover over self.child_nodes or child_nodes, the inferred type is shown as 'Any' instead of 'Dict[str, ChildNode]'. I don't understand why the typehinting I have in the docstring does not work in this case.

QuarkJets
Sep 8, 2008

Try using a comma instead of a colon in the typehinting

Adbot
ADBOT LOVES YOU

FingersMaloy
Dec 23, 2004

Fuck! That's Delicious.
Hi goons. I am trying to teach myself to build a web scraper for Craigslist using Scrapy and BeautifulSoup. I've never programmed before, but I've worked through Python Crash Course, and now I'm using Web Scraping With Python.

I have this program that pulls exactly what I want into a CSV, if I manually feed it urls.
Python code:
from urllib2 import urlopen
from bs4 import BeautifulSoup
import csv

html = urlopen("I type the urls here")
soup = BeautifulSoup(html.read(), "html.parser")

ad_title = soup.title
for date_and_time in soup.findAll(class_="timeago"):
    date_posted = date_and_time.get("datetime")
body = soup.find(id="postingbody")
mapaddress = soup.find(class_="mapaddress")
for apt in soup.findAll(id="map"):
    lat = apt.get("data-latitude")
    lon = apt.get("data-longitude")

csvFile = open("test.csv", 'a')
try:
    writer = csv.writer(csvFile)
    writer.writerow((html, ad_title, date_posted, body, mapaddress, lat, lon))
finally:
    csvFile.close()
This works.

The problem I'm having is I can't get my own crawler to work. I can get Scrapy's tutorial crawler to run so I know everything is correctly installed. What I need, or I imagine I need, is a crawler that populates that variable "html" or reconfigure the "soup" variable and the rest of my code will finish it off. Again I'm relying on Scrapy's site:
Python code:
import scrapy
from bs4 import BeautifulSoup
import csv

class CraigslistSpider(scrapy.Spider):
	name = "craig"
	allowed_domain = "cleveland.craigslist.org/"
	start_urls = ["two really long Craigslist search queries"]

	def parse(self, response):
		soup = BeautifulSoup(response.text, 'lxml')
Can anyone help me connect these two things?

FingersMaloy fucked around with this message at 21:05 on Mar 23, 2017

  • 1
  • 2
  • 3
  • 4
  • 5
  • Post
  • Reply