The Renegade Coder https://therenegadecoder.com Code First. Ask Questions Later. Fri, 27 Mar 2020 23:37:19 +0000 en-US hourly 1 https://wordpress.org/?v=5.4 https://i0.wp.com/therenegadecoder.com/wp-content/uploads/2017/05/the-renegade-coder-icon-cropped.png?fit=32%2C32&ssl=1 The Renegade Coder https://therenegadecoder.com 32 32 127809749 I Applied for A Graduate Associate Teaching Award https://therenegadecoder.com/teach/i-applied-for-a-graduate-associate-teaching-award/ https://therenegadecoder.com/teach/i-applied-for-a-graduate-associate-teaching-award/#respond Mon, 06 Apr 2020 14:00:00 +0000 https://therenegadecoder.com/?p=22436

Now that I have two years of teaching experience, I figured I would test my skills by applying for a teaching award. This article outlines that process.

The post I Applied for A Graduate Associate Teaching Award appeared first on The Renegade Coder.

]]>

Earlier this semester, I went out on a limb and decided to apply for the Graduate Associate Teaching Award at my university. Basically, that means I’m hoping to be recognized for my teaching up to this point. At the moment, I don’t know if I won, but I figured I’d share the process.

Table of Contents

The Application Process

If you want to get a Graduate Associate Teaching Award (GATA) at The Ohio State University (OSU), you have to go through a pretty lengthy process. In total, they mention that you’ll probably spend about 20 hours putting together the entire application, but I think it takes a bit longer than that.

At any rate, in the subsections below, we’ll look at the actual application process. Then, I’ll sort of give you my take on the whole thing.

Acquiring Nominations

Before you can even apply for the award, you have to get nominated. Luckily, nominations can happen at any time during the year. To get one, all it takes is someone filling out the nomination form which includes a simple question like “why do you think this person deserves to be nominated?”

As I hinted at above, anyone can fill out the nomination form. In fact, I could have self-nominated, and I still would have been able to advance to the application process. To be honest, I’m not so sure why the bar is so low. In fact, I am not sure why there is a bar at all. My guess is that it restricts the number of applicants to a group of people that are actually planning to apply.

At any rate, I didn’t know that at the time. In fact, I didn’t even know the nomination process was blind. In other words, I don’t believe it even matters what you put in the box because the panel that reviews the applications will never actually see the nominations.

Honestly, I was a bit bummed by this news because I went out of my way to reach out to old students for support. In the end, I probably picked up 5 or so nominations through cold emails. Part of me feels like I sort of wasted their time. After all, if I could have just self-nominated, I wouldn’t have had to bug them to fill it out.

That said, it worked out! I was able to reach out to some old students and check in on them which was a nice feeling. A lot of them said some really nice things to me unprompted, so that was nice as well. Ultimately, I ended up leveraging one of those interactions for a little more support in the application process outlined below.

Attending Application Orientation

Once you’re nominated, you sort of have to wait until the application window actually opens. This year they revamped the application process, so the portal didn’t open until later December. Then, applications were due late February.

When I found out that I had cleared the first hurdle (i.e. got nominated), they opened up the portal for me which allowed me to begin my application. In addition, they held two meetings to teach applicants about the process. Naturally, I decided to defer any work on the application until I attended one of their meetings.

Eventually, I went to the orientation which was in a large lecture hall, filled with maybe 20 fellow applicants. Suddenly, I was a little underwhelmed. In my mind, I was thinking “are these really the only people applying for the award?” After all, they had planned to have 10 winners, so I was sitting at a comfortable 50% success rate.

Of course, later they mentioned that there was another orientation that featured roughly the same number of people, so my success rate was cut in half. That said, I was feeling pretty good about my odds at that point. This was definitely an award that I could win—ignoring all the wonderfully talented teachers around me.

At any rate, they then spent the next hour outlining exactly what their expectations were for the application: we were to put together a teaching portfolio with the following elements (official list can be found here):

  • Teaching Statement
  • Teaching Responsibilities (OSU only)
  • Instructional Artifact
  • Evaluative Feedback and Summary
  • Overall Student Evaluation of Instruction (SEI) Scores
  • One Course SEI or a Personal or Departmental Evaluation
  • Letters of Recommendation

In the next few sections, we’ll talk about how I actually put this together.

Putting Together a Teaching Portfolio

As you might know by my portfolio site, I was fortunate enough to do a bit of professional development in the past. In other words, I already created a piece of this portfolio: the teaching statement. As a result, I just needed to scope it for this context.

Beyond that, I put everything else together from scratch. For instance, I put together a list of teaching responsibilities which included three different roles: two teaching and one grading.

In addition, I wrote up a summary of my feedback over the years which included an overall review of all my SEIs as well as other feedback sources. Oddly enough, that document is actually what prompted my teaching feedback article.

Since I mentioned SEIs already, I should say that I also collected them for this portfolio. If you’re interested, here they are:

Finally, I put together an instructional artifact which in my case was a peer instruction question. As a part of the requirements, I had to explain the purpose of that artifact. I’ll save you the explanation, and instead I’ll point you to an article on peer instruction.

Requesting Letters of Recommendation

Now, unfortunately, the application doesn’t end after putting together all these resources. On top of the list of documents I collected above, I also had to retrieve a couple letters of recommendation: one from a faculty member and another from a student (optional).

This is where those cold emails came in handy! I was able to get a nice a letter from one of my previous students by reaching out to them to again. In fact, they were quite enthusiastic to burdened by the process, so I’m seriously thankful for that.

Meanwhile, I was a bit at a loss when it came to reaching out to a faculty member. My home department didn’t do a great job of fostering teachers (or students, frankly), so I didn’t feel super comfortable asking for support. Luckily, I had taken several engineering education classes, so I decided to learn on one of those professors. And, boy did I luck out!

Submitting the Application

Once I had all my materials, all I had to do was put them together in a PDF and submit it—sort of…

In reality, the form asked me to list all sorts of information that I didn’t even know. For example, I had to list off contact information for various department officials, both of my references, and my advisor.

On top of that, I had to list off publications (which I didn’t have) for whatever reason. Likewise, they made me write up a blurb for a general audience about my research interests. If you know me, I make everything overly complicated, so I had a hard time narrowing down exactly what my research interests were.

Then, I submitted the application. At which point, I received an email with a copy of my responses. In addition, I was notified that I wouldn’t receive any indication of the results until at least March 15th, 2020 and no later than April 15th, 2020.

Of course, if you live in the present (March 24th, 2020), you know the effects COVID-19 has had on just about everything. As a result, I wouldn’t be surprised if the results are delayed for the foreseeable future. In the next section, we’ll talk about how I felt about this process.

Reflection

After talking about the entire application, I thought it would be interesting to reflect on process. In other words, how long did it take, who did I have to work with, and why I actually did it?

First, let’s talk about the actual timeline. Honestly, I don’t have exact numbers. That said, considering that there are seven elements of the portfolio, I would only get about 3 hours per item according to their guidelines.

While some of those items are out of my hands like recommendation letters, I felt like I spent quite a bit more time on the application than advertised. For example, putting together a teaching statement is no easy matter. It requires thinking about alignment because it ties the whole application together. For example, if I decide to talk about active learning in my instructional artifact, my teaching statement should align with that.

In the end, I spent quite a bit of time just combing over all the files looking for errors. Likewise, I spent a lot of time just cutting down content. As it turns out, it’s really hard to restrict your thoughts to just one page of content. Of course, I am a blogger. Overall, I probably spent closer to 40 hours on the application.

In terms of who I had to work with, that was basically limited to two people: my student and faculty references. The rest of the application was completed by yours truly. Of course, I did interface with a few of the folks overseeing the application process, but I didn’t work with anyone beyond that.

Finally, there’s the question of why I did it. Oddly enough, this was a question that my faculty reference asked me, and I didn’t have a great answer at the time.

At a surface level, I like the idea of being forced to work on professional development. This process would allow me to basically test out application materials before I enter the job market.

However, if you know me, I don’t really care about professional development. If I did, I wouldn’t have trashed one of my previous employers on a public forum. See, the deeper reason why I applied for this award was because I wanted to be recognize for my hard work. As a teacher, I think my students know how hard I work for them, but that doesn’t always translate into departmental or campus-wide recognition.

Finally, the biggest driving force was proving to myself that I’m in the right field. If I could go through this process without quitting, I could reaffirm my belief that teaching is the right profession for me. As a nice byproduct, winning the award would combat my Imposter Syndrome.

Overall, I’d say I am quite happy with myself for actually completing the application. Hell, I only wrote this article, so I could sort of capture this feeling before discovering the outcome.

The Results

If you read up to this point, you know that I still have no idea if I won or not. In fact, I don’t expect to be notified for awhile amidst this pandemic. As a result, I figured I’d share a little bit of good news: I won my department’s version of this award!

When I found out, I was actually kind of shocked. The process for deciding who wins is so opaque that I don’t even know how I got nominated, who decides who wins, or even what the criteria are for the award. That said, I’m pretty stoked. I am supposed to receive the award at a banquet in late April, but who knows if that will happen.

I suppose I’ll have an update by May. When that comes, I’ll follow up with another post. How’s that sound?

In the meantime, help me grow this site by heading over to this post. Otherwise, here are a few great teaching resources from Amazon (ad):

Finally, here are a couple related posts:

Otherwise, thanks for stopping by! I appreciate the support.

The post I Applied for A Graduate Associate Teaching Award appeared first on The Renegade Coder.

]]>
https://therenegadecoder.com/teach/i-applied-for-a-graduate-associate-teaching-award/feed/ 0 22436
How to Pay for Coding School https://therenegadecoder.com/blog/how-to-pay-for-coding-school/ https://therenegadecoder.com/blog/how-to-pay-for-coding-school/#respond Fri, 03 Apr 2020 14:00:00 +0000 https://therenegadecoder.com/?p=23062

Today, we have a kind guest post from our friend, Andy, at LendEDU. They figured you might find value in a post on how to pay for coding school.

The post How to Pay for Coding School appeared first on The Renegade Coder.

]]>

As technology evolves into a foundational aspect of businesses operating around the world, companies are constantly seeking out qualified tech workers to fill positions. In 2019, CNBC reported more than 700,000 open technology positions in the U.S. alone from organizations in need of trained and educated employees in cloud computing, artificial intelligence, and analytics. This high number of job openings has motivated some to learn coding as part of their professional skillset. Coding bootcamps can help in starting or bettering an individual’s technology career, positioning them for the growing number of jobs available here and abroad.

A coding bootcamp is a short-term, intensive training program focused on teaching the skills necessary to improve coding abilities. Some coding bootcamps guide students through coursework in web or mobile development or user experience, while others offer curriculum in specific coding languages, such as JavaScript, Ruby on Rails, and HTML/CSS. The average time to completion for coding bootcamp is 14.4 weeks, with a price tag of $13,500 on average. Because of the time and cost involved, paying for bootcamp out of pocket may not be a viable option. Fortunately, financial resources are available to help cover the cost of coding bootcamp for those who want to improve their skillsets. 

Table of Contents

How to Pay for a Coding Bootcamp

Currently, no federal student loans help cover the cost of a short-term coding bootcamp, but private student loans are an option. Other financial resources, including federal aid programs and employer sponsorships can help cover the cost. 

Federal Aid

Although federal student loans aren’t an option for paying for the tuition of coding bootcamps, government programs exist to cover the upfront cost of tuition. First, the Educational Quality through Innovative Partnerships, or EQUIP, program is an initiative developed through the Office of Educational Technology. 

EQUIP is a test program designed to provide low-income students the ability to complete a coding bootcamp and pay for it using federal financial aid. Students must be using federal financial aid for the first time, and be attending a program with a partner university in the EQUIP program to be eligible. The school’s financial aid department can provide information on how to apply for aid to cover the coding bootcamp tuition. With this financial assistance, students completing a bootcamp have access to the benefits provided by federal student loans, including various repayment programs, deferment and forbearance, and protections under the law.

The GI Bill is a benefit designed specifically for veterans of military service in the U.S., focused on covering the costs of higher education and training. Over the last several years, coding bootcamps have joined the list of eligible training programs to be covered in part or in full by the GI bill. Qualified veterans may receive both tuition and living expenses when attending an eligible coding bootcamp to further their technology skills or lay the groundwork for a new career. Veterans can determine their eligibility for GI Bill educational benefits online or by visiting a Veterans service organization. 

