14 votes

Topic deleted by author

18 comments

  1. [7]
    Deimos
    (edited )
    Link
    I just read through this article now. It's hard for me to judge because these certainly aren't new concepts for me, but I don't think it's a good intro. The classes are very minimal but still have...

    I just read through this article now. It's hard for me to judge because these certainly aren't new concepts for me, but I don't think it's a good intro. The classes are very minimal but still have design issues, and some of the Python isn't idiomatic at all. For example, you should never write if self.eaten == False:, it should just be if not self.eaten:.

    It also starts out explaining the absolute basics of what a class is, and then after a couple of extremely basic examples, suddenly jumps to advanced topics like multiple inheritance, method resolution order, and composition, which I don't think have any place in a post targeted at beginners. You're very unlikely to need any of those until you start getting into some pretty complex programs, and it's likely to be overwhelming. It was fairly confusing even to me, and I already know how all of these concepts work.

    10 votes
    1. [6]
      onyxleopard
      Link Parent
      I think a lot of programmers who learn multiple programming languages learn Python as one of those languages, but they never bother to learn Pythonic idioms. I think that’s excusable in some cases...

      For example, you should never write if self.eaten == False:, it should just be if not self.eaten:.

      I think a lot of programmers who learn multiple programming languages learn Python as one of those languages, but they never bother to learn Pythonic idioms. I think that’s excusable in some cases where Python idioms are not like any other languages, but stuff like boolean comparison is pretty basic. I work with a lot of Java devs and it’s pretty awkward to wade through their Python. I don’t want to say the flexibility of Python is a bad thing, but it allows you to go way off the rails if you’re either a beginner or haven’t spent enough time studying the language/standard library or important PEPs.

      5 votes
      1. [4]
        Deimos
        Link Parent
        I don't think you can really blame Python for it. It's not like the language can (or should) prevent you from writing if something == False, it's perfectly valid code and it does work exactly the...

        I don't think you can really blame Python for it. It's not like the language can (or should) prevent you from writing if something == False, it's perfectly valid code and it does work exactly the same as writing it idiomatically, so there's not really anything truly wrong with it.

        That's just the nature of language idioms, you have to learn the "culture" of that language to see how other people using it will expect you to do certain things. I think a good way to learn is to work on a project with more-experienced devs that can review your code and point out when you do things non-idiomatically, and you can also look through the code they're writing to see how they do things.

        7 votes
        1. [3]
          onyxleopard
          Link Parent
          Yeah, but it’s a little awkward when Pythonistas laud the Python language design principles such as those in "The Zen of Python" like: The unary not operator is probably very confusing, for...

          Yeah, but it’s a little awkward when Pythonistas laud the Python language design principles such as those in "The Zen of Python" like:

          There should be one-- and preferably only one --obvious way to do it.

          The unary not operator is probably very confusing, for instance:

          In [1]: 1 is 1                                                                                                                               
          Out[1]: True
          
          In [2]: 1 is not 0                                                                                                                           
          Out[2]: True
          
          In [3]: not 1 is 0                                                                                                                           
          Out[3]: True
          
          In [4]: not (1 is 0)                                                                                                                         
          Out[4]: True
          
          In [5]: (not 1) is 0                                                                                                                         
          Out[5]: False
          
          In [6]: not 1 == 0                                                                                                                           
          Out[6]: True
          
          In [7]: not None                                                                                                                             
          Out[7]: True
          
          In [8]: not None == 0                                                                                                                        
          Out[8]: True
          
          In [9]: (not None) == 0                                                                                                                      
          Out[9]: False
          
          In [10]: True == 1 == not 0                                                                                                                  
            File "<ipython-input-10-29486ec8bb04>", line 1
              True == 1 == not 0
                             ^
          SyntaxError: invalid syntax
          
          2 votes
          1. [2]
            spit-evil-olive-tips
            Link Parent
            It is a bit confusing laid out like that, but there is at least a fairly simple underlying principle at work - True and False are guaranteed to behave like 1 and 0 (at least in Python 3).

            It is a bit confusing laid out like that, but there is at least a fairly simple underlying principle at work - True and False are guaranteed to behave like 1 and 0 (at least in Python 3).

            5 votes
            1. onyxleopard
              Link Parent
              Truthiness coercion wasn’t even the point I was trying to make, but it can also be confusing. Maybe I can try to make my point about Python’s not more concisely: In [1]: 1 is 1 Out[1]: True In...

              Truthiness coercion wasn’t even the point I was trying to make, but it can also be confusing. Maybe I can try to make my point about Python’s not more concisely:

              In [1]: 1 is 1                                                                                                                               
              Out[1]: True
              
              In [2]: 1 is not 0                                                                                                                           
              Out[2]: True
              
              In [3]: 1 == not 0                                                                                                                           
                File "<ipython-input-3-bc7ccb91fd19>", line 1
                  1 == not 0
                         ^
              SyntaxError: invalid syntax
              
              1 vote
      2. [2]
        Comment deleted by author
        Link Parent
        1. onyxleopard
          Link Parent
          Idioms are inherently part of a language, just like natural language. Just because you know English doesn’t mean you know all English idioms (esp. uncommon, archaic ones). E.g., Python’s dunder...

          Idioms are inherently part of a language, just like natural language. Just because you know English doesn’t mean you know all English idioms (esp. uncommon, archaic ones). E.g., Python’s dunder methods: I see a lot of beginner Python code from devs coming from other languages where classes have custom show, length, etc. methods when they should be using __repr__, __len__ etc.

          1 vote
  2. mrbig
    (edited )
    Link
    I find OOP in Python terse, increasing cognitive load. But it's beautiful and pleasant. OOP in Java, on the other hand, is ridiculously verbose, but also unambiguous by design. I'm just a...

    I find OOP in Python terse, increasing cognitive load. But it's beautiful and pleasant. OOP in Java, on the other hand, is ridiculously verbose, but also unambiguous by design. I'm just a beginner, but I suppose there's some middle ground to achieve here.

    6 votes
  3. [7]
    mrbig
    Link
    A question for the more experienced: how could I make Python OOP more self-evident (but not necessarily much more verbose)?

    A question for the more experienced: how could I make Python OOP more self-evident (but not necessarily much more verbose)?

    3 votes
    1. [6]
      ali
      Link Parent
      What are you trying to achieve? By declaring types you will inherently be verbose. You could, for example only give functions input & output parameters a type, which I already a big step in...

      What are you trying to achieve? By declaring types you will inherently be verbose. You could, for example only give functions input & output parameters a type, which I already a big step in understanding the code

      4 votes
      1. [5]
        mrbig
        (edited )
        Link Parent
        I have trouble with short-term memory (ADHD), and one of my main issues with OOP in Python is simply forgetting what things are and do, even on small programs. Looking-up essential stuff every 5...

        I have trouble with short-term memory (ADHD), and one of my main issues with OOP in Python is simply forgetting what things are and do, even on small programs. Looking-up essential stuff every 5 to 10 seconds break my "flow", requiring constant "cognitive reboots". I figured a bit more verbosity might help, but, since I'm a beginner, I tend to mimic whatever book, documentation or tutorial I'm following just because I don't know any better.

        Your suggestions seem really good, could you maybe point to some layman-friendly articles or documentation that goes over these features?

        3 votes
        1. [4]
          ali
          (edited )
          Link Parent
          I think for the very basic thing, this should suffice: https://docs.python.org/3/library/typing.html just let me know if you have trouble understanding anything in there. I think this example...

          I think for the very basic thing, this should suffice:
          https://docs.python.org/3/library/typing.html

          just let me know if you have trouble understanding anything in there.
          I think this example covers the basic knowledge needed:

          def greeting(name: str) -> str:
              return 'Hello ' + name
          

          so you can type parameters (here the parameter is name) by using a colon, and you let the user /interpreter know that the return value is a string as well. Denoted by the arrow.
          here's a list of types: https://realpython.com/python-data-types/
          I guess the most important are str, float and int. Of course this will get much more complex with time haha

          5 votes
          1. [3]
            mrbig
            Link Parent
            Awesome, thanks! Besides clarity, what are the benefits of this feature?

            Awesome, thanks! Besides clarity, what are the benefits of this feature?

            1 vote
            1. Deimos
              (edited )
              Link Parent
              You can run mypy (or some other checkers) against code with type annotations and it will tell you if you have any type errors. I think some IDEs can also use them to do a better job of suggesting...

              You can run mypy (or some other checkers) against code with type annotations and it will tell you if you have any type errors. I think some IDEs can also use them to do a better job of suggesting variables/methods based on what makes sense with the types.

              For example if I copy @ali's function and accidentally call it with a number instead of a string:

              def greeting(name: str) -> str:
                  return 'Hello ' + name
              
              greeting(5)
              

              When I run mypy on that file it outputs:

              test.py:4: error: Argument 1 to "greeting" has incompatible type "int"; expected "str"
              

              That's a really contrived example that wouldn't really matter because your program would crash as soon as you tried to run it anyway, but it can help a lot in more complicated cases. For example maybe you have a function called get_name() that almost always returns a string, but can occasionally return None if something goes wrong. If you do something like this:

              name = get_name()
              print(greeting(name))
              

              That looks totally reasonable and your program will work as long as get_name() does return a string, but it has the potential to crash in those rare cases where it returns None. mypy will catch that and tell you about the potential error, because it knows get_name() doesn't always return a string but greeting() always needs one, so there's a mismatch.

              9 votes
            2. ali
              Link Parent
              here's an interesting read on that: https://pawelmhm.github.io/python/static/typing/type/annotations/2016/01/23/typing-python3.html In Python your program does not crash when running into invalid...

              here's an interesting read on that: https://pawelmhm.github.io/python/static/typing/type/annotations/2016/01/23/typing-python3.html

              In Python your program does not crash when running into invalid types, as it would in other languages, so without additional tools, the readability is the only advantage (as far as I know). The article mentions a library (mypy) which would precheck the types and tell you whether there is a type error. In languages like Java this is part of the design choice. In Python it is not

              2 votes
  4. [3]
    onyxleopard
    Link
    Personally I dislike OOP and avoid it when I can, but I’m glad that Python is flexible enough to support it. I don’t like some of the conventions and the syntax, but it’s OK. If possible, I try to...

    Personally I dislike OOP and avoid it when I can, but I’m glad that Python is flexible enough to support it. I don’t like some of the conventions and the syntax, but it’s OK. If possible, I try to use collection types from the collections module in the standard library such as namedtuple. Generally when I encounter very stateful Python APIs, they are hard to work with (such as Selenium’s Python driver). I find functional and imperative Python more my style.

    1 vote
    1. [2]
      mrbig
      Link Parent
      Which strand of functional programming you use the most? I’m learning OOP with Java at uni. It feels like killing mosquitoes with a bazooka. I suppose it makes sense for large complex...

      Which strand of functional programming you use the most?

      I’m learning OOP with Java at uni. It feels like killing mosquitoes with a bazooka. I suppose it makes sense for large complex applications, but I can’t tell right now. But I don’t like it. It’s bureaucratic coding.

      1 vote
      1. onyxleopard
        (edited )
        Link Parent
        It’s not possible to write totally side-effect free code in Python, but generally, I try to not use any mutable data types, and if I do, I try to write functions to encapsulate any mutation. I...

        It’s not possible to write totally side-effect free code in Python, but generally, I try to not use any mutable data types, and if I do, I try to write functions to encapsulate any mutation. I like to pass around functions as first-class objects when it makes sense, such as making use of the key argument for sort, min, and max:

        In [12]: words = ['foo', 'bar', 'baz', 'tildes']                                                                                             
        
        In [13]: max(words, key=len)                                                                                                                 
        Out[13]: 'tildes'
        
        In [14]: items = [{'foo': 1, 'bar': 2}, {'foo': 1, 'bar': -2}]                                                                              
        
        In [15]: from operator import itemgetter                                                                                                     
        
        In [16]: sorted(items, key=itemgetter('foo', 'bar'))                                                                                         
        Out[16]: [{'foo': 1, 'bar': -2}, {'foo': 1, 'bar': 2}]
        

        Here’s an example of a program I wrote to compute Krippendorff’s alpha coefficient, a measure of inter-annotator reliability. I only made one class in that program, and that class is just a convenient namespace for consuming code to inject new delta functions. I actually don’t like my implementation there, and I suppose I could break it out into a separate module, but point was really just that I didn’t want to pollute the global namespace with lots of function names. I could also use a decorator (I did the decorator thing in this program with the Format class). I’m not totally happy with either solution, but they work.

        E.g.,

        In [1]: from krippendorff import Difference                                                                                                  
        
        In [2]: class MyDifference(Difference): 
           ...:     def foo(self, v1, v2, *args): # v1 and v2 always differ by 1.0
           ...:         return 1.0 
           ...:     def bar(self, v1, v2, *args): # v1 and v2 never differ
           ...:         return 0.0 
           ...:                                                                                                                                      
        
        In [4]: diff = MyDifference(float)                                                                                                           
        
        In [5]: diff.nominal(None, None)                                                                                                             
        Out[5]: 0.0
        
        In [6]: diff.foo(None, None)                                                                                                                 
        Out[6]: 1.0
        
        In [7]: diff.bar(None, None)                                                                                                                 
        Out[7]: 0.0
        
        In [11]: Difference(float, method='ordinal')._delta(1.0, 3.0)                                                                                
        Out[11]: 16.0
        

        operator.methodcaller is really neat to allow stuff like Difference._delta which is very convenient for allowing a command line driver to specify which delta method to use by interpreting a string argument as a class method name. If you are interested in writing functional Python, I highly recommend checking out the operator, functools, and itertools modules from the standard library.

        4 votes