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
breaks
May 12, 2001

It's so strange I hunted down the change. :shobon:

It's so you can do this:

code:
>>> d = OrderedDict(self=1)
>>> d
OrderedDict([('self', 1)])
A couple other things from collections work the same way for the same reason (as noted in the bug comments it's kind of pointless for OrderedDict). See: https://bugs.python.org/issue22609

breaks fucked around with this message at 00:00 on Apr 16, 2017

Adbot
ADBOT LOVES YOU

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!
So if I'm understanding this right, it lets me use self as a keyword argument and nothing more?

breaks
May 12, 2001

That's my understanding from that bug, yeah, but I don't know any more about it than that. But if you look through the changes made in that patch, that is the one that removed the self argument from __init__.

breaks fucked around with this message at 00:06 on Apr 16, 2017

FAT32 SHAMER
Aug 16, 2012



Dominoes posted:

PyCharm doesn't like to work with files unless they're in a folder that includes PyCharm meta files (.idea directory). Maybe that's it?

Ya basically

Most of my Python projects are small enough to not need auto complete and linting and grammar or however you say it and having to fire up Pycharm to do 150 lines of code isn't really worth it to me so I use vim instead

Nippashish
Nov 2, 2005

Let me see you dance!
There's a lot of slightly strange things in the collections module. Like docstrings using ''' instead of """, or single line doc strings using 1 quote instead of 3, or the whole implementation of namedtuple.

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 for the responses guys. It was interesting to read about.


I just downloaded PyCharm to give it a try because the refactoring tools looked really cool. How do I get it to work nicely with both .rst and .py files? I think it's treating my .rst files in my ./docs/source folder as Python files because the inspector keeps giving me warnings about missing docstrings or encodings etc.

Eela6
May 25, 2007
Shredded Hen
The first rule of namedtuple is 'don't look at the implementation of namedtuple'

Malcolm XML
Aug 8, 2009

I always knew it would end like this.
Fwiw attrs is a better namedtuple at the cost of needing a dependency

Thermopyle
Jul 1, 2003

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

IMO, typing.NamedTuple is also better than collections.namedtuple with no extra dependency. I haven't used attrs, though.

Eela6
May 25, 2007
Shredded Hen

Thermopyle posted:

IMO, typing.NamedTuple is also better than collections.namedtuple with no extra dependency. I haven't used attrs, though.

Thanks for pointing out typing.NamedTuple! It has a really cool syntax with support for type hints:
Python code:
# python 3.6 and up ->
class Employee(typing.NamedTuple):
    name: str
    id: int

# equivalent to
Employee = collections.namedtuple('Employee', ['name', 'id'])

Eela6 fucked around with this message at 03:04 on Apr 17, 2017

Proteus Jones
Feb 28, 2013



You are triggering me so hard with that unpaired open paren.

E: Well, he was. I feel much better now.

Proteus Jones fucked around with this message at 00:14 on Apr 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!
I need to be able to inject a function into a class when the object gets created, and I've found two ways of doing it: 1) I could play around with meta classes and make my metaclass do it for me (possible since I have all the inputs), or 2) I could use the "MethodType" class from the types module.

I kinda like the second choice because it seems much easier and way more intuitive to be able to just do

code:

self.foo = types.MethodType(module.foo, self)

But a lot of what I'm finding on the web suggest to use metaclasses without really saying why. Is there any practical differences to either way?

e: I want the method injected to be bound to the object so I can't just assign it as an attribute.

Boris Galerkin fucked around with this message at 22:10 on Apr 17, 2017

breaks
May 12, 2001

I think what you are trying to do rarely makes sense. You should probably just write a method that calls whatever you want to call instead unless you have a really good reason not to. That said, why not just:

code:
>>> def f(self, arg):
	print(self.blah, arg)
>>> class A:
	def __init__(self):
		self.blah = 1
	meth = f
>>> a = A()
>>> a.meth(2)
1 2
If your concern is that "f" doesn't take self then replace with meth = staticmethod(f).

But again this situation should have every "there's got to be a better way" alarm in your head going off simultaneously.

breaks fucked around with this message at 04:48 on Apr 18, 2017

Eela6
May 25, 2007
Shredded Hen

Boris Galerkin posted:

I need to be able to inject a function into a class when the object gets created

Why do you need to?

Metaclasses are the preferred way of customizing classes, but most of the time you think you need them (or the even deeper magic of method injection) they are not necessary.

To quote Tim Peters

Tim Peters posted:

[Metaclasses] are deeper magic than 99% of users should ever worry about. If you wonder whether you need them, you don't (the people who actually need them know with certainty that they need them, and don't need an explanation about why)

Eela6 fucked around with this message at 05:06 on Apr 18, 2017

Cingulate
Oct 23, 2012

by Fluffdaddy
Different question: does Continuum make money? What are the chances "conda install all_the_software_i_need" won't work in 2018 because Travis Oliphant has to choose between making it slightly easier for me to set up numpy or feeding his kids?

huhu
Feb 24, 2006

Cingulate posted:

Different question: does Continuum make money? What are the chances "conda install all_the_software_i_need" won't work in 2018 because Travis Oliphant has to choose between making it slightly easier for me to set up numpy or feeding his kids?

2018? I don't think anything is guaranteed 3 months from now.

SurgicalOntologist
Jun 17, 2004

Cingulate posted:

Different question: does Continuum make money? What are the chances "conda install all_the_software_i_need" won't work in 2018 because Travis Oliphant has to choose between making it slightly easier for me to set up numpy or feeding his kids?

The nice thing about a heavily used open source project is that it cannot really go away. If Continuum disappears the code will still exist and there will be enough volunteers to maintain it.

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!

breaks posted:

You should probably just write a method that calls whatever you want to call instead unless you have a really good reason not to.


I have a class that represents this equation:



In this equation the nu (Greek v looking thing) is a mathematical function, and there are different ways you can mathematically define it. The simplest mathematical function/model would be a constant value for it. More complex models use a varying amount of arbitrary parameters and it also depends on other parts of that equation that I showed.

For example one model might need access to that "u" variable in the equation. Another model might need access to that "p" in the equation. Another one might need both. I know at runtime what model to use because I define it, but until then the class doesn't know what to pre-compute (I use lazy evaluation a lot here), what it needs to pass into the function, etc.

The class representing that equation I showed knows all the methods to compute these things, though. So that's why I want to inject said function for nu into the object at runtime based on a single kwarg, so that it can access all of the class's methods.


If there's a better way I'm all ears. I'd like to avoid creating a subclass of that equation class for every model I implement, because in actuality some of those other terms in the equation canare represented by arbitrary mathematical functions.

Boris Galerkin fucked around with this message at 15:04 on Apr 18, 2017

SurgicalOntologist
Jun 17, 2004

can you do something like this:


Python code:
class NavierStokes:
    def __init__(self, ..., nu_method='constant'):
        ...
        self.nu = getattr(self, '_nu_' + nu_method)

    def _nu_constant(self, ...):
        ...

    def _nu_full(self, ...):
        ...
although I still don't understand the logic behind not wanting to assign it as an attribute. Because otherwise you could just pass it to __init__.

Cingulate
Oct 23, 2012

by Fluffdaddy
I also have a Pandas question. I have a multi-indexed Dataframe. I want to subset the DF based on the value of column A, and then look up stuff in the original DF based on values of one of the index columns and one of the regular columns in the subset, but in pairs.

E.g., the subset is
code:
i_1 i_2 A  B
0   a   x  a
1   b   x  c
2   c   x  a
And now I want to look up these rows of the original:
code:
i_1 i_2
0   a
1   c
2   a
I have code for this, but it is specific to my situation and I am sure very suboptimal:

code:
result = [dict(g.query("A == @cond_b & B == '{}'".format(int(ii)))[["A", "C"]].values)
 for _, g in df_main.groupby(level=0)
 for ii in g.query("A == 'cond_a'")["B"]]
Sorry for this overly convoluted and irreproducible example, but maybe somebody can already see where I'm going for.


huhu posted:

2018? I don't think anything is guaranteed 3 months from now.
Anything particular makes you say that?

SurgicalOntologist posted:

The nice thing about a heavily used open source project is that it cannot really go away. If Continuum disappears the code will still exist and there will be enough volunteers to maintain it.
Yeah but somebody has to host all of that stuff. And possibly pay for the traffic, pay for up to date packaging, etc. Pay for boring bugfix maintenance work.

Now a lot of the times, this will work out fine, somehow. But I'm sure if Continuum went under, things would change, and probably not for the better.

Thermopyle
Jul 1, 2003

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

I think the continued existence of whatever packaging system or repository is a hard problem.

Continuum is just one company.

PyPI (where your packages come from when you pip install something) is basically developed by one guy. Last I heard, it's infrastructure would cost 40 grand/month if Rackspace wasn't donating it.

onionradish
Jul 6, 2006

That's spicy.
As a Python user on Windows, I'd put Christoph Gohlke in the same "I hope nothing ever happens to him" category. His "Unofficial Windows Binaries for Python" site has been a project lifesaver on more than one occasion.

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!

SurgicalOntologist posted:

can you do something like this:


Python code:

class NavierStokes:
    def __init__(self, ..., nu_method='constant'):
        ...
        self.nu = getattr(self, '_nu_' + nu_method)

    def _nu_constant(self, ...):
        ...

    def _nu_full(self, ...):
        ...

although I still don't understand the logic behind not wanting to assign it as an attribute. Because otherwise you could just pass it to __init__.

I mean I could do this I guess. Your way looks like my way, except that in your way you would define every single model for "nu" inside of that class, and in my way I would define every model for "nu" inside a separate file called viscosity.py.

I honestly thought I was being more clever by splitting those functions into their own file.

SurgicalOntologist
Jun 17, 2004

That's reasonable too. In that case I would just do

Python code:
def __init__(self, ..., nu_func=default_nu_func):
    self.nu = nu_func
The only reason I didn't suggest that is this:

Boris Galerkin posted:

e: I want the method injected to be bound to the object so I can't just assign it as an attribute.

which I don't follow. With the above it is bound to the object.

Dominoes
Sep 20, 2007

Cingulate posted:

Different question: does Continuum make money? What are the chances "conda install all_the_software_i_need" won't work in 2018 because Travis Oliphant has to choose between making it slightly easier for me to set up numpy or feeding his kids?
Switching to Pip and binaries is not a big deal.

onionradish posted:

As a Python user on Windows, I'd put Christoph Gohlke in the same "I hope nothing ever happens to him" category. His "Unofficial Windows Binaries for Python" site has been a project lifesaver on more than one occasion.
Yes def. I've found non-Conda python on Windows easier than Ubuntu, since for packages that don't install well via pip, his binaries always work, while apt-get is a crapshoot, and probably out-of-date. And I still can't figure out how to deconflict the multiple versions of OS python, ie 2.7, 3.5 and 3.6 all at once

Dominoes fucked around with this message at 18:46 on Apr 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!

SurgicalOntologist posted:

That's reasonable too. In that case I would just do

Python code:

def __init__(self, ..., nu_func=default_nu_func):
    self.nu = nu_func

If I did this I wouldn't be able to do "self.u" inside nu_func if I pass it in from outside the class right? I guess theoretically I could just call "self.nu(self)" inside the class to mimic a real method but that sounds weird.

[quote]
The only reason I didn't suggest that is this:


which I don't follow. With the above it is bound to the object.

Maybe I got my terminology wrong. I thought bound meant the thing where it implicitly gets "self" passed to it.

Eela6
May 25, 2007
Shredded Hen
You don't need to do any special magic to create a method and attach it to an object. So long as the first parameter is self it should 'just work'. Phoneposting so i cant go into more detail, but if you want an example I do so in my easyrepr implementation from earlier in this thread.

SurgicalOntologist
Jun 17, 2004

Boris Galerkin posted:

Maybe I got my terminology wrong. I thought bound meant the thing where it implicitly gets "self" passed to it.

Eela6 posted:

You don't need to do any special magic to create a method and attach it to an object. So long as the first parameter is self it should 'just work'. Phoneposting so i cant go into more detail, but if you want an example I do so in my easyrepr implementation from earlier in this thread.


That's what I thought would happen (it would get self passed automatically), but I just checked and Boris is right, it doesn't. Huh. This is the first time in a while I've been surprised by Python. I guess you do need to do that thing with the types module (or use the first method I suggested).

Edit: Eela6, IIRC about your easyrepr thing, it attaches to the class rather than an instance. In that case it works as expected.

breaks
May 12, 2001

If the organizational issue is the only thing, just dump them in a class in the other file and inherit from it?

Eela6
May 25, 2007
Shredded Hen

SurgicalOntologist posted:

That's what I thought would happen (it would get self passed automatically), but I just checked and Boris is right, it doesn't. Huh. This is the first time in a while I've been surprised by Python. I guess you do need to do that thing with the types module (or use the first method I suggested).

Edit: Eela6, IIRC about your easyrepr thing, it attaches to the class rather than an instance. In that case it works as expected.

Ah, I see! Thank you for the correction. It's a technical point but an important one.

Dex
May 26, 2006

Quintuple x!!!

Would not escrow again.

VERY MISLEADING!

Boris Galerkin posted:

I kinda like the second choice because it seems much easier and way more intuitive to be able to just do

code:
self.foo = types.MethodType(module.foo, self)
But a lot of what I'm finding on the web suggest to use metaclasses without really saying why. Is there any practical differences to either way?

the first slide here is the quote i think of whenever metaclasses come to mind: http://www.vrplumber.com/programming/metaclasses.pdf

as far as methodtypes goes, keep in mind functions have __name__ attributes too, so you can do stuff like:

code:
import types


class Example(object):
    def __init__(self, value):
        self.value = value

    def bind_function(self, myfunc):
        return setattr(self, myfunc.__name__, types.MethodType(myfunc, self))


def print_value(self):
    print(self.value)


example = Example('greetings')
example.bind_function(print_value)
example.print_value()

Dex
May 26, 2006

Quintuple x!!!

Would not escrow again.

VERY MISLEADING!

SurgicalOntologist posted:

Huh. This is the first time in a while I've been surprised by Python.

keep in mind what you're actually doing - assigning an object that exists outside the class to a value within the class:

Python code:
def outer_func():
    pass


class RefClass(object):
    def __init__(self, func):
        self.func = func


print(outer_func) 
print(RefClass(func=outer_func).func)
is just going to print out the same object, which makes sense really

breaks
May 12, 2001

That is within the instance not the class. Functions in the class's namespace will work as methods (with maybe some exceptions if you really try to break it).

I know that's maybe kind of pedantic but that's the distinction that changes the behavior so...

Dex
May 26, 2006

Quintuple x!!!

Would not escrow again.

VERY MISLEADING!

breaks posted:

That is within the instance not the class. Functions in the class's namespace will work as methods (with maybe some exceptions if you really try to break it).

I know that's maybe kind of pedantic but that's the distinction that changes the behavior so...

yeah i meant instance since i wrote the post right before it as a way to bind to instances, d'oh. just adding the function to a class' namespace still won't bind it, though

SurgicalOntologist
Jun 17, 2004

Yes it will.
Python code:
In [1]: class Test:
      :     pass
      : 
      : 

In [2]: def foo(self):
      :     print('bar')
      :     

In [3]: a = Test()

In [4]: Test.f = foo

In [5]: a.f()
bar

In [6]: b = Test()

In [7]: b.f()
bar
This is the kind of thing I've done or seen done before, it didn't cross my mind that it wouldn't work with instances.

Dex
May 26, 2006

Quintuple x!!!

Would not escrow again.

VERY MISLEADING!
actually wait a minute, i'm an idiot apparently!

edit: been entirely too long since i looked at descriptor protocol stuff and somehow thought the same magic was needed for classes, i have no idea why

later edit: well, that was actually worth googling again, since you can just use the function's descriptors directly:

Python code:
class Test:
    pass


def foo(self):
    print("foo")


def bar(self):
    self.foo()
    print("bar")


Test.foo = foo
t = Test()
t.bar = bar.__get__(t)
t.bar()
i'm starting to remember why i never do this kind of thing though

Dex fucked around with this message at 22:29 on Apr 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!
You guys are right. I just tried that too and it works. The only problem is that then all Test objects would have access to that foo method. What I want to do is have foo he defined per object so that I could do something like

code:

problems = (Test('foo_bar', ...), Test('foo_baz', ...), Test('foo_baz2'))
results = [a.foo() for a in problems]

Dex posted:

keep in mind what you're actually doing - assigning an object that exists outside the class to a value within the class:

Python code:

def outer_func():
    pass


class RefClass(object):
    def __init__(self, func):
        self.func = func


print(outer_func) 
print(RefClass(func=outer_func).func)

is just going to print out the same object, which makes sense really

The way I thought of it was that everything is being passed around by reference/pointer. So when I assign test.foo = foo what I'm actually doing is saying "hey test object, your memory location corresponding to "foo" is now pointing to this other memory location which happens to have information on how to execute the foo function.

I'm not sure if that's right or not but from a Fortran background it made perfect sense …

Nippashish
Nov 2, 2005

Let me see you dance!
How about
code:
class WeirdClass(object):
    def __init__(self, foo):
        self._foo = foo

    def foo(self, *args, **kwargs):
        return self._foo(self, *args, **kwargs)
This is sort of weird, but what you want is also sort of weird. "I want a function that does different things depending on which instance I call it on" really screams "I want a base class with a bunch of different subclasses" to me.

Dex
May 26, 2006

Quintuple x!!!

Would not escrow again.

VERY MISLEADING!

Boris Galerkin posted:

What I want to do is have foo he defined per object

the descriptor bit in my last edit is probably what you want if you need access to the instance(self), unless i've confused myself completely again?

Python code:
class Welp(object):
    def __init__(self, func):
        self.foo = func.__get__(self)
        
def foo(self):
    print("foo")
    
def bar(self):
    print("bar")
    
def foo_bar(self):
    print("foo bar")
    
problems = (Welp(foo), Welp(bar), Welp(foo_bar))
[a.foo() for a in problems]
problems[0].foo()
problems[1].foo()
problems[2].foo()

output posted:

foo
bar
foo bar
foo
bar
foo bar

Dex fucked around with this message at 00:31 on Apr 19, 2017

Adbot
ADBOT LOVES YOU

shrike82
Jun 11, 2005

Which is a roundabout way of saying that Boris was right with his initial solution.

From Hettinger's Descriptor HowTo
code:
class Function(object):
    . . .
    def __get__(self, obj, objtype=None):
        "Simulate func_descr_get() in Objects/funcobject.c"
        return types.MethodType(self, obj, objtype)
I think everyone here, including me, just found out that attaching a function to an instance doesn't automatically bind it, which is an interesting quirk.

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