Aside from these federal benefits for select groups of students, no other financial aid options exist on the federal level for coding bootcamps.

Private Student Loans

A handful of private student loan lenders offer qualified borrowers financing options for attending a coding bootcamp. Private student loans require a borrower to have a strong credit history and score, as well as verifiable income that may need to meet a minimum threshold. When credit isn’t strong, a co-signer may be added to the loan application to improve the chances of getting approved. 

If you are approved for a private student loan, the lender provides options for how much you can borrow, the repayment terms available, and the fixed or variable interest rate charged on the loan. 

Typical repayment terms for private student loans range from five to 15 years, but because of the low cost of coding bootcamp compared to a full degree program, repayment terms may be limited to one or two years. In addition to understanding the repayment term, borrowers need to recognize that interest is charged on the loan from the day the funds are received. Interest rates can range from the low single digits to nearly double digits, depending on credit score. The higher the interest rate, the higher the total cost of borrowing for coding bootcamp. However, private student loans can be a smart choice for covering the cost of coding bootcamp when other resources are not available. 

Employer Sponsorships

Some employers may help cover the cost of attending a coding bootcamp as well. Because completing intensive training in coding can help benefit both you as the employee and the employer, companies recognize that paying for a coding bootcamp may generate a return on their investment. Employer sponsorships are not available with every business, nor are they structured the same across the board. Employees may need to work for a company for a certain period before becoming eligible for a sponsorship, or they may need to commit to working for the employer for several months or years after completion to ensure benefits do not need to be repaid. 

Employees can check with their employer to see if sponsorship for coding bootcamp is a possibility, and what the specific terms are for accepting that benefit.

Is Coding Bootcamp Worth It?

Before jumping on the coding bootcamp bandwagon, it’s necessary to understand what the return on investment could be for your career. According to a report on bootcamp graduates, 66 percent reported full-time employment using the skills they learned in coding bootcamp after graduation. The average salary for those with full-time positions came in at just over $67,000 per year. For a $10,000 to $20,000 investment, coding bootcamp may be worth the cost in the end. 

However, those interested in coding bootcamp need to understand their financing options if paying for tuition out-of-pocket isn’t an option. Be sure to select financing that includes flexible repayment terms that fit within your budget, and be selective with the coding school you attend from the start. Completion of coding bootcamp should result in a boost to your skillset and your career prospects in a short period of time after graduation. 


Andy Kearns is a Content Analyst for LendEDU and works to produce personal finance content to help educate consumers across the globe. When he’s not writing, you can find Andy cheering on the new and improved Lakers, or somewhere on a beach.

The post How to Pay for Coding School appeared first on The Renegade Coder.

]]>
https://therenegadecoder.com/blog/how-to-pay-for-coding-school/feed/ 0 23062
How to Convert a String to Lowercase in Python https://therenegadecoder.com/code/how-to-convert-a-string-to-lowercase-in-python/ https://therenegadecoder.com/code/how-to-convert-a-string-to-lowercase-in-python/#respond Mon, 30 Mar 2020 14:00:00 +0000 https://therenegadecoder.com/?p=22445

As this series grows, I’ve started poking at seemingly simple problems to expose their complexity. This time, I thought it would be interesting to look at how to convert a ...

The post How to Convert a String to Lowercase in Python appeared first on The Renegade Coder.

]]>

As this series grows, I’ve started poking at seemingly simple problems to expose their complexity. This time, I thought it would be interesting to look at how to convert a string to lowercase.

As it turns out, there’s a really straightforward solution (lower()), but I think it’s worth looking at a few homemade solutions first. For instance, we could try building up a string by looping over every character. If that sounds interesting, check out the rest of this article.

Table of Contents

Problem Description

If you’ve ever tried to write code which manipulates strings, you know how painful of a process it can be. For instance, try writing some code to reverse a string. Pro tip: it’s not as easy as you think. I know this because I added string reversal as one of the challenges in our Sample Programs repository.

When I was building up that repo, I found out that you can’t just start at the end of the string and print out the characters in reverse. That’ll work for simple strings like most of the text in this article. However, it could fail for more complex characters like emojis.

All that said, Python 3 does a great job of abstracting characters, so you may not run into issues. For example, the following code seems to work fine:

>>> hero = "😊"
>>> hero[::-1]
'😊'

Now, I bring this up because today we want to talk about converting a string to lowercase. If you’ve been around Python awhile, you know there’s a quick way to do this. However, if you haven’t, there’s a chance you might try to do it yourself (or you have to do it yourself for a course). As a result, I’ll be setting a constraint for this entire article: assume ASCII.

This constraint can save us a lot of pain and suffering. It basically restricts us to the first 128 characters (or 256 depending on who you ask). That way, we don’t have to worry about dealing with characters from other languages or emojis.

Assuming ASCII, we should be able to convert a string like “All Might” to “all might” fairly easily. In the sections below, we’ll look at a few solutions that will be able to do just this.

Solutions

In this section, we’ll take a look at each solution I could come up with. Since this problem has been trivially solved by the lower() method, most of these solutions are essentially brute force. In other words, each solution goes through a different strategy for converting a string to lowercase by hand. If that’s not you’re thing, feel free to jump to the last solution. For everyone else, let’s take a look at our first brute force solution!

Convert a String to Lowercase by Brute Force

Since we’re assuming ASCII, we can try to convert our string to lowercase by looking at the ordinal values of each character. In other words, each character is assigned to some number. If a character’s ID falls within the range of capital letters, we should be able to find its corresponding lowercase ID and replace it. That’s exactly what we do below:

hero = "All Might"
output = ""
for char in hero:
  if "A" <= char <= "Z":
    output += chr(ord(char) - ord('A') + ord('a'))
  else:
    output += char

Here, we create a string called hero which stores the name “All Might”. Then, we create an empty output string. After that, we loop over every character in the string checking to see if the current character falls in the range of capital letters. If it does, we convert it to lowercase with this clever little expression:

chr(ord(char) - ord('A') + ord('a'))

By subtracting ord('A'), we get the index of the character in the alphabet. For example, if char was “C”, the expression ord(char) - ord('A') would be 2. Then, all we need to know is what the ordinal value of ‘a’ is to shift our index into the range of lowercase letters. In other words, this expression converts any uppercase letter to lowercase.

One thing I don’t love about this algorithm is the concatenation. In general, it’s a bad idea to concatenate strings in a loop like this. As a result, we could use a list instead:

hero = "All Might"
output = []
for char in hero:
  if "A" <= char <= "Z":
    output.append(chr(ord(char) - ord('A') + ord('a')))
  else:
    output.append(char)
output = "".join(output)

In the performance section, we’ll take a look to see if this matters at all. For now though, let’s dig into some better options.

Convert a String to Lowercase Using ASCII Collections

In the previous solution, we computed lowercase values mathematically. However, what if we just happened to have the lowercase and uppercase letters available to us as a collection? As it turns out, the string library has us covered:

from string import ascii_lowercase, ascii_uppercase

If you’re curious to know what these values look like, I checked for us:

>>> ascii_lowercase
'abcdefghijklmnopqrstuvwxyz'
>>> ascii_uppercase
'ABCDEFGHIJKLMNOPQRSTUVWXYZ'

As we can see, each value is a string containing the alphabet. Now, it’s just a matter of mapping from one set to the other given an index:

hero = "All Might"
output = []
for char in hero:
  if char in ascii_uppercase:
    output.append(ascii_lowercase[ascii_uppercase.index(char)])
  else:
    output.append(char)
output = "".join(output)

Again, we loop over every character in our string. Of course, this time we check if that character is in the uppercase set. If it is, we look for the corresponding lowercase character and add it to our final string. Otherwise, we append the original character.

Personally, I like this solution a little bit better because we’re more explicitly dealing with certain sets of characters. That said, there is still a better solution ahead.

Convert a String to Lowercase Using a List Comprehension

Looking at the solutions above, I thought it might be fun to try to use a list comprehension. It’s not pretty, but it gets the job done:

from string import ascii_uppercase, ascii_lowercase

hero = "All Might"
output = [ascii_lowercase[ascii_uppercase.index(char)] if char in ascii_uppercase else char for char in hero]
output = "".join(output)

If you’d prefer something a little more readable, here’s the same list comprehension with the expression separate from the loop:

[
  ascii_lowercase[ascii_uppercase.index(char)] 
    if char in ascii_uppercase 
    else char 
  for char in hero
]

Basically, we say that for each character in hero, assume we’re going to convert uppercase to lowercase. Otherwise, leave the character unchanged.

Honestly, this might be a bit cleaner if we pulled the expression out into a function:

def to_lowercase(char: str):
  if char in ascii_uppercase:
    return ascii_lowercase[ascii_uppercase.index(char)]
  else:
    return char

Then, we could call this function in place of that mess:

[to_lowercase(char) for char in hero]

Now, that’s a lot cleaner! Of course, there is definitely a better solution to follow. That said, if you like list comprehensions, and you want to learn more about them, check out my article on how to write list comprehensions.

Convert a String to Lowercase Using the lower() Method

Up to this point, we tried rolling our own lowercase function. Due to the complexity of strings, it turned out to be a nontrivial matter. Luckily, the Python developers knew this would be a popular request, so they wrote a method for us:

hero = "All Might"
hero.lower()

And, that’s it! In one line, we can convert a string to lowercase.

Since we assumed ASCII up to this point, there’s not much to say in terms of the benefits with this solution. Sure, lower() is likely more convenient and faster than our previous solutions, but our assumption has stopped us from talking about the real benefit: it works beyond ASCII.

Unlike our previous solutions, this solution will work for basically any locale where the concepts of uppercase and lowercase make sense. In other words, lower() should work in contexts beyond ASCII. If you’re interested in how it works under the hood, check out section 3.13 of the Unicode standard.

Performance

At this point, let’s take a look at how each solution compares in terms of performance. If you’ve been around awhile, you know we start off testing by storing each solution in a string. If this is your first time seeing one of these tutorials, you can get up to speed on performance testing with this article. Otherwise, here are the strings:

setup = """
hero = "All Might"
from string import ascii_lowercase, ascii_uppercase
"""

brute_force_concat = """
output = ""
for char in hero:
  if "A" <= char <= "Z":
    output += chr(ord(char) - ord('A') + ord('a'))
  else:
    output += char
"""

brute_force_list = """
output = []
for char in hero:
  if "A" <= char <= "Z":
    output.append(chr(ord(char) - ord('A') + ord('a')))
  else:
    output.append(char)
output = "".join(output)
"""

ascii_collection = """
output = []
for char in hero:
  if char in ascii_uppercase:
    output.append(ascii_lowercase[ascii_uppercase.index(char)])
  else:
    output.append(char)
output = "".join(output)
"""

list_comp = """
output = [ascii_lowercase[ascii_uppercase.index(char)] if char in ascii_uppercase else char for char in hero]
output = "".join(output)
"""

lower_method = """
output = hero.lower()
"""

Then, if we want to performance test these solutions, we can import the timeit library and run the repeat() method:

>>> import timeit
>>> min(timeit.repeat(setup=setup, stmt=brute_force_concat))
1.702892600000041
>>> min(timeit.repeat(setup=setup, stmt=brute_force_list))
1.9661427000000913
>>> min(timeit.repeat(setup=setup, stmt=ascii_collection))
1.5348989000001438
>>> min(timeit.repeat(setup=setup, stmt=list_comp))
1.4514239000000089
>>> min(timeit.repeat(setup=setup, stmt=lower_method))
0.07294070000011743

Unsurprisingly, the lower() method is incredibly fast. We’re talking a 100 times faster than our brute force solutions. That said, I was actually surprised by the minor improvement in speed that concatenation has over using a list in our example. As a result, I decided to use a larger string for testing:

>>> setup = """
hero = "If you feel yourself hitting up against your limit remember for what cause you clench your fists... remember why you started down this path, and let that memory carry you beyond your limit."
from string import ascii_lowercase, ascii_uppercase
"""
>>> min(timeit.repeat(setup=setup, stmt=brute_force_concat))
22.304970499999996
>>> min(timeit.repeat(setup=setup, stmt=brute_force_list))
24.565209700000025
>>> min(timeit.repeat(setup=setup, stmt=ascii_collection))
19.60345490000003
>>> min(timeit.repeat(setup=setup, stmt=list_comp))
13.309821600000078
>>> min(timeit.repeat(setup=setup, stmt=lower_method))
0.16421549999995477

Somehow, concatenation is still a little bit faster than using a list. This surprised me a lot. After all, pretty much all literature points to concatenation being a bad idea, so I was a bit stumped. As a result, I actually went as far as to duplicate the test code from that article above to see if I was doing something wrong in my testing:

>>> setup = """
hero = "All Might"
loop_count = 500
from string import ascii_lowercase, ascii_uppercase

def method1():
  out_str = ''
  for num in range(loop_count):
    out_str += str(num)
  return out_str

def method4():
  str_list = []
  for num in range(loop_count):
    str_list.append(str(num))
  return ''.join(str_list)
"""
>>> min(timeit.repeat(setup=setup, stmt="method1()"))
156.1076584
>>> min(timeit.repeat(setup=setup, stmt="method4()"))
124.92521890000012

To me, there’s one of two things going on:

  • Either my test is bad
  • Or, there is some crossover point where the join() method is better

As a result, I decided to test the same code for various amounts of loop_count:

# Loop count = 10
>>> min(timeit.repeat(setup=setup, stmt="method1()"))
2.665588600000774 
>>> min(timeit.repeat(setup=setup, stmt="method4()"))
3.069867900000645

# Loop count = 25
>>> min(timeit.repeat(setup=setup, stmt="method1()"))
6.647211299999981
>>> min(timeit.repeat(setup=setup, stmt="method4()"))
6.649540800000068

# Loop count = 50
>>> min(timeit.repeat(setup=setup, stmt="method1()"))
12.666602099999182
>>> min(timeit.repeat(setup=setup, stmt="method4()"))
12.962779500000579

# Loop count = 100
>>> min(timeit.repeat(setup=setup, stmt="method1()"))
25.012076299999535
>>> min(timeit.repeat(setup=setup, stmt="method4()"))
29.01509150000038

As I was running these tests, I had a sudden epiphany: you can’t run other programs while testing code. In this case, tests were taking so long that I decided to play Overwatch while waiting. Bad idea! It skewed all my tests. As a result, I decided to retest all of our solutions under the same exact conditions. Here are the results where the parentheses indicate the length of the string under test:

SolutionTime (10)Time (25)Time (50)Time (100)
Brute Force Concatenation0.949443.728148.3357917.56751
Brute Force List1.275674.454639.3325820.43046
ASCII Collection1.234414.262189.2658819.34155
List Comprehension1.032742.994146.1363412.71114
Lower Method0.071210.085750.110290.163998

To be honest, I wasn’t able to isolate the discrepancy. My guess is that at some point concatenation gets bad; I just haven’t been able to prove it. That said, I haven’t found myself building up massive strings, so I don’t imagine it actually matters. Of course, there’s probably some application where it does.

At any rate, it’s clear that the lower() method is almost certainly the way to go (unless you have some sort of class assignment that says otherwise). Of course, take these measures with a grain of salt. For context, I’m on a Windows 10 system running Python 3.8.2.

Challenge

Since we spent the whole article talking about converting strings to lowercase, I figured for the challenge we can try something a little different. To make things more interesting, I thought it might even be fun to specify a couple challenges:

  1. Convert a string to uppercase (e.g. “all might” -> “ALL MIGHT”)
  2. Convert a string to sarcasm case (e.g. “All Might” -> “AlL miGhT”)
    • For this one, I wasn’t sure if it made more sense to alternate or just randomly case each letter. You can decide!
  3. Convert a string to title case (e.g. “all might” -> “All Might”)

Each one of these challenges comes with a unique set of problems. Feel free to share a solution to any of them down below in the comments. As always, I’ll drop one down there as well to get y’all started.

A Little Recap

With all that said, I think we’re done for the day. Here are all the solutions from this article in one convenient place:

from string import ascii_lowercase, ascii_uppercase

hero = "All Might"

# Brute force using concatenation
output = ""
for char in hero:
  if "A" <= char <= "Z":
    output += chr(ord(char) - ord('A') + ord('a'))
  else:
    output += char

# Brute force using join
output = []
for char in hero:
  if "A" <= char <= "Z":
    output.append(chr(ord(char) - ord('A') + ord('a')))
  else:
    output.append(char)
output = "".join(output)

# Brute force using ASCII collections
output = []
for char in hero:
  if char in ascii_uppercase:
    output.append(ascii_lowercase[ascii_uppercase.index(char)])
  else:
    output.append(char)
output = "".join(output)

# Brute force using a list comprehension
output = [ascii_lowercase[ascii_uppercase.index(char)] if char in ascii_uppercase else char for char in hero]
output = "".join(output)

# Built-in Python solution
output = hero.lower()

With that, all that’s left is to recommend some ways you can support the site. Otherwise, check out some of these Python resources on Amazon (ad):

In addition, you’re welcome to keep browsing. Here are some related articles:

If not, thanks for sticking around! I appreciate the support.

The post How to Convert a String to Lowercase in Python appeared first on The Renegade Coder.

]]>
https://therenegadecoder.com/code/how-to-convert-a-string-to-lowercase-in-python/feed/ 0 22445
5 Ways to Get Feedback on Your Teaching https://therenegadecoder.com/teach/ways-to-get-feedback-on-your-teaching/ https://therenegadecoder.com/teach/ways-to-get-feedback-on-your-teaching/#respond Fri, 27 Mar 2020 14:00:00 +0000 https://therenegadecoder.com/?p=22682

As I close in on two years of teaching amidst the Coronavirus pandemic, I figured I'd share a list of ways of getting feedback.

The post 5 Ways to Get Feedback on Your Teaching appeared first on The Renegade Coder.

]]>

Over the last year or so, I’ve been rapidly growing as a young educator. In that time, I’ve had to find various ways to get feedback on my teaching, so I could continue to grow. Now, I’m passing off those lessons to you.

As it turns out, there are several ways to get feedback on your teaching. In this list, we’ll cover 5 which include observing body language, administering in-class assessments, developing surveys, requesting peer reviews, and hosting external reviews. In the sections below, we’ll take a look at each of these solutions in more detail.

Table of Contents

What Is Feedback?

When we talk about feedback in an education context, we have to ask: what are we trying to assess? Or even better, what are we trying to improve?

In other words, feedback isn’t as simple as asking: how can I improve my teaching? We have to ask ourselves what it is we want to learn or improve about our teaching. That’s how we get to the real answers.

Of course, knowing what to assess and assessing it are two completely different challenges. For example, if I want to improve my peer instruction activities, I need to know the best method of assessing them. Is gathering feedback through student body language enough, or do I need to do more?

While I don’t plan to tackle these sort of nuanced questions in this article, I do plan to at least share a toolkit of feedback methods. It’s up to you to decide what you find useful.

Feedback Methods

In this article, we’ll take a look at five different ways to get feedback on your teaching. To help you out, I’ve ordered them by increasing levels of investment (time, energy, etc.). In other words, the first couple methods should be low hanging fruit. If you want something more involved, move down the list.

Body Language

One of my favorite ways to get direct feedback is by observing student body language—particularly faces. It may seem silly but being aware of body language is a great way of gauging the engagement level of a class.

Here are few things I look for:

  • Sleeping
  • Yawning
  • Reclining
  • Faces in laptops/phones
  • Chit-chat
  • Note taking
  • Questions
  • Confused looks
  • Smiles
  • Head nods
  • Eye contact
  • Attendance (not a form of body language, but it’s data)

Now, these behaviors in isolation aren’t enough to indicate lack of engagement. For example, you might have students who are just tired because it’s late in the semester and the flu is going around.

That said, these behaviors can be a great indicator of engagement if observed in context. In other words, if 10% of the class is asleep and another 30% of the class has their faces buried in laptops, you might want to rethink your teaching strategies.

Likewise, engagement isn’t the only type of feedback you can get from body language. For instance, confused looks and a lack of questions could indicate that you’re way too deep in material. If that happens, it might be time to move on to our next form of feedback.

In-Class Assessments

If you’re curious about how you’re teaching is going, a great way to find out is to ask your students to answer some questions. If they can’t answer them, or their answers aren’t satisfactory, it might be time to revisit some material.

One way I like to do this is with regular leading questions. For example, if I’m teaching about recursion, I might ask a question like “how would you implement this method normally (read: iteratively)?” Then, I might follow up with other leading questions like “what if there’s a method that already does this?”, “what if that method can only accept ‘smaller’ input?”, “are these changes enough to get this working?”

In essence, these guiding questions force students to think ahead. If they can’t answer them, it’s possible that they lack context. Alternatively, the questions could just be poorly worded. In either case, I find value in involving the class in lecture process. In other words, can my students predict what comes next? If yes, we’re on track. Otherwise, it’s time to backtrack.

In addition to leading questions, I’m a big fan of peer instruction—as evidenced by my massive peer instruction article. In essence, peer instruction is the process of administering multiple choice questions where students can discuss their answers. On one hand, it’s a great tool because students who don’t understand something can lean on their peers for support. On the other hand, it’s just a great way to check up on class understanding.

If you find that students can’t answer your questions, there’s one of two possible issues: either the question is poorly written, or the students don’t know the material well enough to answer it. If you add a debrief stage to your peer instruction questions, you can find out which one it is by asking. Then, you can adjust accordingly.

Surveys

If body language and in-class assessments aren’t doing the trick, it might be time to ask your students to fill out a questionnaire. Personally, I do this just to mine for testimonials, but our department also sends out an end of semester evaluation.

As with all of the methods in this list, it’s not useful to just ask for feedback generically. Your survey should include questions which target specific aspects of your teaching that you’d like to improve. For instance, my survey includes rating scales for the following topics:

  • Skill and Responsiveness of Instructor
  • Course Content
  • Level of Effort

In addition, I like to leave some space for long form questions like “what aspects of this course were most useful or valuable?” and “How would you improve this course?” That said, these are probably a bit to broad to get anything useful.

Keep in mind that you don’t have to make semester review surveys. You could just put together a survey because you have a specific issue you’d like to address. For example, I once put together a survey for course and exam alignment. In this survey, I asked questions like “do you feel the exam lined up with what you expected?” and “what exam topics do you feel needed more emphasis in class?”

Again, OSU has great resources for this. For instance, they have a survey creator tool which you can use to generate PDF surveys. If you prefer an electronic survey, you might consider using this tool to snag example questions.

Peer Review

Another way to get feedback—although probably my least favorite—is to ask a peer to observe your class. The idea here being that you would ask someone with teaching expertise to actually watch you teach in some capacity (e.g. lecture, lab, office hours, etc.). Although, it’s possible to have a peer review other aspects of your teaching like your assessments.

At any rate, for a peer review to go well, I recommend asking your peer to focus on specific aspects of your teaching. Otherwise, you might get a ton of random feedback in return. For instance, I was once told I move around too much.

Now, I always create a rubric for my reviewer. For instance, I once asked a reviewer to only critique me on my peer instruction. That way, I wouldn’t get comments about my teaching style. Here’s what portions of that rubric looked like:

ItemsBeginningMeetingExceedingComments
Peer Instruction (PI) Question(s) Relates to lecture contentStretches students’ understanding but doesn’t address any misconceptionsChallenges key misconceptions relevant to lecture content
PI Multiple Choice Answers Relate to question, but some are obviously wrongForce students to carefully consider their response but don’t target misconceptions Include “traps” that target misconceptions
PI Discussion Learning Facilitates peer dialogue related to question responses Challenges students to consider another student’s perspective Challenges students to consider another student’s perspective

Of course, if you don’t know what you want reviewed, it might not hurt to have a veteran sit in on your class. That said, as I’ve alluded to already, every educator does their job differently. In other words, the feedback you get probably won’t not align with your personal teaching philosophy. As a result, it’s probably not worth the headache.

External Review

Another option for getting feedback is to find an organization which does teaching reviews. For example, The Ohio State University (OSU) has an office call the University Institute for Teaching and Learning (UITL), and they offer a program called Small Group Instructional Diagnosis (SGID)—yes, I’m aware that’s a lot of acronyms.

At any rate, a SGID is basically a feedback collection activity held by an instructional consultant at UITL. First, they’ll sit down with you to gather context around your situation. Then, they’ll facilitate an activity for about 20 minutes which collects feedback on your teaching. Then, they report back what they found.

When I did it, I was teaching a software components course. At the time, I had a couple main worries. First, I felt like I still wasn’t doing a good job of managing my graders. In particular, I knew we didn’t have good alignment in terms of expectations, so I expected that to come up. Second, I had a stronger class than usual, so I sometimes went down rabbit holes. As a result, I anticipated complaints about moving too fast or not focusing on the expected material.

As expected, the SGID came back with all the same feedback I anticipated. That said, the cool part about the SGID is that it includes a section that’s actionable. In other words, students get a chance to suggest how they would change things which saves me the time and energy of figuring out solutions myself.

If you’re interested in seeing an example report, here’s mine. In it, you’ll see the three questions they ask along with a breakdown of each groups’ responses. In addition, you’ll see each comment includes a number of students who agree with the statement. That way, you can figure out if the issue is effecting everyone or just a student or two.

All that said, when getting an external review (or any review for that matter), it’s super important that you report back to your students, so they know their feedback isn’t going to the void.

Share Your Feedback Methods

While I’m happy to share five ways to get feedback on your teaching, I’m sure there are dozens if not hundreds of other methods. Why not share some of your favorites with us in the comments?

While you’re here, I put together a brief list of feedback related resources from Amazon below (ad):

Likewise, you might enjoy some of the following related articles:

Otherwise, thanks for sticking around! I appreciate the support.

The post 5 Ways to Get Feedback on Your Teaching appeared first on The Renegade Coder.

]]>
https://therenegadecoder.com/teach/ways-to-get-feedback-on-your-teaching/feed/ 0 22682
How to Round a Number in Python: Truncation, Arithmetic, and More https://therenegadecoder.com/code/how-to-round-a-number-in-python/ https://therenegadecoder.com/code/how-to-round-a-number-in-python/#respond Mon, 23 Mar 2020 14:00:00 +0000 https://therenegadecoder.com/?p=22453

Remember learning to round in grade school? Me too! The only problem is I don’t use the idea very often. As a result, I don’t always remember how to round ...

The post How to Round a Number in Python: Truncation, Arithmetic, and More appeared first on The Renegade Coder.

]]>

Remember learning to round in grade school? Me too! The only problem is I don’t use the idea very often. As a result, I don’t always remember how to round a number in programming contexts like Python. Luckily, I’ve pieced together a little article for myself. Hopefully, you get some value out of it as well.

As it turns out, there are a ton of ways to a round a number in Python. For instance, we could truncate the fraction altogether using a cast to int: int(). Of course, there are more sophisticated options like the round() function which rounds to the nearest even number for midway values like 7.5. That said, feel free to roll your own solution. I built my own “round-half-up” solution using the ternary operator: int(x + .5) if x >= 0 else int(x - .5). Check out the rest of the article for details.

Table of Contents

Problem Description

Rounding is one of those operations we sort of take for granted in everyday life. For instance, I use Acorns which rounds up my purchases to the nearest whole dollar and invests the excess on my behalf.

Unfortunately, rounding to whole numbers isn’t an obvious operation in programming. There’s no operator for rounding in most languages, and I doubt there ever will be. Instead, we often have to lean on a library or roll own one.

To make things more complicated, rounding isn’t always an obvious operation. For example, how do we know when to round up or down? The way I was taught in school was to round numbers up (away from zero) when the decimal is .5 or greater.

As it turns out, there are a lot of different ways to round a whole number. In fact, I found this interesting article in the Electronic Engineering Times which outlines several different rounding methods. To summarize, here are a few options:

  • Round-toward-nearest: round to the closest number (but, what about .5?)
  • Round-half-up: round-toward-nearest where .5 rounds away from zero (e.g 4.5 rounds to 5)
  • Round-half-down: round-toward-nearest where .5 rounds toward zero (e.g. 4.5 rounds to 4)
  • Round-half-even: round-toward-nearest where .5 rounds toward the nearest even number (e.g. 4.5 rounds to 4 while 5.5 rounds to 6)
  • Round-half-odd: round-toward-nearest where .5 rounds toward the nearest odd number (e.g. 4.5 rounds to 5 while 5.5. rounds to 5)
  • Round-alternate: round-toward-nearest where .5 alternates between rounding up and down over time (e.g. 4.5 rounds to 5 then 5.5 rounds to 5)
  • Round-random: round-toward-nearest where .5 rounds up or down randomly (e.g 4.5 could round to either 4 or 5)
  • Round-cieling: round all decimals toward positive infinity (e.g 4.3 rounds to 5 while -4.7 rounds to -4)
  • Round-floor: round all decimals toward negative infinity (e.g. 4.7 rounds to 4 while -4.7 rounds to -5)
  • Round-toward-zero: round all decimals toward zero (e.g. 4.7 rounds to 4 while -4.7 rounds to -4)
  • Round-away-from-zero: round all decimals away from zero (e.g. 4.3 rounds to 5 while -4.3 rounds to -5)

Clearly, there are a lot of ways to round numbers. For the purposes of this article, we’ll be using the “round-half-up” method. In other words, numbers like 3.5, 5.5, and -2.5 will all round up to 4, 6, and -3, respectively.

Solutions

In this article, we’ll take a look at a few different ways of rounding numbers in Python. As always, we’ll start with the straightforward or brute force solutions. Then, we’ll move our way through more common solutions.

Rounding by Truncation

One way to round a number is to trim the decimal place off through truncation:

x = int(5.3)  # stores 5

In this example, x will store 5 as we trim off the .3. If we were to change the example value to something should round up, we’ll be disappointed:

x = int(5.7)  # stores 5

Clearly, this isn’t the “round-half-up” solution we discussed above, but it’s a nice shortcut if we just need to remove the decimal place (i.e. “round-toward-zero”).

That said, the simplicity of this solution gives us a nice benefit: truncation works for negative numbers as well:

x = int(-5.7)  # stores -5

Of course, if we want a true “round-half-up” solution, we’ll need to try something else.

Rounding by Control Flow

If we think about how “round-half-up” works, then we can probably piece together some if statements to get it done:

x = 5.3
fraction = x - int(x)
if abs(fraction) >= .5:
  offset = 1 - fraction
  x = x + offset
else:
  x = x - fraction

Here, we can compute the fractional portion of a number by using our previous truncation solution. In other words, we can subtract the truncated value from the actual value to get the fraction. In this case, int(x) will return 5 which we’ll subtract from 5.3. As a result, fraction stores .3 (ish).

Then, we can use that fraction to perform some control flow. For instance, if the absolute value of fraction is greater than or equal to .5, we know we need to round up. Here, the absolute value accounts for the fact that fraction could be positive or negative. Otherwise, we might have to write a slightly more annoying if statement. If you want to learn more about computing absolute value in Python, I have a whole separate article on that.

At any rate, to round a number up, we need to compute the distance to the next number which we call offset. We can compute that by subtracting fraction from 1. Now, it’s just a matter of adding the offset to x, and we’re done.

On the other hand, if we find that the absolute value of fraction is actually less than .5, we can subtract that fraction directly from x. This will work regardless of if x is positive or negative.

If we want to go the extra mile, we could cast x to an integer. That said, this should get the job done—barring any pesky rounding errors.

Rounding by Arithmetic

Another really clever way to “round-half-up” is to take advantage of the truncation solution from above with a slight modification:

x = int(5.3 + .5)

Here, we’ve added .5 directly to x. If the fractional portion of x happens to be .5 or greater, x will roll over into the next number. Then, when we truncate x, we’ll have successfully rounded it.

On the other hand, if the fractional portion of x is below .5, the whole number portion of x will stay the same. As a result, truncating x will have the effect of rounding the number.

Unfortunately, this solution won’t work when x is negative. To handle that case, we’ll need some sort of branch. Because I’m lazy, and I like one-liners, I’m going to opt for the ternary:

x = 5.3
int(x + .5) if x >= 0 else int(x - .5)

Now, if x is negative, we’ll subtract .5 rather than adding it. If there’s a more clever solution, let me know in the comments.

Rounding With the round() Function

If writing a rounding algorithm by hand is out of the question, Python actually provides a built-in rounding function:

round(5.3)

Unfortunately, it’s behavior doesn’t quite map out to our “round-half-up” algorithm. Instead, it’s a bit more complicated. Let’s take a look at a few examples:

>>> round(.5)
0
>>> round(-.5)
0
>>> round(1.5)
2
>>> round(2.5)
2
>>> round(3.5)
4
>>> round(-1.5)
-2
>>> round(-2.5)
-2
>>> round(-3.5)
-4

If we look back at our list of rounding algorithms, we’ll find that the Python developers have actually implemented the “round-half-even” algorithm. When I did some research on this algorithm, I found that it’s sometimes called bankers rounding—the more you know!

Honestly, there’s not much else to say about this solution. However, it’s important to note that the round function in Python can actually work for floating point values as well. For example, we can round out to the tenths place as follows:

>>> round(3.52, 1)
3.5

How cool is that?

Performance

With the solutions out of the way, let’s take a look at how they perform. To do that, we’ll need to capture each solution in a string:

setup = """
x = 2.5
"""

truncation = """
int(x)
"""

control_flow = """
fraction = x - int(x)
if abs(fraction) >= .5:
  offset = 1 - fraction
  x + offset
else:
  x - fraction
"""

arithmetic = """
int(x + .5) if x >= 0 else int(x - .5)
"""

banker = """
round(x)
"""

With our strings ready to go, all we need to do is load in the timeit library and launch our tests:

>>> import timeit
>>> min(timeit.repeat(setup=setup, stmt=truncation))
0.1537370000005467
>>> min(timeit.repeat(setup=setup, stmt=control_flow))
0.43060659999900963
>>> min(timeit.repeat(setup=setup, stmt=arithmetic))
0.2925704000008409
>>> min(timeit.repeat(setup=setup, stmt=banker))
0.25559939999948256

Perhaps unsurprisingly, truncation wins in the speed contest. However, the built-in round() function is actually quite quick! I imagine that’s because the function is implemented in a lower level language.

As always, take these measurements with a grain of salt. I ran each of them on a Windows 10 machine with Python 3.7.3. Also, if you’re interested in this performance testing process, I have a whole article about it.

Challenge

When it comes to rounding, there are a ton of different algorithms. And for each algorithm, there are probably thousands of contexts where they are used. Naturally, I thought it would be fun to make you apply the rounding algorithm in one of those contexts, but I figured it might be more fun to dig into other rounding algorithms instead.

For this challenge, I’m asking you to implement your own bankers rounding algorithm. In other words, write some python code that would implement that same style of rounding that is provided by Python’s round() function.

When you think you have something, wrap it in a function and test it on the following inputs:

DescriptionInputOutput
Near Zero0.50
Standard Case0.71
Standard Case1.21
Even Round Up1.52
Even Round Down2.52
Even Round Up Negative-1.5-2
Even Round Down Negative-2.5-2

Then, when you’re ready, your solution in the comments!

A Little Recap

At long last, we’ve reached the end of this post. As always, here’s a list of each solution used in this article:

x = 17.1

# Truncation
int(x)

# Control flow rounding
fraction = x - int(x)
if abs(fraction) >= .5:
  offset = 1 - fraction
  x + offset
else:
  x - fraction

# Arithmetic rounding
int(x + .5) if x >= 0 else int(x - .5)

# Functional rounding
round(x)

If you got any value out of this article, consider supporting The Renegade Coder by heading over to my list of ways to help grow the site. Otherwise, consider checking out some of these Python resources on Amazon (ad):

In addition, you might find value in the following related posts:

With all that said, thanks for stopping by. Hope to see you back here soon!

The post How to Round a Number in Python: Truncation, Arithmetic, and More appeared first on The Renegade Coder.

]]>
https://therenegadecoder.com/code/how-to-round-a-number-in-python/feed/ 0 22453
Experimenting With Site Layout in 2020 https://therenegadecoder.com/meta/experimenting-with-site-layout-in-2020/ https://therenegadecoder.com/meta/experimenting-with-site-layout-in-2020/#respond Fri, 20 Mar 2020 14:00:00 +0000 https://therenegadecoder.com/?p=22715

If the site stays the same for too long, I begin to hate it. Naturally, I decided to experiment a bit with the site layout again. Check it out!

The post Experimenting With Site Layout in 2020 appeared first on The Renegade Coder.

]]>

Every once in awhile, I like to take a good look at my site to decide if there’s any way to make it fresh and interesting. During Spring Break this year, I did just that. Now, I have a fresh new site layout with some nice additions. Let me know what you think!

Table of Contents

Sidebar Overhaul

As a minimalist, I don’t like to overwhelm my users with flashy buttons, animations, and calls to action. In fact, for a long time, I tried to avoid adding any elements to the sidebar as to attract everyone to the small amount of content that was actually there.

Over time, I experimented with different layout elements, but nothing really stuck beyond a picture of myself and a search bar. Then, I had this great idea! What if I added the table of contents to the sidebar? Better yet, what if I also made it stick? That became my new goal.

Now, you’ll notice on nearly every post I have a table of contents in the sidebar. When you scroll down, you’ll even see the table of contents move with you. This was an idea that I actually stole from my Trill Trombone website. Although, this time it was for good rather than evil.

If you look around the site, you may notice that the table of contents isn’t everywhere. Unfortunately, I couldn’t figure out how to reduce the number of elements that show up, so list posts and reflections straight up don’t display it. In addition, there are likely other posts that have far too many headings to support the table. I’ll be removing it as I notice them.

In addition to the table of contents, I’ve also added elements for members, products, and advertisements. Hopefully, that will help direct some people to the other ways they can support the site.

Finally, I updated the text under my picture to link to both my portfolio and my new support article.

Styling Overhaul

One thing that I’ve been really scared to try is styling. After all, up until this point, I’ve tried to build everything around theme and plugin default behavior. Of course, that leaves a lot to be desired, and I desire a lot.

Well, I finally decided to get over my fear of CSS and overhauled the visual styling of my sidebar. Not only are there new widgets there, but now it looks considerably different. Here’s all the code that got that done:

#ezw_tco-5, #woocommerce_products-5, #text-8, #patreon_wordpress_login_widget-3, #custom_html-14, #woocommerce_widget_cart-3, .wpcnt, .post-last-modified {
	border: 1px solid;
	border-radius: 16px;
	padding: 15px;
	border-color: gray;
	background: #f9f9f9;
}

As you can see, each of the widgets now shares the same styling elements:

  • 1 pixel solid border
  • 16 pixel border radius (rounded corners)
  • 15 pixels of padding to adjust for comfortable whitespace inside the element
  • Gray border color
  • Light gray background color

In addition, these same changes were applied to my last update date under each featured image. Of course, I had to make a few specific changes for that:

.post-last-modified {
	text-align: center;
	font-style: italic;
}

Now, the text is italicized and center just like it used to be.

Likewise, my ads at the bottom of the page also feature the new styling. Now, they no longer seem out of place!

Overall, I’m quite pleased with the style updates. Now everything looks consistent even if it isn’t. The simple containers make things look nicer.

Last Updated Date Overhaul

Last updated date was something I added as a measure of proving the freshness of my content awhile back. With all the work I’ve put in, I was worried that some of these articles would lose value over time simply because of the publish date. At least, that was the reason I decided to added the last updated date.

Well, I’ve made some changes to it. For one, the styling is consistent with my widgets. In other words, that date is nicely packed in a little gray window.

Likewise, I’ve also updated the last update date text. Now, it states the date in a human readable format. Instead of listing the date, it states how recent the latest update was (i.e. 5 days ago). In addition, it details which author made the most recent changes.

On top of all that, I have the plugin working in compatibility mode. Now, it replaces the post publish date in the meta data with the last updated date. Hopefully, that gives it better traction in search engines. Of course, I like to keep the actually publish date on each post.

Overall, I don’t think this change will impact user experience much. That said, I do think it’s a nice quality of life change for me!

Plans Going Forward

Right now, I am at the beginning of my spring break. My goal over this next week is to get enough content scheduled to get me through to the end of the semester (i.e. April 20th). In other words, I need to write roughly 10 articles including this one. If we include exams, I might need a couple additional articles.

On top of that, I was hoping to record a YouTube video or two. Unfortunately, I don’t see that happening as I also have two assignments to finish before March 18th. That said, I’m hopeful! By the time this article is finished, I’ll have about a week left in break. Let’s see what gets done!

In the meantime, feel free to recommend some ideas for the site. This summer, I’m planning to take a month or two off to relax. Of course, I also want to get ahead on this site! That would be a good time for me to start working on new ideas.

At any rate, that’s all I’ve got for today’s update! Thanks for sticking around.

The post Experimenting With Site Layout in 2020 appeared first on The Renegade Coder.

]]>
https://therenegadecoder.com/meta/experimenting-with-site-layout-in-2020/feed/ 0 22715
How to Create a List in Python: Loops, Comprehensions, and More https://therenegadecoder.com/code/how-to-create-a-list-in-python/ https://therenegadecoder.com/code/how-to-create-a-list-in-python/#respond Mon, 16 Mar 2020 14:00:00 +0000 https://therenegadecoder.com/?p=22618

As this series grows, I find myself digging back into the basics. Today, we'll look at a few ways to create a list in Python.

The post How to Create a List in Python: Loops, Comprehensions, and More appeared first on The Renegade Coder.

]]>

If you’re working with Python for the first time, you might be interested in learning how to store data. For example, you might want to collect a list of exam scores, so you can average them. If so, the list data structure gets the job done. But, how do you create a list in Python? That’s the topic of today’s article.

As it turns out, there are a few different ways to create a list. First, we could create a list directly as follows: my_list = [0, 1, 2]. Alternatively, we could build that same list using a list comprehension: my_list = [i for in range(0, 3)]. Finally, if we need more control, we could build up our list using a loop and append(). In the remainder of this article, we’ll look at each solution in detail.

Table of Contents

Problem Description

When it comes to working with different types of data in Python, it’s helpful to have some way to manage it. Luckily, Python supports and easy-to-use data structure for storing all kinds of data: the list.

In Python, the list is an array-like data structure which is dynamic in size. In other words, we don’t have to worry about knowing how many items we have before we create our list. For those of us who work in languages like Java or C, we’re used to being stuck with the following syntax:

int[] list = new int[10];

Luckily, Python has a much cleaner syntax. Specifically, we have two options:

  1. Create a list using the constructor: my_list = list()
  2. Or, create a list using an empty list: my_list = []

But, what if we want to populate that list? That’s the problem we’ll be tackling today. Fortunately, there are several solutions.

Solutions

At this point, we’ll take a look at a few ways to create a list in Python. As always, we’ll work our way from straightforward to more complex solutions. After that, we’ll compare each solution’s performance. At any rate, let’s dive in!

Create a List by Hand

One of the nice things about Python is that we can create a list by hand. In other words, if we know how we want to populate the list, we can write those contents out directly:

my_list = ["Crosby", "Malkin", "Letang", "Rust"]

In one line, we managed to create a variable called my_list. Then, we assigned it a literal list which contains a few Penguins players.

Now, if we want to interact with this list, we can. For instance, we could get any of the following information:

  • First player: my_list[0]
  • Last player: my_list[-1]
  • First two players: my_list[:2]
  • Every other player: my_list[::2]

If you’re interested in articles on list interaction, I’ve written a thing or two:

Otherwise, let’s look at a few other solutions.

Create a List with a Loop

Since lists in Python are dynamic, we don’t actually have to define them by hand. In other words, we can create an empty list and add items to it with a loop:

my_list = []
for i in range(10):
  my_list.append(i)

Here, we’ve created an empty list and assigned it to my_list. Then, we run a loop over a range of numbers between 0 and 9. Each number is then added to the list using append().

When this code snippet is all said and done, we’ll have a list that looks something like the following:

[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

As we can probably image, we could use this loop to populate a list in just about any way we want. For example, we could modify our range to give us only even values:

my_list = []
for i in range(0, 10, 2):
  my_list.append(i)

In this case, my_list would only contain even numbers between 0 and 9:

[0, 2, 4, 6, 8]

Likewise, there are a ton of different ways to add items to lists as well. If you’re interested in that sort of thing, I have an article on that.

Create a List with a List Comprehension

One of my favorite ways to create a list is using the list comprehension functionality. Essentially, it’s a compressed loop syntax that lets us generate simple lists. For instance, the first loop example could be written as a list comprehension as follows:

my_list = [i for i in range(10)]

Now, instead of manually appending items to a list, this expression handles all the heavy lifting. As a result, we can focus on modifying the expression to do fun things like scale all values in the range by 3:

my_list = [i * 3 for i in range(10)]

This expression will generate a list that looks like the following:

[0, 3, 6, 9, 12, 15, 18, 21, 24, 27]

While I’d be happy to dig into all the details, I already have a fun article and even a video which cover list comprehensions in depth. Check those resources out if you’re interested.

Performance

Now that we have a few solutions, let’s compare their performance. To do that, we’ll need to generate some strings:

static = """
my_list = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
"""

loop = """
my_list = []
for i in range(10):
  my_list.append(i)
"""

comprehension = """
my_list = [i for i in range(10)]
"""

At this point, all we have to do is import the timeit library, so we can begin testing:

>>> import timeit
>>> min(timeit.repeat(stmt=static))
0.08311530000000289
>>> min(timeit.repeat(stmt=loop))
1.0872243000000026
>>> min(timeit.repeat(stmt=comprehension))
0.7429419999999993

And, there you have it! The quickest way to create a list is to declare it statically. That said, if you have to generate a list, the list comprehension seems to be the way to go.

Challenge

Now that you know how to create a list, I have a little challenge for you: create a list which contains the first 100 terms of the fibonacci sequence. For the purposes of this exercise, we’ll assume the first two terms are 1 and 1.

Feel free to use any solution from this article to generate your list. For example, you could compute the first 100 terms by hand and build up your list statically, Alternatively, you might choose to use a loop or even recursion to populate your list.

If you manage to generate the list using a list comprehension, let me know! I have no idea if that’s possible–at least not without doing some really nasty stuff. After all, you can’t access elements of the list as you’re building it, so it would be tough to track the previous values. That said, you may be able to take advantage of the new walrus operator or some outside state tracking mechanism.

At any rate, I’ll drop a solution in the comments. If you come up with something different, let me know!

A Little Recap

At this point, we’ve reached the end of the article. As always, I like to share a list of all the solutions for your perusal:

# Create a list statically
my_list = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

# Create a list with a loop
my_list = []
for i in range(0, 10, 2):
  my_list.append(i)

# Create a list with a list comprehension
my_list = [i for i in range(10)]

And with that, all I ask is that you take a trip over to my post about different ways to support the site. If you could chip in, that would really help the site grow. Otherwise, check out some of these Python resources on Amazon (ad):

While you’re here, consider checking out some of these related articles:

Thanks for sticking around! I appreciate it.

The post How to Create a List in Python: Loops, Comprehensions, and More appeared first on The Renegade Coder.

]]>
https://therenegadecoder.com/code/how-to-create-a-list-in-python/feed/ 0 22618
How to Compute Absolute Value in Python: Control Flow, Abs(), and More https://therenegadecoder.com/code/how-to-compute-absolute-value-in-python/ https://therenegadecoder.com/code/how-to-compute-absolute-value-in-python/#respond Fri, 13 Mar 2020 14:00:00 +0000 https://therenegadecoder.com/?p=22457

Today, I'm sharing a few ways to compute absolute value in Python. If you thought the standard library was the only way to get it done, buckle up!

The post How to Compute Absolute Value in Python: Control Flow, Abs(), and More appeared first on The Renegade Coder.

]]>

As Python is increasingly used for computation, it becomes more important for math related resources to be made available. To aid in that effort, I figured I’d share a few ways to compute absolute value in Python.

As it turns out, there are a few ways to compute absolute value in Python. First, there’s the abs() function which comes built in. Alternatively, there’s an arithmetic expression that gets the job done: (x**2)**0.5. Finally, a quick negative test (i.e. if x < 0: x = -x works as well. Which one you choose depends on your needs. Luckily, we’ll dig into the details below.

Table of Contents

Problem Description

In mathematics, the absolute value of a number is its magnitude (i.e. ignore the sign). For example, the absolute value of 7 is 7. Meanwhile, the absolute value of -9 is 9.

Naturally, absolute value is used in a lot of different places in mathematics. For example, if we travel to and from the grocery store, our displacement is zero. After all, our starting point and ending point is the same. Or to look at it another way, the two legs of the trip were the same distance with opposite signs:

leg1 = 15  # miles
leg2 = -15  # miles
displacement = leg1 + leg2

To compute the total distance traveled, we’d compute the absolute value of each leg before summing them:

distance = |leg1| + |leg2|

Of course, if it were that easy to represent operations like absolute value in Python, you probably wouldn’t be here. In other words, we have to go about doing this some other way. Luckily, we’ll cover a few solutions below.

Solutions

When I set out to write this article, I only knew of two ways to compute absolute value in Python. As it turns out, there are at least three ways to do it:

  • Manually
  • Mathematically
  • Functionally

Below, we’ll break down each solution with an example. Then, in the next section, we’ll check each solution for performance.

Compute Absolute Value by Hand

If the problem with computing an absolute value is the sign, then there’s a pretty straightforward solution:

x = -5
if x < 0:
  x = -x

Here, we check to see if our value is negative. If it is, we negate it. That way, positive values stay positive, and negative values are made positive.

One way I’ve gotten value out of this solution is in a program where numbers drive the logic. For example, let’s say we have a program which performs an action based on a number input by the user. In this program, the number drives how many times the action occurs while the sign drives which action occurs.

In this program, it’s helpful to assume that the user will enter a positive number. That way, we can use the positive number to drive a loop. If the user doesn’t enter a positive number, we can use this branch to update our expected action as well as compute absolute value.

That said, I generally think the other solutions in this article are more useful.

Compute Absolute Value Using Math

When I was putting together this article, I knew there were essentially two ways to compute absolute value: use a branch or use a function. At the time, however, I wasn’t aware of the following math trick:

x = -5
x = (x**2)**.5

If you’ve ever done any statistics or machine learning, you might know that we often square values, so we don’t have to deal with negative numbers (e.g. mean squared error). That’s exactly why we square our value here. For example, -2 and 2 are both 4 when squared.

Once we have our squared values, we can generate the absolute value by taking the square root. In most languages, computing square root is a bit complicated—would would probably justify another article. Luckily, Python includes power as one of the standard operations. As a result, we can compute square root by raising our base to 1/2 or 0.5.

In the end, we’ll end up with the expected absolute value with a few caveats:

First, this solution produces a floating point value. In this case, x will move from -5 to 5.0. As a result, if we plan to use x as a loop counter, we’ll probably want to cast it to an integer.

Second, rounding errors for floating point values may become an issue. I wasn’t able to generate any, but I suspect it’s possible to get an unexpected absolute value with this method.

If you don’t want to deal with these issues, there’s always another solution.

Compute Absolute Value Using Standard Library

Conveniently, Python has bottled up the concept of absolute value for use in the standard library. In fact, there’s no need to import any modules. The following function works right out of the box:

x = -5
x = abs(x)

In other words, if you need to compute an absolute value directly—for instance, as a part of an expression—this is the way to go.

Performance

At this point, I figure it’s worth looking at each of these solutions from a performance perspective. To do that, we’ll need to construct a few equivalent code snippets:

setup = """
x = -5
"""

control_flow = """
if x < 0:
  -x
"""

mathematics = """
(x**2)**0.5
"""

function = """
abs(x)
"""

As you can see, I simplified these expressions a bit because I just wanted to observe the effects of the absolute value computation. In other words, none of these expressions actually change x. Let’s see how they play out:

>>> import timeit
>>> min(timeit.repeat(setup=setup, stmt=control_flow))
0.04148059999988618
>>> min(timeit.repeat(setup=setup, stmt=mathematics))
0.3548131000002286
>>> min(timeit.repeat(setup=setup, stmt=function))
0.05475890000025174

As it turns out, the branch is actually the fastest option. I suspect that the abs() function is slightly slower due to the function call. At any rate, I was curious to see how these solutions scale, so I decided to change x to a much larger number:

>>> setup = """
x = -51310834193491
"""
>>> min(timeit.repeat(setup=setup, stmt=control_flow))
0.06167479999976422
>>> min(timeit.repeat(setup=setup, stmt=mathematics))
0.5422766000001502
>>> min(timeit.repeat(setup=setup, stmt=function))
0.07209680000005392

Again, the results shook out about the same. Our simple control flow solution is rather quick.

Finally, I decided to look at a positive number:

>>> setup = """
x = 51310834193491
"""
>>> min(timeit.repeat(setup=setup, stmt=control_flow))
0.0271256999999423
>>> min(timeit.repeat(setup=setup, stmt=mathematics))
0.5370481999998447
>>> min(timeit.repeat(setup=setup, stmt=function))
0.05108329999984562

Since there’s no branching, we get a bit of a performance boost with our control flow and abs() solutions. Unfortunately, the mathematics solution is slow no matter how you run it. No wonder I’ve never seen it in practice.

As always, take these test cases with a grain of salt. I ran them using Python 3.7.3 on a Windows machine; your mileage may vary. If you’re interested in learning more about this performance testing process, I have an article for that.

Challenge

As promised, I’ve brought along a challenge which leverages absolute value. In particular, this challenge is related to the example provided in the control flow solution:

Let’s say we have a program which performs an action based on a number input by the user. In this program, the number drives how many times the action occurs while the sign drives which action occurs.

More specifically, write a program which generates |x| plus signs if the number is positive and |x| negative signs otherwise. Here, x is the number input by the user. As a result, the program should behave as follows:

>>> "Enter a number": 7
+++++++
>>> "Enter a number": -5
-----

As I mentioned, I would likely solve this problem using our control flow sample. Of course, you’re welcome to use any solution available to you. Just remember to drop it in the comments! I’ll be sharing mine there as well.

A Little Recap

With all that out of the way, let’s take a look at our ways to compute absolute value once again:

x = -37

# Compute absolute value by brute force
if x < 0:
  x = -x

# Compute absolute value by arithmetic
x = (x**2)**0.5

# Compute absolute value with standard library
x = abs(x)

As always, if you liked this article, feel free to show it some love by dropping a comment, giving it a share, or any number of other ways. If this article interested you, the following articles are heavily related:

In addition, here are a few Python related resources on Amazon (ad):

Otherwise, thanks for stopping by! I appreciate your time.

The post How to Compute Absolute Value in Python: Control Flow, Abs(), and More appeared first on The Renegade Coder.

]]>
https://therenegadecoder.com/code/how-to-compute-absolute-value-in-python/feed/ 0 22457
How to Obfuscate Code in Python: A Thought Experiment https://therenegadecoder.com/code/how-to-obfuscate-code-in-python/ https://therenegadecoder.com/code/how-to-obfuscate-code-in-python/#respond Mon, 09 Mar 2020 14:00:00 +0000 https://therenegadecoder.com/?p=22451

Are you worried that people might reverse engineer your script? One way to combat that issue is to obfuscate your code. Luckily, it's not too hard to d

The post How to Obfuscate Code in Python: A Thought Experiment appeared first on The Renegade Coder.

]]>

As with most articles in this series, I was doing some browsing on Google, and I found that some folks had an interest in learning how to obfuscate code in Python. Naturally, I thought that would be a fun topic. By no means am I an expert, but I’m familiar with the idea. As a result, treat this like a fun thought experiment.

Table of Contents

Problem Description

Unlike most articles in this series, I’m not looking for a quick answer to code obfuscation—the process of making code unreadable. Instead, I want to look at various obfuscation methods. To do that, we’ll need some piece of nicely formatted source code:

def read_solution(solution_path: str) -> list:
    """
    Reads the solution and returns it as a list of lines.
    :param solution_path: path to the solution
    :return: the solution as a list of lines
    """
    with open(solution_path, encoding="utf8") as solution:
        data = solution.readlines()
    return data

Cool! Here’s a standalone function that I pulled from my auto-grader project. It’s not the best code in the world, but I figured it would serve as a nice example. After all, it’s a short snippet that performs a simple function: reads a file and dumps the results as a list of lines.

In this article, we’ll take a look at a few ways of making this code snippet as unintelligible as possible. Keep in mind that I’m not an expert at this. Rather, I thought this would be a fun exercise where we could all learn something.

Solutions

In this section, we’ll take a look at several ways to obfuscate code. In particular, we’ll be taking the original solution and gradually manipulating it throughout this article. As a result, each solution will not be a standalone solution. Instead, it will be an addition to all previous solutions.

Obfuscate Code by Removing Comments

One surefire way to make code hard to read is to begin by avoiding best practices. For instance, we could start by removing any comments and docstrings:

def read_solution(solution_path: str) -> list:
    with open(solution_path, encoding="utf8") as solution:
        data = solution.readlines()
    return data

In this case, the solution is self-documenting, so it’s fairly easy to read. That said, the removal of the comment does make it slightly harder to see exactly what this method accomplishes.

Obfuscate Code by Removing Type Hints

With the comments out of the way, we can begin removing other helpful pieces of syntax. For example, we have a few bits of syntax which help people track variable types throughout the code. In particular, we indicated that the input parameter solution_path should be a string. Likewise, we also indicated that the function returns a list. Why not remove those type hints?

def read_solution(solution_path):
    with open(solution_path, encoding="utf8") as solution:
        data = solution.readlines()
    return data

Again, this function is still fairly manageable, so it wouldn’t be too hard to figure out what it does. In fact, almost all Python code looked like this at one point, so I wouldn’t say we’ve reached any level of obfuscation yet.

Obfuscate Code by Removing Whitespace

Another option for visual obfuscation is removing all extraneous whitespace. Unfortunately, in Python, whitespace has value. In fact, we use it to indicate scope. That said, there’s still some work we can do:

def read_solution(solution_path):
    with open(solution_path,encoding="utf8") as solution:
        data=solution.readlines()
    return data

Here, we were only able to remove three spaces: one between solution_path and encoding, one between data and =, and one between = and solution.readlines(). As a result, the code is still fairly readable. That said, as we begin to obfuscate our code a bit more, we’ll see this solution pay dividends.

Obfuscate Code by Abandoning Naming Conventions

One thing we have full control over in code is naming conventions. In other words, we decide what we name our functions and variables. As a result, it’s possible to come up with names that completely obfuscate the intent of a variable or function:

def x(a):
    with open(a,encoding="utf8") as z:
        p=z.readlines()
    return p

Here, we’ve lost all semantic value that we typically get from variable and function names. As a result, it’s even hard to figure out what this program does.

Personally, I don’t think this goes far enough. If we were particularly sinister, we’d generate long sequences of text for each name, so it’s even more difficult to understand:

def IdDG0v5lX42t(hjqk4WN0WwxM):
    with open(hjqk4WN0WwxM,encoding="utf8") as ltZH4QOxmGy8:
        QVsxkg07bMCs=ltZH4QOxmGy8.readlines()
    return QVsxkg07bMCs

Hell, I might even use a single random string of characters and only modify bits of it. For example, we could try using the function name repeatedly with slight alterations (e.g. 1 for l, O for 0, etc.):

def IdDG0v5lX42t(IdDG0v51X42t):
    with open(IdDG0v51X42t,encoding="utf8") as IdDGOv51X42t:
        IdDGOv51X4Rt=IdDGOv51X42t.readlines()
    return IdDGOv51X4Rt

Of course, while this looks harder to read, nothing is really stopping the user from using an IDE to follow each reference. Likewise, compiling and decompiling this function (i.e. .py -> .pyc -> .py) would probably undo all our hard labor. As a result, we’ll have to go deeper.

Obfuscate Code by Manipulating Strings

Another way to make code unintelligible is to find hardcoded strings like “utf8” in our example and add an unnecessary layer of abstraction to them:

def IdDG0v5lX42t(IdDG0v51X42t):
    I6DGOv51X4Rt=chr(117)+chr(116)+chr(102)+chr(56)
    with open(IdDG0v51X42t,encoding=I6DGOv51X4Rt) as IdDGOv51X42t:
        IdDGOv51X4Rt=IdDGOv51X42t.readlines()
    return IdDGOv51X4Rt

Here, we’ve constructed the string “utf8” from its ordinal values. In other words, ‘u’ corresponds to 117, ‘t’ corresponds to 116, ‘f’ corresponds to 102, and ‘8’ corresponds to 56. This additional complexity is still pretty easy to map. As a result, it might be worthwhile to introduce even more complexity:

def IdDG0v5lX42t(IdDG0v51X42t):
    I6DGOv51X4Rt="".join([chr(117),chr(116),chr(102),chr(56)])
    with open(IdDG0v51X42t,encoding=I6DGOv51X4Rt) as IdDGOv51X42t:
        IdDGOv51X4Rt=IdDGOv51X42t.readlines()
    return IdDGOv51X4Rt

Instead of direct concatenation, we’ve introduced the join method. Now, we have a list of characters as numbers. Let’s reverse the list just to add a bit of entropy to the system:

def IdDG0v5lX42t(IdDG0v51X42t):
    I6DGOv51X4Rt="".join(reversed([chr(56),chr(102),chr(116),chr(117)]))
    with open(IdDG0v51X42t,encoding=I6DGOv51X4Rt) as IdDGOv51X42t:
        IdDGOv51X4Rt=IdDGOv51X42t.readlines()
    return IdDGOv51X4Rt

How about that? Now, we have even more code we can begin modifying.

Obfuscate Code by Manipulating Numbers

With our “utf8” string represented as a reversed list of numbers, we can begin changing their numeric representation. For example, 56 is really 28 * 2 or 14 * 2 * 2 or 7 * 2 * 2 * 2. Likewise, Python supports various bases, so why not introduce hexadecimal, octal, and binary to the mix?

def IdDG0v5lX42t(IdDG0v51X42t):
    I6DGOv51X4Rt="".join(reversed([chr(2*2*7*2),chr(0x66),chr(0o164),chr(0b1110101)]))
    with open(IdDG0v51X42t,encoding=I6DGOv51X4Rt) as IdDGOv51X42t:
        IdDGOv51X4Rt=IdDGOv51X42t.readlines()
    return IdDGOv51X4Rt

Suddenly, it’s unclear what numbers we’re even working with. To add a bit of chaos, I thought it would be fun to insert a whitespace character:

def IdDG0v5lX42t(IdDG0v51X42t):
    I6DGOv51X4Rt="".join(reversed([chr(2*2*7*2),chr(0x66),chr(0o164),chr(0b1110101),chr(0x20)])).strip()
    with open(IdDG0v51X42t,encoding=I6DGOv51X4Rt) as IdDGOv51X42t:
        IdDGOv51X4Rt=IdDGOv51X42t.readlines()
    return IdDGOv51X4Rt

Then, we can call the strip method to remove that extra space.

Obfuscate Code by Introducing Dead Code

In the previous example, we added a whitespace character to our string to make it slightly more difficult to decode. We can now take that idea and begin to add code that doesn’t really do anything:

def IdDG0v5lX42t(IdDG0v51X42t):
    I6DGOv51X4Rt="".join(reversed([chr(2*2*7*2),chr(0x66),chr(0o164),chr(0b1110101),chr(0x20)])).strip()
    if len(IdDG0v51X42t*3)>-1:
        with open(IdDG0v51X42t,encoding=I6DGOv51X4Rt) as IdDGOv51X42t:
            IdDGOv51X4Rt=IdDGOv51X42t.readlines()
        return IdDGOv51X4Rt
    else:
        return list()

Here, I’ve introduce a dead branch. In other words, we’re operating under the assumption that the input is a valid string. As a result, we can add a silly case where we check if the string has a length greater than -1—which is always true. Then, on the dead branch, we return some generic value.

At this point, what is stopping us from writing a completely ridiculous dead block? In other words, instead of returning a simple junk value, we could construct a complex junk value:

def IdDG0v5lX42t(IdDG0v51X42t):
    I6DGOv51X4Rt="".join(reversed([chr(2*2*7*2),chr(0x66),chr(0o164),chr(0b1110101),chr(0x20)])).strip()
    if len(IdDG0v51X42t*3)>-1:
        with open(IdDG0v51X42t,encoding=I6DGOv51X4Rt) as IdDGOv51X42t:
            IdDGOv51X4Rt=IdDGOv51X42t.readlines()
        return IdDGOv51X4Rt
    else:
        IdDG0v51X42t=IdDG0v51X42t[len(IdDG0v51X42t)/2::3]*6
        return [I6DG0v51X42t for I6DG0v51X42t in IdDG0v51X42t]

Honestly, I could have put anything in the dead block. For fun, I decided to play with the input string. For instance, I constructed a substring and repeated it. Then, I constructed a list from the characters in that new string.

Obfuscate Code by Adding Dead Parameters

If we can introduce dead branches, we can absolutely introduce dead parameters. However, we don’t want to alter the behavior of the underlying function, so we’ll want to introduce default parameters:

def IdDG0v5lX42t(IdDG0v51X42t,LdDG0v51X42t=0x173):
    I6DGOv51X4Rt="".join(reversed([chr(2*2*7*2),chr(0x66),chr(0o164),chr(0b1110101),chr(0x20)])).strip()
    if len(IdDG0v51X42t*3)>-1:
        with open(IdDG0v51X42t,encoding=I6DGOv51X4Rt) as IdDGOv51X42t:
            IdDGOv51X4Rt=IdDGOv51X42t.readlines()
        return IdDGOv51X4Rt
    else:
        IdDG0v51X42t=IdDG0v51X42t[len(IdDG0v51X42t)/2::3]*6
        return [I6DG0v51X42t for I6DG0v51X42t in IdDG0v51X42t]

Of course, this parameter is of no use currently. In other words, let’s try doing something with it:

def IdDG0v5lX42t(IdDG0v51X42t,LdDG0v51X42t=0x173):
    I6DGOv51X4Rt="".join(reversed([chr(2*2*7*2),chr(0x66),chr(0o164),chr(0b1110101),chr(0x20)])).strip()
    if LdDG0v51X42t%2!=0 or len(IdDG0v51X42t*3)>-1:
        with open(IdDG0v51X42t,encoding=I6DGOv51X4Rt) as IdDGOv51X42t:
            IdDGOv51X4Rt=IdDGOv51X42t.readlines()
        return IdDGOv51X4Rt
    else:
        IdDG0v51X42t=IdDG0v51X42t[len(IdDG0v51X42t)/2::3]*6
        return [I6DG0v51X42t for I6DG0v51X42t in IdDG0v51X42t]

Now, there is something beautiful about the expression LdDG0v51X42t%2!=0. To me, it looks like a password—not a test for odd numbers.

Of course, why stop there? Another cool thing we can do with parameters is take advantage of variable length arguments:

def IdDG0v5lX42t(IdDG0v51X42t,LdDG0v51X42t=0x173,*LdDG0v51X42tf):
    I6DGOv51X4Rt="".join(reversed([chr(2*2*7*2),chr(0x66),chr(0o164),chr(0b1110101),chr(0x20)])).strip()
    if LdDG0v51X42t%2!=0 or len(IdDG0v51X42t*3)>-1:
        with open(IdDG0v51X42t,encoding=I6DGOv51X4Rt) as IdDGOv51X42t:
            IdDGOv51X4Rt=IdDGOv51X42t.readlines()
        return IdDGOv51X4Rt
    else:
        IdDG0v51X42t=IdDG0v51X42t[len(IdDG0v51X42t)/2::3]*6
        return [I6DG0v51X42t for I6DG0v51X42t in IdDG0v51X42t]

Now, we’ve opened the door to an unlimited number of arguments. Let’s add some code to make this interesting:

def IdDG0v5lX42t(IdDG0v51X42t,LdDG0v51X42t=0x173,*LdDG0v51X42tf):
    I6DGOv51X4Rt="".join(reversed([chr(2*2*7*2),chr(0x66),chr(0o164),chr(0b1110101),chr(0x20)])).strip()
    if LdDG0v51X42t%2!=0 or len(IdDG0v51X42t*3)>-1:
        with open(IdDG0v51X42t,encoding=I6DGOv51X4Rt) as IdDGOv51X42t:
            IdDGOv51X4Rt=IdDGOv51X42t.readlines()
        return IdDGOv51X4Rt
    elif LdDG0v51X42tf:
        return list()
    else:
        IdDG0v51X42t=IdDG0v51X42t[len(IdDG0v51X42t)/2::3]*6
        return [I6DG0v51X42t for I6DG0v51X42t in IdDG0v51X42t]

Again, we’ll never hit this branch because the first condition is always true. Of course, the casual reader doesn’t know that. At any rate, let’s have some fun with it:

def IdDG0v5lX42t(IdDG0v51X42t,LdDG0v51X42t=0x173,*LdDG0v51X42tf):
    I6DGOv51X4Rt="".join(reversed([chr(2*2*7*2),chr(0x66),chr(0o164),chr(0b1110101),chr(0x20)])).strip()
    if LdDG0v51X42t%2!=0 or len(IdDG0v51X42t*3)>-1:
        with open(IdDG0v51X42t,encoding=I6DGOv51X4Rt) as IdDGOv51X42t:
            IdDGOv51X4Rt=IdDGOv51X42t.readlines()
        return IdDGOv51X4Rt
    elif LdDG0v51X42tf:
        while LdDG0v51X42tf:
            LdDG0v51X42tx=LdDG0v51X42tf.pop()
            LdDG0v51X42tf.append(LdDG0v51X42tx)
        return LdDG0v51X42tf
    else:
        IdDG0v51X42t=IdDG0v51X42t[len(IdDG0v51X42t)/2::3]*6
        return [I6DG0v51X42t for I6DG0v51X42t in IdDG0v51X42t]

Yep, that’s an infinite loop! Unfortunately, it’s sort of obvious. That said, I suspect that the variable names will obscure the intent for a little while.

Other Ways to Obfuscate Code

Once again, I’ll mention that this article was more of a thought experiment for me. I had seen obfuscated code in the past, and I thought it would be fun to give it a try myself. As a result, here’s the original snippet and the final snippet for comparison:

def read_solution(solution_path: str) -> list:
    """
    Reads the solution and returns it as a list of lines.
    :param solution_path: path to the solution
    :return: the solution as a list of lines
    """
    with open(solution_path, encoding="utf8") as solution:
        data = solution.readlines()
    return data
def IdDG0v5lX42t(IdDG0v51X42t,LdDG0v51X42t=0x173,*LdDG0v51X42tf):
    I6DGOv51X4Rt="".join(reversed([chr(2*2*7*2),chr(0x66),chr(0o164),chr(0b1110101),chr(0x20)])).strip()
    if LdDG0v51X42t%2!=0 or len(IdDG0v51X42t*3)>-1:
        with open(IdDG0v51X42t,encoding=I6DGOv51X4Rt) as IdDGOv51X42t:
            IdDGOv51X4Rt=IdDGOv51X42t.readlines()
        return IdDGOv51X4Rt
    elif LdDG0v51X42tf:
        while LdDG0v51X42tf:
            LdDG0v51X42tx=LdDG0v51X42tf.pop()
            LdDG0v51X42tf.append(LdDG0v51X42tx)
        return LdDG0v51X42tf
    else:
        IdDG0v51X42t=IdDG0v51X42t[len(IdDG0v51X42t)/2::3]*6
        return [I6DG0v51X42t for I6DG0v51X42t in IdDG0v51X42t]

At this point, I suppose we could continue to iterate, but I’m not sure that would be the best use of my time. That said, there were a few things I considered trying. For instance, I thought about compressing lines of code such as:

with open(IdDG0v51X42t,encoding=I6DGOv51X4Rt) as IdDGOv51X42t:
    IdDGOv51X4Rt=IdDGOv51X42t.readlines()
return IdDGOv51X4Rt

Into something like:

with open(IdDG0v51X42t,encoding=I6DGOv51X4Rt) as IdDGOv51X42t:
    return IdDGOv51X42t.readlines()

However, part of me felt like this would actually make the code easier to read since we wouldn’t have to map variable names.

In addition, I thought about making some methods just to pollute the namespace a little bit. For example, we could create functions that overwrite some of the standard library. Then, give them totally different behavior. In our case, we might redefine reversed to confuse the reader into thinking it has its typical behavior:

def reversed(x):
    return "utf8"

Then, we could pass whatever we wanted into it as bait. Wouldn’t that be sinister?

Beyond that, I’m aware that there are obfuscation tools out there, but I’m not sure how widely used they are. Here are a few examples:

  • pyarmor: “A tool used to obfuscate python scripts, bind obfuscated scripts to fixed machine or expire obfuscated scripts.”
  • pyminifier: “Minify, obfuscate, and compress Python code”
  • Opy: “Obfuscator for Python”
  • Oxyry: “the power to protect your python source code”

I haven’t tried many of these tools, but Oxyry is definitely the most convenient. When I plug our function into it, it generates the following code:

def read_solution (OOOO0OO0OO00OOOOO :str )->list :#line:1
    ""#line:6
    with open (OOOO0OO0OO00OOOOO ,encoding ="utf8")as OO0O00OO0O0O0OO0O :#line:7
        OO0000O00O0OO0O0O =OO0O00OO0O0O0OO0O .readlines ()#line:8
    return OO0000O00O0OO0O0O 

Clearly, that’s not great, but I suppose it’s effective. If you know of any other tools or cool techniques, feel free to share them in the comments.

Challenge

For today’s challenge, pick a piece of code and try to obfuscate it. Feel free to use all of the ideas leveraged in this article. However, the challenge will be to come up with your own ideas. What other ways can we obfuscate Python code?

If you’re looking for some ideas, I mentioned a couple in the previous section. Of course, there are other things you could try. For instance, you could always add a logger which prints erroneous messages to the console. Something like this would have no effect on your program’s behavior, but it could confuse a reader.

If you want to go the extra mile, try writing a program which performs your favorite obfuscation technique. For instance, could you write a program which could identify Python variables? If so, you could generate your own symbol table which would track all variables. Then, you could generate new names without any worries about clashes.

At the end of the day, however, treat this challenge like a fun thought experiment. I don’t expect any of these methods to be all that practical. After all, if a machine can run the code even in an obfuscated state, so can a human (eventually).

A Little Recap

Typically, in this section, I would list off all the solutions. However, the code snippets are quite long, and I don’t think it makes a lot of sense for me to dump them here. As a result, I’ll just share the options as a list:

  • Remove comments, type hints, and whitespace
  • Abandon naming conventions
  • Manipulate strings and numbers
  • Introduce dead code and parameters
  • Try something else

With that, I think we’re don for the day. If you like this sort of content, I’d appreciate it if you checked out an article on the different ways you can support the site. Otherwise, here are a few security related books on Amazon (ad):

Finally, here are some related articles:

Once again, thanks for stopping by. See you next time!

The post How to Obfuscate Code in Python: A Thought Experiment appeared first on The Renegade Coder.

]]>
https://therenegadecoder.com/code/how-to-obfuscate-code-in-python/feed/ 0 22451
How to Increment a Number in Python: Operators, Functions, and More https://therenegadecoder.com/code/how-to-increment-a-number-in-python/ https://therenegadecoder.com/code/how-to-increment-a-number-in-python/#respond Fri, 06 Mar 2020 15:00:00 +0000 https://therenegadecoder.com/?p=22442

It's surprisingly common to want to increment a number in Python. Yet, I haven't seen a lot written about it. Here's my attempt!

The post How to Increment a Number in Python: Operators, Functions, and More appeared first on The Renegade Coder.

]]>

Every once in awhile, I like to revisit Python fundamentals to see if I can learn anything new about the language. This time around I thought it would be fun to look at a few different ways to increment a number in Python.

As it turns out, there two straightforward ways to increment a number in Python. First, we could use direct assignment: x = x + 1. Alternatively, we could use the condensed increment operator syntax: x += 1. In addition, there are a few less conventional options like using the add method of the operator module or using generator expressions. Feel free to dig in below to learn more.

Table of Contents

Problem Description

When solving programming problems, one very common operation is adding a fixed value to a number. We call this operation increment, and it’s useful in many contexts. For instance, we might want to use a number as a counter, so we can perform a fixed number of operations. In that case, we’d probably start from zero and add one until our condition is met (e.g. i < 10).

Of course, how you actually accomplish an increment varies by language. For example, in C-style languages, there are often direct increment operators:

++i
i++
i += 1

Unfortunately, some of these options above just don’t work in Python. For instance, both the pre-increment (i.e. ++i) and post-increment (i.e. i++) operators fail in Python:

>>> i = 7
>>> i++
SyntaxError: invalid syntax
>>> ++i
7

With the post-increment operator, we see that we get a blatant SyntaxError. In other words, it’s straight up invalid. Meanwhile, the pre-increment operator executes but nothing actually happens. That’s because the unary plus operator in Python does nothing for numbers. In fact, we could put as many pluses as we want:

>>> +++++++++++++++++++i
7

Naturally, we’ll have to look elsewhere if we want to increment a number!

Solutions

Fortunately, there are a few ways to increment a value in Python. Otherwise, why would this article exist? At any rate, let’s dig in!

Increment a Number With Assignment

One of the nice things about numbers in Python is that they’re immutable—meaning they cannot be changed. Otherwise, we’d have to deal with pesky issues like aliasing. If you’re interested in learning about the effects of aliasing, I have another article which talks about the risks of copying mutable data types.

At any rate, since Python numbers are immutable, we can use them in arithmetic and assign their value back with ease:

x = 5
x = x + 1

Here, we have defined a variable, x, which stores the value 5. In the next line, we take x and add 1 to it. Then, we store the result back into x. As a result, x stores 6.

As someone who teaches a lot of introductory programming classes, I find that students are often bothered by this syntax the first time. After all, most students are familiar with the = from math, so they haven’t made the connection that = is really the assignment operator—which makes the statement x = x + 1 very much legal.

If this syntax bothers you, my advice is to ignore the left-hand side (i.e. x =). Instead, focus on what is happening on the right-hand side of the statement (i.e. x + 1). This portion of the statement is called an expression, and we can have literally anything there as long as it evaluates to some value. In this case, we can evaluate the expression directly in three steps:

  1. x evaluates to 5
  2. 1 evaluates to 1
  3. 5 + 1 evaluates to 6

At this point, the result is stored back into x which overwrites its previous value, 5.

If this breakdown of statements and expressions sounds interesting to you, I recommend checking out my article which dives into this topic a bit further. Otherwise, we’ll look at the next solution.

Increment a Number Using an Operator

Like most programming languages, Python has a way of including syntactic sugar for scenarios like increment. That said, there is only one true increment operator: +=. To use it, we’ll need to rework our code from before:

x = 5
x += 1

As we can probably imagine, this statement works exactly like the line from the previous section. However, we’ve removed some redundant code (i.e. the additional x).

One of the nice things about this operator is that it creates a standalone statement. In other words, it cannot be embedded in other contexts:

>>> y = x += 1
SyntaxError: invalid syntax

Contrast this with the typical increment operators in other languages like Java where this is possible:

x = x++

Any idea what this does? Answer: absolutely nothing. In this example, x is incremented. Then, its previous value is returned, and the result is overwritten. In other words, x stays the same. If that sound wacky, I wrote a whole article about the behavior. It’s one of the reasons I’m glad the syntax never made its way to Python.

Increment a Number Using a Function

One thing I find interesting about Python is the plethora of functional language features it has. For example, in addition to all of the explicit operators, Python includes a set of functional overloads. As a result, we could increment a number without ever using an arithmetic operator:

import operator
x = 5
x = operator.add(x, 1)

The advantage of using a function over the direct operator is scalability. For example, we may find that we want to increment an entire list of values. In that case, the add function does just the trick:

list(map(operator.add, [1, 1, 1], [5, -4, 13]))

Of course, it might be a little cleaner to use the underlying __add__ method:

list(map(1 .__add__, [5, -4, 13]))  # the space is important

That said, this solution is probably the most ridiculous for the standard case.

Increment a Number Implicitly

Sometimes it doesn’t make sense to manually increment a number. After all, in our problem description, we talked about using a number as a counter in a loop. Most of the time, however, we try to avoid explicit counters by using iterators. For example, if we wanted to loop over characters in a string, we could write the following:

my_string = "Bob"
for character in my_string:
  pass  # Do Something!

Notice how we didn’t have to explicitly increment a counter. Since strings are iterable, all of that is taken care of for us.

Of course, sometimes we still want to do some counting. After all, we might want to perform an action exactly 5 times. In that case, we can use a range:

for i in range(5):
  pass  # Do Something!

Likewise, we could even make our own counter using a generator expression:

counter = (i for i in range(5))

Then, to generate terms in the sequence, we could continually call next():

>>> next(counter)
0
>>> next(counter)
1

All of these options perform an increment operation implicitly. Depending on your needs, that might make more sense. Of course, that’s up to you to decide.

Bonus: Decrement a Number

I’d hate to go through an entire article talking about incrementing numbers without ever bringing up the compliment operation: decrement. Without introducing any additional syntax, we can decrement a number with ease:

x = 10
x += -1

Of course, that’s a bit counterintuitive. Instead, we often opt for the decrement operator:

x -= 1

Likewise, direct assignment works just as well:

x = x - 1

In addition, the functional solution we’ve mentioned can be modified to get the job done:

x = operator.sub(x, 1)

Of course, as we’ve already mentioned, it’s probably a bit excessive to do anything like this. Instead, stick to the decrement operator.

Performance

As always, I like to take a look at the various solutions and compare them in terms of performance. To do that, we’ll need to put each solution in its own string:

setup = """
import operator
"""

assignment = """
x = 0
x = x + 1
"""

increment = """
x = 0
x += 1
"""

function = """
x = 0
x = operator.add(x, 1)
"""

generator = """
x = (i for i in range(5))
next(x)
"""

Then, to test these options, we’ll need to run them with timeit:

>>> import timeit
>>> min(timeit.repeat(setup=setup, stmt=assignment))
0.03538969999999608
>>> min(timeit.repeat(setup=setup, stmt=increment))
0.03586820000001012
>>> min(timeit.repeat(setup=setup, stmt=function))
0.09383009999999103
>>> min(timeit.repeat(setup=setup, stmt=generator))
0.6202383999999768

Naturally, the core operators get the job done the fastest, but I don’t love the generator test. As a result, I decided to rewrite it so the setup string includes the generator up to a very large value:

>>> setup = """
import operator
x = (i for i in range(100000000))
"""
>>> generator = """
next(x)
"""
>>> min(timeit.repeat(setup=setup, stmt=generator))
0.11321939999999131

Now, that’s a bit more respectable. Of course, I’m wondering if including x in the setup string will change the original tests as well:

>>> setup = """
import operator
x = 0
"""
>>> assignment = """
x = x + 1
"""
>>> increment = """
x += 1
"""
>>> function = """
x = operator.add(x, 1)
"""
>>> min(timeit.repeat(setup=setup, stmt=assignment))
0.05624840000001541
>>> min(timeit.repeat(setup=setup, stmt=increment))
0.061655099999995855
>>> min(timeit.repeat(setup=setup, stmt=function))
0.12224320000001399

In either case, it looks like the direct assignment or increment operators are the best choice. To put this into context, I ran all tests using Python 3.7.3 on a Windows 10 machine.

Challenge

When I was thinking about a good challenge, I had a hard time coming up with an idea. After all, there are a lot of different contexts where incrementing a variable could be useful, but it’s not exactly a skill we can build on.

As a result, I thought it might be more fun to come up with a complex increment function which has various conditions. For example, here are some of the conditions:

  • If the current number is odd, add 1
  • If the current number is even, add 3
  • If the current number is divisible by 5, add 5

As an added wrinkle, each number will need to be checked for all three criteria. For example, the number 15 is both odd and divisible by 5. As a result, the next number should be 21 (i.e. 15 + 5 + 1). Likewise, the number 12 will only meet the even criteria, so the next number will be 15.

As always, I’ll share an answer in the comments. Feel free to share yours as well!

A Little Recap

And with that, we’re all done! Once again, here are all the solutions in one convenient place:

x = 0

# Increment by one with assignment
x = x + 1

# Increment by one with the increment operator
x += 1

# Increment by one with a function
import operator
x = operator.add(x, 1)

# Increment by one implicitly on an iterable
my_string = "Bob"
for character in my_string:
  pass  # Do Something!

# Increment by one implicitly using range
for i in range(5):
  pass  # Do Something!

# Increment by one implicitly using a generator expression
counter = (i for i in range(5))
next(counter)

# Decrement by one with assignment
x = x - 1

# Decrement by one with the decrement operator
x -= 1

# Decrement by one with a function
x = operator.sub(x, 1)

If you liked this sort of thing, there are tons of ways to help grow the site. Of course, one quick way is to continue browsing:

While you’re here, check out some of the resources on Amazon (ad):

Otherwise, thanks for stopping by! Come back soon.

The post How to Increment a Number in Python: Operators, Functions, and More appeared first on The Renegade Coder.

]]>
https://therenegadecoder.com/code/how-to-increment-a-number-in-python/feed/ 0 22442